rake assets:precompile:nodigest in Rails 4

前端 未结 6 1429
耶瑟儿~
耶瑟儿~ 2021-01-11 17:03

In Rails 3 there was a rake assets:precompile:nodigest task which was compiling assets and writing them without the digest part in /public/assets directory. In Rails 4 this

相关标签:
6条回答
  • 2021-01-11 17:33

    My enormous analysis of all the available options is here:

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

    I decided to add a custom rake task, using custom configuration to determine certain assets to produce as non-digested versions, and using the Sprockets manifest to find the digested assets and copy them with non-digested names.

    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
    
    0 讨论(0)
  • 2021-01-11 17:34

    Set this property config.assets.digest = false in `development.rb' file

    0 讨论(0)
  • 2021-01-11 17:37

    As the best answer suggested, I recommend go reading the issue first to fully understand the background story, if you're not in a hurry. I like this idea most, https://github.com/rails/sprockets-rails/issues/49#issuecomment-24837265.

    And below is my personal take, basically I took the code from the answer above. In my case I only have 2 files that I want to be non digested, widget.js and widget.css. So I use sprockets method to find the digested files and then symlink it to public folder.

    # 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
    
    0 讨论(0)
  • 2021-01-11 17:44

    There is also a gem to do this for you: the somewhat provocatively named non-stupid-digest-assets.

    gem "non-stupid-digest-assets"
    
    0 讨论(0)
  • 2021-01-11 17:48

    The version of sprockets-rails used in Rails 4.0.0 no longer supports non-digest assets.

    Per sprocket-rails's Readme:

    Only compiles digest filenames. Static non-digest assets should simply live in public

    So any assets that need to be static can be manually put into your public folder. If you need to copy compiled assets such as SCSS files, etc., this rake task may help (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
    
    0 讨论(0)
  • 2021-01-11 17:51

    Thank you Dylan Markow, I follow his answer, but I found that there are several versions of an asset (e.g. application-0a*.css, application-9c*.css, ...) when using Capistrano so that latest one should be non-digested. Here the logic is:

    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
    

    As wells as, I applied 907th's regex comment, and add hook let this task executes after precompile.

    0 讨论(0)
提交回复
热议问题