【问题标题】:rake assets:precompile:nodigest in Rails 4耙资产:预编译:Rails 4 中的 nodigest
【发布时间】:2013-07-06 08:08:45
【问题描述】:

在 Rails 3 中有一个 rake assets:precompile:nodigest 任务,它正在编译资产并在 /public/assets 目录中没有摘要部分的情况下编写它们。在 Rails 4 中,这已被删除,默认情况下,所有资产都仅使用摘要进行预编译。由于各种原因,我还需要一些资产的非消化版本。有什么简单的方法可以恢复旧的行为吗?

【问题讨论】:

    标签: ruby-on-rails asset-pipeline ruby-on-rails-4 sprockets


    【解决方案1】:

    Rails 4.0.0 中使用的sprockets-rails 版本不再支持非摘要资产。

    sprocket-rails's Readme:

    只编译摘要文件名。静态非摘要资产应该简单地公开存在

    因此,任何需要静态的资产都可以手动放入您的public 文件夹中。如果你需要复制 SCSS 文件等编译好的资产,这个 rake 任务可能会有所帮助(source):

    task non_digested: :environment do
      assets = Dir.glob(File.join(Rails.root, 'public/assets/**/*'))
      regex = /(-{1}[a-z0-9]{32}*\.{1}){1}/
      assets.each do |file|
        next if File.directory?(file) || file !~ regex
    
        source = file.split('/')
        source.push(source.pop.gsub(regex, '.'))
    
        non_digested = File.join(source)
        FileUtils.cp(file, non_digested)
      end
    end
    

    【讨论】:

    • 我建议使用正则表达式:/(?
    【解决方案2】:

    还有一个宝石可以为你做这件事:有点挑衅的名字non-stupid-digest-assets

    gem "non-stupid-digest-assets"
    

    【讨论】:

    • 即使在安装了这个 gem 之后,我也得到了消化的资产。
    • 在 development.rb 文件中设置这个 config.assets.digest = false
    【解决方案3】:

    正如最佳答案所建议的那样,如果您不着急,我建议您先阅读该问题以充分了解背景故事。我最喜欢这个主意,https://github.com/rails/sprockets-rails/issues/49#issuecomment-24837265

    以下是我个人的看法,基本上我从上面的答案中获取了代码。就我而言,我只有 2 个我不想消化的文件,widget.js 和 widget.css。所以我使用 sprockets 方法找到摘要文件,然后将其符号链接到公用文件夹。

    # config/environments/production.rb
    config.assets.precompile += %w[v1/widget.js v1/widget.css]
    
    # lib/tasks/assets.rake
    namespace :assets do
      desc 'symlink digested widget-xxx.js and widget-xxx.css to widget.js and widget.css'
      task symlink_widget: :environment do
        next if Rails.env.development? || Rails.env.test?
    
        digested_files = []
        # e.g. /webapps/myapp/public/assets
        assets_path = File.join(Rails.root, 'public', Rails.configuration.assets.prefix)
    
        %w(v1/widget.js v1/widget.css).each do |asset|
          # e.g. 'v1/widget-b61b9eaaa5ef0d92bd537213138eb0c9.js'
          logical_path = Rails.application.assets.find_asset(asset).digest_path
          digested_files << File.join(assets_path, logical_path)
        end
    
        fingerprint_regex = /(-{1}[a-z0-9]{32}*\.{1}){1}/
        digested_files.each do |file|
          next unless file =~ fingerprint_regex
    
          # remove fingerprint & '/assets' from file path
          non_digested = file.gsub(fingerprint_regex, '.')
                             .gsub(Rails.configuration.assets.prefix, '')
    
          puts "Symlinking #{file} to #{non_digested}"
          system "ln -nfs #{file} #{non_digested}"
        end
      end
    end
    

    【讨论】:

    • 谢谢。我必须让 Rails.configuration.assets.prefix 在你的任务结束时让它为我工作。
    • 我不知道Rails.application.assets.find_asset(asset).digest_path,这就是快速为您提供所需的方法,这是正确的方法!虽然我认为有一种方法可以进一步简化代码,但无需剥离指纹正则表达式,您已经知道您想要原始文件名是什么,v1/widget.js 您开始使用,不是吗?
    • 糟糕,Rails.application.assets.find_asset(asset).digest_path 在生产环境中不起作用,而config.assets.compile == false。但这样做:Rails.application.assets_manifest.assets[asset] 并产生相同的结果。
    【解决方案4】:

    我对所有可用选项的大量分析在这里:

    https://bibwild.wordpress.com/2014/10/02/non-digested-asset-names-in-rails-4-your-options/

    我决定添加一个自定义 rake 任务,使用自定义配置来确定某些资产作为非消化版本生成,并使用 Sprockets 清单来查找消化后的资产并使用非消化名称复制它们。

    https://github.com/team-umlaut/umlaut/blob/5edcc609389edf833a79caa6f3ef92982312f0c5/lib/tasks/umlaut_asset_compile.rake

    # Rails4 doesn't create un-fingerprinted assets anymore, but we
    # need a couple for umlaut's API. Let's try to hook in and make
    # symlinks. 
    #
    # list of what file(globs) need non-digest-named copies is kept in
    #     Umlaut::Engine.config.non_digest_named_assets
    # defined in lib/umlaut.rb, but app can modify it if desired. 
    
    require 'umlaut'
    require 'pathname'
    
    
    # Every time assets:precompile is called, trigger umlaut:create_non_digest_assets afterwards. 
    Rake::Task["assets:precompile"].enhance do
      Rake::Task["umlaut:create_non_digest_assets"].invoke
    end
    
    namespace :umlaut do 
    
      # This seems to be basically how ordinary asset precompile
      # is logging, ugh. 
      logger = Logger.new($stderr)  
    
      # Based on suggestion at https://github.com/rails/sprockets-rails/issues/49#issuecomment-20535134
      # but limited to files in umlaut's namespaced asset directories. 
      task :create_non_digest_assets => :"assets:environment"  do    
        manifest_path = Dir.glob(File.join(Rails.root, 'public/assets/manifest-*.json')).first
        manifest_data = JSON.load(File.new(manifest_path))
    
        manifest_data["assets"].each do |logical_path, digested_path|
          logical_pathname = Pathname.new logical_path
    
          if Umlaut::Engine.config.non_digest_named_assets.any? {|testpath| logical_pathname.fnmatch?(testpath, File::FNM_PATHNAME) }
            full_digested_path    = File.join(Rails.root, 'public/assets', digested_path)
            full_nondigested_path = File.join(Rails.root, 'public/assets', logical_path)
    
            logger.info "(Umlaut) Copying to #{full_nondigested_path}"
    
            # Use FileUtils.copy_file with true third argument to copy
            # file attributes (eg mtime) too, as opposed to FileUtils.cp
            # Making symlnks with FileUtils.ln_s would be another option, not
            # sure if it would have unexpected issues. 
            FileUtils.copy_file full_digested_path, full_nondigested_path, true      
          end
        end
    
      end
    end
    

    【讨论】:

      【解决方案5】:

      谢谢 Dylan Markow,我按照他的回答,但我发现在使用 Capistrano 时有多个版本的资产(例如 application-0a*.css、application-9c*.css、...),因此 最新的应该是不消化的。这里的逻辑是:

      namespace :my_app do
        task non_digested: :environment do
          assets = Dir.glob(File.join(Rails.root, 'public/assets/**/*'))
          regex = /(?<!manifest)(-{1}[a-z0-9]{32}\.{1}){1}/
          candidates = {}
      
          # gather files info
          assets.each do |file|
            next if File.directory?(file) || file !~ regex
      
            source = file.split('/')
            source.push(source.pop.gsub(regex, '.'))
            non_digested = File.join(source)
            file_mtime = File.stat(file).mtime
            c = candidates[non_digested]
            if c.blank? || file_mtime > c[:mtime]
              candidates[non_digested] = {orig: file, mtime: file_mtime}
            end
          end
      
          # genearate
          for non_digested, val in candidates do
            FileUtils.cp(val[:orig], non_digested)
          end
        end
      end
      
      Rake::Task['assets:precompile'].enhance do
        Rake::Task['my_app:non_digested'].invoke
      end
      

      另外,我应用了 907th 的正则表达式注释,并添加了钩子让这个任务在预编译后执行。

      【讨论】:

      • 在 Rails 4.2 中,我的摘要是 64 个字符,所以正则表达式是 regex = /(?&lt;!manifest)(-{1}[a-z0-9]{64}\.{1}){1}/
      【解决方案6】:

      在 `development.rb' 文件中设置此属性 config.assets.digest = false

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-06-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-07-24
        相关资源
        最近更新 更多