Friday, 20 April 2012

Compiled asset woes

3.1 introduced the , which is a great addition but can cause some unfortunate issues.
One that has recently been an issue for us is a cascade of behaviours that individually are all perfectly reasonable but, when combined, leave you with major headaches.

When you compile your assets with you get (as expected) your files, in compiled, minified form in the folder public/assets.

Files in public/assets are served in preference to anything produced by the Rails stack (they shadow your controllers). Perfect behaviour for caching, disabling certain routes, etc. and makes sure you are familiar with how things would act with a web server in front of Rails.

In development mode, Rails will serve all your javascript files separately, while precompiled only the manifest files will be present. So in development, you may have several (or even dozens) of files, while in production you only have one. Again, fantastic behaviour for caching, reducing requests and a whole host of other things.

In combination with precompiled assets though, it's disastrous. Your top level file (assets/application.js) in development is pretty much empty, but compiled contains all or almost all of your application's javascript. If the compiled version gets served in development then all your javascript is sent to the browser twice... and this is almost certainly going to break things.

If you're lucky and you have a light javascript application, the most you may notice is some effects not working correctly, maybe you'll investigate briefly on production and see it works fine, put it down as a development machine problem (or you'll solve the problem and never think about it again until it happens again).

On a heavy javascript application with a lot of javascript running in the browser, chances are your entire application will simply not work. If you aren't aware of the cascade of issues, this can take a long time to solve.

If you're running automated tests against everything (using tools like capybara-webkit or poltergeist) then the situation is slightly changed. In the test environment, Rails doesn't serve separate assets in a single file. But the file will still be served from public/assets in preference to the Rails stack, so your tests will run against the last version you precompiled. Again, this can be very confusing and even if you're aware of the previous behaviour it can take you a while to work out why tests that run fine on one machine (with no precompiled assets) don't work on another (where you precompiled assets last week for a demo and haven't cleaned them out).

Is there a solution? Yes, there's a very simple one. Simply configure Rails to serve your assets from a different location depending on environment.

Add the line to config/environments/development.rb file and a similar one to config/environments/test.rb
and the problem is now gone and you can compile assets on any machine without fear of causing issues if you forget to clean them up.

No comments:

Post a Comment