Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

Asset Pipeline ignores assets.compress config option #5145

Closed
batter opened this Issue Feb 23, 2012 · 48 comments

Comments

Projects
None yet

batter commented Feb 23, 2012

When you create a brand new application using rails 3.2.x, the default configuration for the asset pipeline in the development environment, as set in config/environments/development.rb is as follows:

# Do not compress assets
config.assets.compress = false

# Expands the lines which load the assets
config.assets.debug = true

This is described in the Asset Pipeline documentation as shown here. Unfortunately, this setup doesn't actually work out of the box. If you generate a brand new application with a basic controller serving up a page with plain text, and then inspect the code, you'll notice that it does indeed acknowledge the config.assets.debug = true option, as multiple javascript files will be included (jquery.js and jquery_ujs.js are provided by default).

However, if you inspect what's inside of the application.js file that is being served up, you will notice that it is actually a compressed combination of all the others. This must mean that config.assets.compress = false is being ignored and treated as true no matter what.

You'll also notice that if you inspect the javascript console in a browser like chrome, it causes a javascript error to be thrown with this message: Uncaught TypeError: undefined is not a function (application.js:32). Worse yet, all jQuery scripts cease to function properly if you try to run with it like this. I believe the error is thrown as a result of jQuery being included twice, but it's difficult to tell for certain since the application.js file is compressed.

Note that the application will still function fine in production mode, but it doesn't work properly in development mode. Now there are two possible workarounds; the first is to set config.assets.debug = false, which will prevent the individual javascript files from being served up. This defeats the purpose of the development mode configuration, as the application will essentially work as though it's being run in production mode (with just one giant compressed application.js file). The second, more functional workaround, as found here is to add config.serve_static_assets = false to your config/environments/development.rb file. This will only work if you run rake assets:precompile at least once.

The fact remains that this is a bug, and that unless this is addressed, the assets.compress option is essentially useless without a hack workaround.

Here's a link to a simple app I created which demonstrates this bug.

I am not the first to acknowledge this. It has been mentioned in this issue report, as well as this post on StackOverflow. Pardon me for re-posting this but I feel the other issue is mislabeled.

batter commented Feb 29, 2012

Cheers @cap10morgan. Thanks for taking affirmative on this one!

Owner

guilleiguaran commented Apr 27, 2012

I couldn't reproduce this with a new generated app, I'm using default settings and I don't get the files concatenated and compressed in application.js

Owner

guilleiguaran commented Apr 27, 2012

can you provide an app to reproduce your error?

@ghost ghost assigned guilleiguaran Apr 30, 2012

batter commented May 7, 2012

@guilleiguaran - Here's a link to a simple app I created which demonstrates this bug. Simply clone, then run with rails s then inspect the source and look at the contents of assets/application.js to see the bug in question demonstrated.

If you look at the commits I make in the order that I made them, it seems to be the running of rake assets:precompile that triggers this problem (even though the feedback from running the command indicates it should only be affecting the production environment... rake assets:clean:all RAILS_ENV=production RAILS_GROUPS=assets).

Contributor

gaurish commented May 22, 2012

I can reproduce this issue using the app you push on to github. jquery is included as jquery.js & also gets bundled into application.js

However, I do not get any javascript errors.

batter commented May 22, 2012

@gaurish - You are correct. It doesn't actually give you an javascript errors as I originally reported. I was fairly certain I had an app at some point that was throwing javascript errors as a result of this but it may have been an unrelated javascript file that was causing that to happen.

jspaper commented May 24, 2012

I got the same issue. Hope someone could provide solutions.
thanks.

@jspaper & @fullbridge-batkins I was having this same problem.

It turned out it was from running rake assets:precompile early on in the project.

When I ran rake assets:clean it was running it with the production ENV.

RAILS_ENV=development rake assets:clean did the trick.

jspaper commented May 26, 2012

hi @tommyvyo ,
I try to 'RAILS_ENV=development rake assets:clean' and 'rm -rf tmp/cache/assets', but still didn't work.
Rails 3.2.3 and ruby 1.9.3-p125

@jspaper what about /rails_project/public/assets/ ?

jspaper commented May 26, 2012

@tommyvyo public/assets only few file. I try to 'find . -name application*.js' only find manifest file.

svileng commented May 27, 2012

I am experiencing a similar problem. I have no //=require jquery-ui in application.js, nothing in tmp/ and public/assets/ directories, and yet, jquery-ui gets magically loaded with all the other javascript files I have. When I search for the jquery-ui file the only result I get is from the gem directory where the jquery-rails gem is installed, so it is definitely not in my project directory. I am also using Rails 3.2.3 with ruby 1.9.2p180 (2011-02-18) [i386-mingw32].

@svileng and @jspaper just to double check you tried

RAILS_ENV=development rake assets:clean
rm -rf public/assets

on top of restarting the Rails server? I was using powder and it took a powder restart for the changes to take effect.

jspaper commented May 28, 2012

@tommyvyo ,I did as you say many times, but still didn't work.
Finally, I try to modify application.js file, delete one blank line and did what you say. Everything work properly, even recover application.js and didn't clean the assets.

setting config.assets.debug = false solved the problem for me. The debug==true seems to cause the javascript_include_tag to create a separate tag for every js file, plus a reference to application.js

it seems like the logic should be:

if config.assets.debug
[generate individual js file links, but not application.js]
else
[generate application.js and drop link to it into the page ]
end

jspaper commented Jun 8, 2012

hi @daveheitzman ,
If you set debug to false, you can't debug in development. It's really not a good idea.
Solution is modify application.js anything and clean assets, that's all.
:)

I tried the solution you mention, but it didn't work for me. I have no trouble debugging . It's just that
with debug==false, only 1 js file is produced , solving the double jquery issue. A fix should really be done so that with debugging==true, only code within the application.js file itself gets compiled into the application.js that is sent to the browser.

batter commented Jun 8, 2012

@daveheitzman - Exactly. That's what I was trying to say in the first place.

toxaq commented Jun 12, 2012

The only thing that worked for me was removing everything from application.js, reloading that application.js directly (it becomes empty) and then putting everything back into it. If you reload Application.js it is still empty.

I experienced the same issue: playing with production and dev environments locally, launching rake assets:precompile i got application.js full with scripts in development mode, debug == true. But it should contain manifest only.
After I cleaned up tmp folder and restarted the application application.js become a manifest back again. So issue is solved for me. I use Rails 3.2.6, sprockets 2.1.3. I didn't have a time to look deeper, possibly it's assets caching issue.

batter commented Aug 22, 2012

Just updated my Sample App which displays the bug to use the most recent version of rails (3.2.8). This problem is still occurring. Upon further reflection, I can only assume that this is happening because the precompiled assets are marked as static assets, so if you have serve_static_assets = true (as it is by default), then Rails throws it in there.

I don't agree with the notion that the public/assets directory contents should be thought of static assets to be served when serve_static_assets = true.

Contributor

gaurish commented Sep 2, 2012

So the issue is jQuery & other js files are regarded as static assets by asset pipile & therefore are included twice? Correct?

batter commented Sep 6, 2012

@gaurish - If you have jQuery and other JS files in your app/assets/javascripts directory, and then have precompiled your assets, then those scripts will get thrown into public/assets as a result. The files in public/assets are then designated as static assets by rails, and get served up twice when you run in development mode (once in your condensed application.js file, and then again as uncompressed/separated files).

This isn't really a problem when it's only jQuery, but certain JS files will throw javascript errors when they are included/run twice in a row. This in turn causes your javascript functionality to stop working correctly. This is only an issue in development mode, but still bothersome.

Contributor

codyrobbins commented Sep 6, 2012

I can confirm this bug as well and it is highly annoying. I’ve done all of the following:

  • rake assets:clean
  • RAILS_ENV=development rake assets:clean
  • rm -rf public/assets
  • rake tmp:clear
  • Restarted the server.
  • Cleared my browser cache.

Rails continues compiling all of my Javascript assets into application.js but also including them individually in the page in <script> tags. I’m on Rails 3.2.7 and Ruby 1.9.3-p194.

Got the same issue here.

criess commented Sep 27, 2012

confirming this issue. Using config.assets.debug = false for my dev environment right now. Is highly annoying as comments state here.

kuon commented Sep 30, 2012

If I remove public/assets and empty the browser cache, the issue is cleared for me (with config.assets.debug = true).

The solution would be to ensure application.js is not included, but this would force user to not put any code into application.js below the comments.

This issue has been infuriating me lately. I know for sure it happens in one of my apps where I've precompiled the assets (for checkin) but then forgot to clean them out after a push. I really want to see a better process for deployments that don't involve having a JS runtime in the production environment.

That being said, I run into this issue as well in other rails apps (3.2.6) where I've never performed an asset precompile. It's a major issue for backbone-run apps because you get errors when the browser history is fired up a second time ... since all assets are included twice, including initializers.

What is the deal with this issue? It's crazytown. I've wasted lots of man hours, spinning my wheels and trying to get to the bottom of it. Every time I think I've nailed it, the next day I see it reappear in my app again.

Update: Hit this again. Assuming you've cleaned your assets out after a precompile, the next place to look is browser caching. Which has been mentioned. For me, it's Chrome caching the results of application.js?body=1. An incognito window solves it, but that is not ideal. Looking for a better fix. I tried incrementing the asset version in application.rb but that did not help. I don't even understand why cache headers are being served with these assets when in dev mode, but I guess that's a different conversation.

I've put more testing into this and can get it to happen with a bare bones, fresh rails app (3.2.6). It's the browser caching the old file and I can repro it in chrome and safari (haven't tested anything else). The reliable fix for me is to alter "application.js" in some way that will affect the rendered JS file, reloading in the browser, then removing my file edit. Let's see if I can write some steps down ... they are long winded and probably could be a lot more concise but here they are ...

  1. rails new testapp; cd testapp; rm public.index.html
  2. rails g controller Welcome
  3. echo "welcome#index" >> app/views/welcome/index.html.erb
  4. echo "console.log('hello from welcome.js.coffee')" >> app/assets/javascripts/welcome.js.coffee
  5. At this point, fire up your rails app and check it out in the browser, with your javascript console open just to verify you're seeing what you'd expect: one console.log statement.
  6. Kill your rails app, and run: rake assets:precompile
  7. Start the app again, go to your browser, reload. You'll now see two console.log statements. The first from your welcome.js file and the second from the compiled asset file (which includes all JS assets).
  8. Kill the rails app once again, run: rake assets:clean
  9. At this point you can verify that the public/assets directory is gone as expected.
  10. Start the rails app again
  11. Edit app/assets/javascripts/welcome.js.coffee to log a different message
  12. Reload in the browser, you'll see two messages, both your old and new one.
  13. Edit app/views/javascripts/application.js to include some statement that will be output, such as a console.log statement.
  14. Reload in the browser again and you'll finally see just one console.log statement, as you would expect.

So the question is, what cache headers are being set for the final JS include of application.js?body=1 and what makes them different than what we're expecting?

+1 I just experienced this while developing. There goes an hour

Here is what happened to me:

  • Precompiled asset in development at some time
  • Finished what i was doing and set configs back to normal for development
  • Made changed in my JS that were ignored by my app (this is when i realised it was using a compiled application.js)
  • ran rake assets:clean - no change
  • finally, decided to manually delete /public/assets/javascripts/application.js
  • still no change, had to delete browser cache
  • finally back to working order

It seems rails is ignoring the config file if there is an application.js already present. I haven't looked at the rails source to confirm this though

EDIT:

here is my development.rb file
config.assets.compress = false
config.assets.debug = true

+1 I true fix would be helpful I just figured out why all of a sudden in development my js confirmation prompts started appearing twice and it was because I had precompled assets and deployed into production (where this problem does not happen).

Contributor

gouravtiwari commented Nov 19, 2012

+1 this is really annoying! Eagerly waiting for this to be fixed.

Owner

pixeltrix commented Dec 6, 2012

This should be fixed by c59734f

@pixeltrix pixeltrix closed this Dec 6, 2012

batter commented Dec 7, 2012

@pixeltrix - looks like you reverted your change with af73e3c, so this should be re-opened I would imagine? Based on the discussion in c59734f, however, it sounds like this issue may not be an easy fix.

Owner

pixeltrix commented Dec 7, 2012

@fullbridge-batkins the way we're going to deal with it is by showing a warning if the specific set of conditions required for this bug to manifest itself exists when the application boots. Heroku uses ActionDispatch::Static to serve files so the commit would make the serving of files there slower and it was decided that flipping the behaviour based upon config.cache_classes or the environment name was undesirable.

If you wish to workaround it in your app you can by setting config.serve_static_assets = false in config/environments/development.rb and mounting the ActionDispatch::Static app in your config/routes.rb, e.g:

# Put this at the end of your config/routes.rb
if Rails.env.development?
  app = ActionDispatch::Static.new(
    lambda{ |env| [404, { 'X-Cascade' => 'pass'}, []] },
    Rails.application.config.paths['public'].first,
    Rails.application.config.static_cache_control
  )

  mount app, :at => '/', :as => :public
end

batter commented Dec 10, 2012

Thanks for the response. I also use Heroku to host many of my applications, so it sounds like this is not a good idea for usage in my apps.

I feel like there should be some way that we can add an option to Rails::Application.configure which gives users the option to toggle this on or off, that way they can modify it on a per environment basis to ensure that they don't get unexpected results when running in production mode, but can still toggle it on when in development mode, don't you?

Owner

pixeltrix commented Dec 10, 2012

@fullbridge-batkins if you disable config.serve_static_assets and add the above code to the end of routes.rb it's behaves exactly the same as the original commit so I don't think it's worth adding a config.

Contributor

shioyama commented Feb 27, 2013

Echoing someone else on this thread: there goes an hour, and not much learned from it except that caching assets in dev mode can cause problems.

macler commented May 15, 2013

This is simple, ad-hoc solution. Add :shell guard that delete public/assets/application.js and public/assets/application.js.gz. Put it after rails-assets and before livereload.

guard 'rails-assets', :run_on => [:start, :change] do
watch(%r{^app/assets/.+$})
watch('config/application.rb')
end

guard :shell, :all_on_start => true do
watch('public/assets/application.js') { rm public/assets/application.js }
watch('public/assets/application.js.gz') { rm public/assets/application.js.gz }
end

guard 'livereload' do
watch(%r{app/views/.+.(erb|haml|slim)$})
watch(%r{app/helpers/.+.rb})
watch(%r{public/.+.(css|js|html)})
watch(%r{config/locales/.+.yml})

Rails Assets Pipeline

watch(%r{(app|vendor)(/assets/\w+/(.+.(css|js|html))).*}) { |m| "/assets/#{m[3]}" }
end

What is the fix/workaround for this bug, or more precisely #5095, in development environment with a nonexistent public/assets directory?

batter commented Nov 25, 2013

As mentioned on my original post:

The second, more functional workaround, as found here is to add config.serve_static_assets = false to your config/environments/development.rb file.

That change does not appear to have any effect on my application.

batter commented Feb 6, 2014

@p-originate - you need to set these accordingly as well:

# Do not compress assets
config.assets.compress = false

# Expands the lines which load the assets
config.assets.debug = true

After hassling with this for about a week, I've finally stubbled upon disabling 'config.assets.debug' in my Dev env. That works, but isn't exactly optimal.

I see no warning about my environment being wacky. Stuff (like drop downs) was just failing in Dev, and working in Staging (with pre-compiled assets). Doing a 'rake assets:clean' had no effect for me (in Dev) - only turning off assets.debug allowed Dev to function "normally".

I'm also apparently seeing multiple copies of some files (at least being processed) during the pre-compilation step for Staging/Productions. This doesn't appear to be causing me any problems at this point though.

Where is the proposed Warning supposed to be displayed? (if it got into the source base @pixeltrix ?) I'm not seeing anything in the Webrick output that I'm using for my Dev env.

I'm using Rails 3.2.12, Bootstrap(-sass) 3.1.1


The workaround documented above by @pixeltrix doesn't appear to fix my issue. Only setting config.assets.debug = false allows the Dev site to work properly.

Ooops - sorry. Spoke to soon. The workaround does work, once I cleared out the browser's cache.

cec commented Sep 11, 2014

Hi, I have the following in my development.rb

config.assets.compress = false
config.assets.compile = true
config.assets.debug = true

in my case the problem was a rake assets:precompile that I ran for some performance tests.
Doing a simple RAILS_ENV=development rake assets:clean and clearing browser cache solved the problem.

To be more specific about my problem, my rails_admin backend was not opening collapsed field groups or split drop-down buttons, making the backend unusable in development.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment