Disable Asset Minification in Rails Production - javascript

In order to debug javascript in my heroku production environment, I need to disable asset compression (or at least compression of javascript). I tried config.assets.compress = false along with config.assets.debug = true, and the compressed assets were still used. I then deleted the compressed assets, at which point no assets were rendered at all. I added config.assets.enabled = false, which did not help. I tried copying the uncompressed assets into various directories, including the application root, public, and public/assets (the latter two using both the folders "images, "javascripts", and "stylesheets", and putting the assets directly into the folders without the three subfolders). I was eventually able to get the javascripts to work by changing the html to directly reference all of the javascript files. But the CSS and images still are not working.
I would have thought that my original config.assets.compress = false should have worked. Any ideas what I did wrong?

I came up with this workaround after reading the docs:
create a module that does nothing to compress js / css here: lib/modules/no_compression.rb
class NoCompression
def compress(string)
# do nothing
string
end
end
configure your assets to (not) be compressed with your do-nothing compressor
config.assets.compress = true
config.assets.js_compressor = NoCompression.new
config.assets.css_compressor = NoCompression.new

Under Rails 4 just commenting out the line
# config.assets.js_compressor = :uglifier
in config/environments/production.rb worked for me. Looks like default is no compresson.

I also need to debug my js so I tried ncherro's solution. The problem was that it would still throw
rake aborted!
uninitialized constant NoCompression
So I just put the NoCompression class in the production.rb file
# Compress JavaScripts and CSS
class NoCompression
def compress(string)
# do nothing
string
end
end
config.assets.compress = true
config.assets.js_compressor = NoCompression.new
config.assets.css_compressor = NoCompression.new

Comment out the uglifier and add config.assets.debug = true. This worked for me.
Compress JavaScripts and CSS:
config.assets.js_compressor = :uglifier
Debug mode disables concatenation and preprocessing of assets. But this option may cause significant delays in view rendering with a large number of complex assets:
config.assets.debug = true

Also worth noting... In addition to ncherro solution you will need to do the following:
make sure to put your new module somewhere where it will be loaded by default. Was lib/extras in my case.
run rake assets:clean to clean your existing assets.
run rake assets:precompile to compile your assets using the new compressor.
restart your app... i use touch tmp/restart.txt
Happy debugging ;)

With Rails 4 on Heroku you need to do two things. First as #geekQ mentioned, comment out the js_compressor line in config/environments/production.rb
# config.assets.js_compressor = :uglifier
Second, you need to consider Heroku's asset pipeline cache for Rails 4. Any file with the same MD5 as the version in the cache will not be recompiled. The previous (possibly compressed) version will be served. Any file you edit will have a new MD5 and be recompiled.
You can also purge the entire asset cache with the Heroku Repo plugin to the Heroku toolbelt. Install that, then use the command
heroku repo:purge_cache
Deploy a new version after purging the cache and all your assets will be recompiled.

I had to update Rails.application.config.assets.version in config/initializers/assets.rb for the production.rb changes to take effect.

Find and comment out these line in environments/production.rb:
config.assets.js_compressor = ...
config.assets.css_compressor = ...

Looks like this MAY have been a bug in Rails. From the changelog for upcoming rails 3.2.9, is this what you were running into?
Respect config.digest = false for asset_path
Previously, the asset_path internals only respected the :digest option, but ignored the global config setting. This meant that config.digest = false could not be used in conjunction with config.compile = false this corrects the behavior.
http://weblog.rubyonrails.org/2012/10/29/ann-rails-3-2-9-rc1-has-been-released/
Do you think that could be related?

Related

Cannot disable rails assets pipeline

I have a rails '4.2.11.1' application. I want to dissable assets compilation, minifying, pipeline in development. in order to use indium debugger
The rails app seems to be set up with sprokets. so in my config/application.rb I changed to this:
# Enable the asset pipeline
config.assets.enabled = false
also in config/environmetns/development.rb I have this setup:
# Do not compress assets
config.assets.compress = false
# Debug mode disables concatenation and preprocessing of assets.
# This option may cause significant delays in view rendering with a large
# number of complex assets.
config.assets.debug = true
config.serve_static_files = true
# Adds additional error checking when serving assets at runtime.
# Checks for improperly declared sprockets dependencies.
# Raises helpful error messages.
config.assets.raise_runtime_errors = true
but nothing happens and I get the files:
assets/stixs.self-7246a54effa0c5edaa806b9c4fbc6ba4617c0d80bef8c236f9a4cbcfcf7f0be7.js
finally I get this files not minifyed, or compresed but how can I get that rails work with serving the files in app/assets/javascripts in de delopment environment
Technique Sprockets uses for fingerprinting is to insert a hash of the content into the name
Add this in your development.rb
config.assets.digest = false
I hope that work for you.

Rails: Heroku assets in vendor getting 404

I have a javascript in the vendors/assets/javascripts folder, and I have this line of code:
<script src="assets/grid.js"></script>
in one of my app/views page.
This grid.js file (inside the vendors directory) works when I test it out in localhost, but when I precompile and push my application to heroku, it says:
GET http://www.domain.com/assets/grid.js 404 (Not Found)
Why is this occurring?
Thanks
I would use the javascript_include_tag instead and that should work
<%= javascript_include_tag("grid.js") %>
In production I believe that the asset pipeline adds a hash onto the name of grid.js for fingerprinting (Section 1.2 of that documentation) so you can't use that path <script src="assets/grid.js"></script>
I tried: Set config.assets.compress = true in my config/environments/production.rb and all was fine, but it is a bad practice and gain bad performance. Yo can see this for more details config.assets.compile=true in Rails production, why not?
My solution:
Run in your local project RAILS_ENV=production bundle exec rake assets:precompile and push all the files generated in public/assent/ in your github repo and deploy in heruko. Yo can read this for more details https://devcenter.heroku.com/articles/rails-asset-pipeline#compiling-assets-locally

Export static HTML+CSS+JS from Rails

When creating static apps I often start a new Rails app. This makes quite some things easier, like compilation (Coffeescript, SCSS), minimization (JS, CSS) and browser limitations (the page is being served from localhost:3000 so external sources can be loaded etc.).
At the end I want to export the app so I can put it online. Then I just need the HTML+CSS+JS. One can go and pluck the files out manually, but there probably is an easier way for this.
So: is there a tool that stores the compiled, minimized HTML+CSS+JS files from a Rails app?
If you just want to basically copy the website as it will be rendered by rails (and there is no need for server side code execution), you could just mirror the rails-website using
wget --page-requisites --convert-links http://URL-to-Start
However, this will only download those files that are referenced from the entry URL, so you might need to run it on all sub-URLs individually.
Source: Download a working local copy of a webpage
Agree with Screenmutt. I've tried a couple of the ones mentioned but have had most success with:
http://middlemanapp.com/
Does pretty much everything you are asking for and let's you export to static HTML.
install:
gem install middleman
create project:
middleman init my_new_project (or even better with template --template=html5)
run in local server for live edits:
bundle exec middleman
dump static code:
bundle exec middleman build
Perhaps you can 'scrape' the HTML from the localhost serving it?
There seem to be some tools for downloading sites in general... You can probably limit them to download resources from localhost:3000 only.
http://www.httrack.com/
http://www.linuxjournal.com/content/downloading-entire-web-site-wget
UPDATE: Here's another tutorial that might help Use Rails 3.1 for Static Sites
This is not a common usage. You might be able to extract all the static pages by manually caching everything.
I would recommend taking a look at some alternatives.
I'm sorry that this isn't a good answer, but to be honest... You are using Rails for something that it was never intended to do. There are much better ways of making static sites.
Also, a static site is not an "app". :)
All you have to do is switch to Rails production mode locally so that assets are combined and minified. Then all you have to do is view source for the HTML, CSS, and JS. This should only take a few seconds.
So the steps are
config.assets.compress = true in development.rb
view the app locally
view source, copy and paste into an index.html file
click on compressed CSS and JS form source and save those relative to your index.html making sure they link correctly
You can use Wget (as it's already mentioned). I would go with:
wget --mirror --convert-links --adjust-extension --page-requisites --no-parent http://www.yourdomain.com
Yo can also use Httrack.
Be sure when you set Httrack you exclude all external websites with scripts so you don't download f.e. Google Analytics js files or Adsense or Facebook scripts. In Httrack, you exclude it in Preferences with:
-*.googlesyndication.com/* -*.facebook.net/* -*.google-analytics.com/*
After you are done you still need to rewrite all links because they will point at .../some-page/index.html You need .../some-page/. This solves Dynamic to Static Script.
You shouldn't serve them from rails or do anything that binds your static files to being served from rails. You may one day decide to serve your app from a CDN.
JS
One big tip would be to look at using AMD (async module definition), which would allow you to specify your JS file dependencies. Then you can use require.js and r.js(a tool that crawl and compile your dependencies in you precompile step). That would work for your JS.
CSS
For CSS, you could use sass or less. You'd include 1 file at the end of the day on your page, but the compilation process would involve merging your CSS files together. Once again this can be done at the pre-compile step.
CDN
There are gems out there that show take your assets and pass them over to something like S3, this answer and others like it would help: Is there a way to asset pipeline assets to s3 when pushing to heroku? ; however, that isn't necessary when you are first starting.
I did it with a Rake task that would fetch each of the Rails routes one at a time. It needed a bit of jiggery pokery to handle the fact that you might have conflicting routes - e.g. wget would fetch /objects as a file called "objects" but then when you want to fetch /objects/4 it would overwrite that file with a folder called "objects" with a nested file called "4". So I move each downloaded page to "index.html" inside a directory with the same name.
Here's my code, which I out in lib/tasks/export.rake:
def adjust_paths(path)
text = File.read(path)
new_contents = text.gsub(/("|\.\.\/)(assets|packs)\//, "\\1../\\2/")
new_contents = new_contents.gsub("http://localhost:3020", "")
File.write(path, new_contents)
end
namespace :static do
desc 'Generate static site in ./out/ directory'
task :export => [
'assets:clean',
'assets:precompile',
:start_rails_server
] do
begin
out_prefix = "dist"
paths = Rails.application.routes.routes.map do |route|
route.path.spec.to_s
end.uniq.reject { |p| p.starts_with?("/rails") || p == "/cable" || p == "/assets" }
paths = paths.map { |p| p.sub("(.:format)", "") }
paths.sort_by(&:length).each do |path|
if path.include?(":id")
# You'll have to use your own method for deciding which ids to use
ids = ["1", "2", "3", "4"]
else
ids = [""]
end
ids.each do |id|
id_path = path.sub(":id", id)
`wget -P #{out_prefix} -nH -p -k http://localhost:3020#{id_path}`
if id_path != "/"
file_path = "#{out_prefix}#{id_path}"
FileUtils.mv(file_path, "#{file_path}.tmp", force: true)
FileUtils.mkdir_p(file_path)
result = FileUtils.mv("#{file_path}.tmp", "#{file_path}/index.html", force: true)
puts "Moving #{id_path} to #{id_path}/index.html: #{result}"
# Will then need to relativise all of the asset paths, since we've moved it
adjust_paths("#{file_path}/index.html")
end
end
end
ensure
# stop the server when we're done
Rake::Task['static:stop_rails_server'].reenable
Rake::Task['static:stop_rails_server'].invoke
end
end
desc 'Start a Rails server in the static Rails.env on port 3020'
task :start_rails_server do
`RAILS_SERVE_STATIC_FILES=1,RAILS_ENV=static rails s -p 3020 -d`
end
desc 'Stop Rails server'
task :stop_rails_server do
`cat tmp/pids/server.pid | xargs -I {} kill {}`
end
end
Then you can just do bundle exec rake static:export

3rd Party Script Caching in Rails 3.1

I have a script 3rd party websites are using: /assets/script.js. For obvious reasons, I can't ask them to change the link every time I deploy to point to the latest fingerprinted version of the script. I got a few caching issues where users still see old versions of /script.js. Are there any ways to make the cache go away directly for script.js instead of script-9dc5afea3571ba2a883a72b0da0bb623.js?
More Information: Rails on Passenger + Nginx. Looking for ways to serve the script.js file instead if the finger-printed file and invalidate the cache on every deployment.
I thought about adding ETags based on the deployment git revision, but have no idea how to do this. Nginx has no built in ETags support. There are unsupported old third party modules that do this. I can use add_header Etag="something" for this, but how do I add the git version there.
Any other ideas and options?
Thanks!
If you have a script with a name that is part of your public interface then you need to start versioning this script explicitly, and keeping old versions around for older clients.
e.g. /assets/script.1.0.js, /assets/script.1.1.js etc
The key part is that you need to be keeping the old ones around, and the code doesn't change without the name changing explicitly. The Rails asset pipeline can't do this for you, since there's usually only the very latest version of the script kept current.
As with all public interfaces, you will need to spend more time on managing this process than you would for an internal-only script.
I recommend using an ETag.
Add an ETag header to your response
http://en.wikipedia.org/wiki/HTTP_ETag
Set the ETag header to a different, unique string for each version of your script.
This will make sure browsers get a new version of the script whenever you deploy a new version .
nginx is able to generate etags in the latest version: http://nginx.org/en/docs/http/ngx_http_core_module.html#etag
I've also seen the configuration below here: https://serverfault.com/questions/426260/nginx-cache-control
location /static {
alias /opt/static/blog/;
access_log off;
etags on;
etag_hash on;
etag_hash_method md5;
expires 1d;
add_header Pragma "public";
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
}
Following up on the ETag suggestion, you might find this gem useful: bust_rails_etags. It allows you to set a key on each deployment which is used in the generation of ETags, that way, your ETags will change (and so the cached script will be invalidated) every time your app is deployed. The author uses the example of Heroku release numbers as a key that changes on each deploy.
What I'm using for updating assets is:
Increment config.assets.version in config/application.rb like
#Version of your assets, change this if you want to expire all your assets
config.assets.version = '1.1'
bundle exec rake assets:precompile RAILS_ENV=production RAILS_GROUPS=assets
App restart, empty webserver cache if any
If you are using Capistrano, you could write a task that copies the script from Public/assets to another directory within Public (i.e. Public/scripts) after your assets are precompiled.
Well you can remove the fingerprint of the file :
asset_path('script.js', :digest => false)
hope it helps
Or you can use this gem if you want : https://github.com/spohlenz/digestion
But : The Rails asset pipeline now compiles asset files both with and without digests.
So after you generate your assets usually you got script.js?xxxxx and script.js into your public/assets folder.
You want a non fingerprinted asset url for third party websites.
For example: assets/public_api.js
There have been plugins or gems that excluded specified assets from fingerprinting. However rails has changed the pre-compilation process in a way that also creates non-fingerprinted files. Therefore this isn't a problem. More info here.
How to make sure your clients are loading the latest deployed script, when the asset is not fingerprinted?
I would suggest the solution youTube uses to expose their API. Basically all your assets/public_api.js does, it injects another script tag into the dom. That injected one loads the actual API code. Now your assets/public_api.js becomes assets/public_api.js.erb and looks something like this:
var tag = document.createElement('script');
tag.src = "<%=asset_path('/assets/javascripts/acctual_api')%>";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
Please note how tag.src is set to the current fingerprinted path to /assets/javascripts/acctual_api. This way your users will always get the latest compiled acctual_api script.
How to update the ETAG for the assets/public_api.js?
I suppose you use Capistrano or similar recipe based deployment solution. Maybe you could add a deployment step that updates the server config file before its restarted. It should just update:
add_header Etag="update_me_on_deploy"
Please note that you should still use versioned (assets/public_api.0.js) public scripts even with this approach.

javascript not running on heroku with rails 3.1

I've migrated a rails 3.0 app to 3.1 on Heroku. It's running on the cedar stack and everything is fine except that the app's javascript won't run. The application.js file is compiled and looks just as it should. It's accessible by going to myapp.com/assets/application.js. It just doesn't get run!
If I run the app locally, the javascript works, so I suspect that there must be some simple configuration issue that I'm missing. Here's my production.rb file:
FloridaBirdTrail::Application.configure do
# Settings specified here will take precedence over those in config/application.rb
# Code is not reloaded between requests
config.cache_classes = true
# Full error reports are disabled and caching is turned on
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
# Disable Rails's static asset server (Apache or nginx will already do this)
config.serve_static_assets = true
# Compress JavaScripts and CSS
config.assets.compress = true
# Send deprecation notices to registered listeners
config.active_support.deprecation = :notify
end
edit
Replacing the contents of production.rb with that of development.rb has allowed at least some of my javascript to run (gmap3 isn't working, for some reason). But which of the settings is making the difference?
Open your application.rb file and make sure your Bundler require statement looks like the following:
Bundler.require *Rails.groups(:assets)
By default it looks like
# If you precompile assets before deploying to production, use this line
Bundler.require *Rails.groups(:assets => %w(development test))
# If you want your assets lazily compiled in production, use this line
# Bundler.require(:default, :assets, Rails.env)
Manually precompiling worked for me.
bundle exec rake assets:precompile before you push to heroku.
Were you sure to switch Heroku to the Cedar stack? Here are some docs for upgrading
http://devcenter.heroku.com/articles/rails31_heroku_cedar#upgrading_from_previous_rails_31_releases
http://devcenter.heroku.com/articles/cedar
I had some Javascript problems (server-side on Heroku, locally everything was fine) that went away when I
* moved all my Javascript into a separate file instead of application.js
* removed require_tree from application.js and instead called up every javascript I wanted by name
* removed bootstrap.js from my app/assets/javascript folder
My guess is that compilation somehow screws things up.
I hope you did a local pre-compilation of assets before your latest Heroku push (as advised in one of the responses above).
Please check if your system is blocking the execution of JavaScripts. For this, open up the console while you are on your Heroku app, and check for exceptions. In case you see exceptions related to JavaScripts being blocked, that could be the issue. In my case, the same happened, and unfortunately, I was not able to do anything about it, as I didn't have admin privileges.

Categories

Resources