Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combining assets into a single file in Rails 4 development environment

I'm trying to extract all vendor assets into separate file and serve them as a minified and combined file also in development environment. I could do that in Rails 3 by using debug: false in javascript_link_tag and stylesheet_link_tag helpers like this:

<%= stylesheet_link_tag    "vendor",      :media => "all", :debug => false %>
<%= stylesheet_link_tag    "application", :media => "all" %>
<%= javascript_include_tag "vendor",      :debug => false %>
<%= javascript_include_tag "application" %>

That made Rails to serve me vendor.js and vendor.css as a minified and combined assets even in development environment. application.js and application.css were served as usually in development environment.

I can not achieve similar results in Rails 4, because if using the lines above, then this will be generated into html for every asset specified in vendor assets:

<script debug="false"... ><script>

How to achieve the same thing in Rails 4?

I have written a detailed blog post for Rails 3 about this feature at my blog. You can check it out if my question is not clear enough http://itreallymatters.net/post/45763483826/speeding-up-page-load-time-in-rails

like image 358
Jarmo Pertman Avatar asked Jun 06 '13 19:06

Jarmo Pertman


People also ask

How do you Precompile rails assets?

To compile your assets locally, run the assets:precompile task locally on your app. Make sure to use the production environment so that the production version of your assets are generated. A public/assets directory will be created. Inside this directory you'll find a manifest.

What is assets Precompile?

rails assets:precompile is the task that does the compilation (concatenation, minification, and preprocessing). When the task is run, Rails first looks at the files in the config.assets.precompile array. By default, this array includes application.js and application.css .

How does Rails asset pipeline work?

The asset pipeline provides a framework to concatenate and minify or compress JavaScript and CSS assets. It also adds the ability to write these assets in other languages such as CoffeeScript, Sass and ERB. Prior to Rails 3.1 these features were added through third-party Ruby libraries such as Jammit and Sprockets.


2 Answers

Overall: Its a regression with Sprockets 2. Read on for an explanation and solution.

How Debugging works internally

Assume you have a file called vendor.js with the following:

# vendor.js
//= require jquery
//= require knockout
//= ... some more requires

function one() { }
function two() { }
// and some javascript code

First, let's see what the Asset Debugging does:

  1. Places a single <script src="vendor.js"> tag if debugging is disabled,

    (or)

    Places multiple <script src="vendor.js?body=1">, <script src="jquery.js?body=1">, <script src="knockout.js?body=1">, ... when debugging is enabled

  2. The body=1 is also an integral part of debugging. If you say <script src="vendor.js?body=1"> - it only renders the javascript inside vendor.js. It doesn't include any of the other require ... code.

    But if you hit vendor.js alone, without the ?body=1, it includes all the require ... code as well.

So a combination of the above two produce the necessary debugging output. What we want to do is, when we say javascript_include_tag "vendor", :debug => false, we want a single <script src="vendor.js"> tag with NO ?body=1 appended.

Explaining the Regression

The regressed code is here. Specifically the buggy code is this one statement:

L88. if request_debug_assets?

Its checking request_debug_assets?, and then automatically setting :debug => true further in line #92. But request_debug_assets? is returning true, because that is being set at the application configuration level.

This one statement should have ideally been:

L88. if request_debug_assets? && options["debug"] != false

Solution / Patch

I'll raise a pull request for the same, but until the pull request is reviewed and merged, you can do the following in an initializer:

# config/initializers/sprockets_debug_patch.rb
module Sprockets::Rails::Helper

  def javascript_include_tag(*sources)
    options = sources.extract_options!.stringify_keys

    # CHECK options["debug"] as well, not just the global assets.debug
    if request_debug_assets? && options["debug"] != false
      # REST ALL SAME CODE AS ORIGINAL METHOD

Do the same for stylesheet_include_tag as well. Unfortunately there is no better way than copy/pasting the method code, but this resolves the problem.

Throughout Sprockets::Rails::Helper class, you will find that it says all this will be deprecated in Sprockets 3.x. I don't know if Rails 4 is scheduled to ship with Sprockets 3.x. If so, then these patches might end up not being required.

like image 136
Subhas Avatar answered Sep 18 '22 16:09

Subhas


Another option if you don't want to use monkeypatch right now and you are just trying to work with your app without worrying about all of you assets is to set / change

config.assets.debug = false
config.assets.compress = false 

in config/development.rb

like image 6
konung Avatar answered Sep 20 '22 16:09

konung