sprockets - precompiling a standalone asset

1.1k views Asked by At

I am trying to make sprokets compile a single standalone js asset, so it will uglify and minify it and be part of the entire rails projects.

I need that this js to have a non-digest name, so it's will not change (i.e. embedded in other websites, etc)

I can't seem to force rails (4) /sprockets to do my bidding.

What I tried:

  1. Adding the asset (script.js) in a misc folder unders assets/javascripts and not load it in the sprockets javascript manifest. While this keeps it in the project, it doesn't get uglified and minified, and doesn't get automatically loaded via asset-sync.

  2. Tried adding another manifest called scripts-manifest.js to //= require script.js asset, to add its path in the precompile path in application.rb, but the problem is that rails 4 adds digest to all assets no matter what (doesn't work like that in rails 3)

  3. Tried using https://github.com/alexspeller/non-stupid-digest-assets to add a non digest version of the asset. I may have done it incorrectly, as it doesn't work or do anything..

    I add the initializer NonStupidDigestAssets.whitelist = ["script.js"] and tried putting it in app/assets/javascripts/misc and in public/ but it still won't work/

I have read that this gem should help in most cases, and I am sure I am doing something wrong with either path definition or no including it somewhere

3

There are 3 answers

0
Ken Stipek On

One way to do this is to add an initializer that generates the compiled versions directly.

  1. Add your js file to a subfolder in /app/assets/javascripts. Don't include this in application.js so it isn't added to the compiled assets.
  2. Create an initializer in /config/initializers that uses uglify directly

    output_file = "#{Rails.root}/public/public_script.js"

    input_file = "#{Rails.root}/app/assets/javascripts/non_digest/public_script.js"

    uglified = Uglifier.compile(File.read(input_file))

    File.open(output_file, 'w') {|f| f.write(uglified) }

  3. Include the public js file (in this example: /public/public_script.js) in your application layout

This way you have direct access to make custom changes to how uglify handles your js and the location of the file never changes for your external services accessing them.

I did all this locally and tested that it worked using the beta version of Rails 4.2

2
phoet On

the way you would do this with rails 4 is the following:

  • add it to the precompile list config.assets.precompile += %w(your_file_name.js)
  • make sure it's not referenced in application.js (directly or via require_tree)
  • symlink the digested file on deployment
    • read the manifest.yml to get the actual filename
    • ln -s digested-filename.js actual-filename.js

since rails 4, generation of non-digested assets has been removed (for good reasons) and this is a simple and straight forward way to implement the desired behavior.

1
Thomas Taylor On

Just wanted to add my own solution based off Ken's answer.

I created non_digest.rb in config/initializers:

Dir["#{Rails.root}/app/assets/javascripts/non_digest/*"].each do |asset|
  asset_name = File.basename(asset)
  asset_output = "#{Rails.root}/public/external/#{asset_name}"
  asset_uglified = Uglifier.compile(File.read(asset))

  File.open(asset_output, 'w') {|a| a.write(asset_uglified) }
end

Don't forget to stub the file in javascripts/application.js. as we probably don't want it compiled with the rest of our JS and we can continue to use //= require_tree .:

//= stub non_digest/external_bookmarklet