15

In my dev sandbox

RAILS_ENV=production rake assets:precompile

is taking over 4 minutes to complete. Is this normal. On heroku it is taking over 10 minutes to do the job and sometimes is timing out. Is there any way to disect this and/or speed it up?

UPDATE

I profiled the CSS vs JS phases of compilation

3.7 s        js
175 s            css

The numbers were made by instrumenting here

----------------------
/Users/bradphelan/.rvm/gems/ruby-1.9.2-p180@gobbq/gems/sprockets-2.1.2/lib/sprockets/processing.rb
----------------------
266     # Assign a compressor to run on `application/javascript` assets.
267     #
268     # The compressor object must respond to `compress` or `compile`.
269     def js_compressor=(compressor)
270       expire_index!
271  
272       unregister_bundle_processor 'application/javascript', :js_compressor
273       return unless compressor
274  
275       register_bundle_processor 'application/javascript', :js_compressor do |context, data|
276  
277         timeit "js" do
278           compressor.compress(data)
279         end
280  
281       end
282     end

and

    ----------------------
    /Users/bradphelan/.rvm/gems/ruby-1.9.2-p180@gobbq/gems/sprockets-2.1.2/lib/sprockets/processing.rb
    ----------------------
    241  
    242     # Assign a compressor to run on `text/css` assets.
    243     #
    244     # The compressor object must respond to `compress` or `compile`.
    245     def css_compressor=(compressor)
    246       expire_index!
    247  
    248       unregister_bundle_processor 'text/css', :css_compressor
    249       return unless compressor
    250  
    251       register_bundle_processor 'text/css', :css_compressor do |context, data|
    252         timeit "css" do
    253           compressor.compress(data)
    254         end
    255       end
    256     end

The timeit call is the added bit doing the timing

def timeit context
  s = Time.now
  yield.tap do 
    e = Time.now
    d = e - s
    puts "#{d*1000}\t #{context}"
  end
end
bradgonesurfing
  • 30,949
  • 17
  • 114
  • 217
  • Here are a few things I found on increasing performance... not really an answer; more like some pointers: [1]: http://stackoverflow.com/questions/9546831/rake-assetsprecompile-is-slooooow-any-way-to-speed-it-up [2]: http://stackoverflow.com/questions/8568786/poor-time-performance-of-rake-assetsprecompile [3]: http://www.ruby-forum.com/topic/2538285 – ScottJShea Mar 16 '12 at 16:15
  • Actually one of those links looks like a likely candidate. I had a suspicion that the rails app was being loaded multiple times somehow. http://www.ruby-forum.com/topic/2538285#1026719 – bradgonesurfing Mar 16 '12 at 19:47
  • Oh good... I was worried my answer would be so broad as to be annoying. – ScottJShea Mar 16 '12 at 19:49
  • 2
    Setting config.assets.compress = false drops the compile time to 40s on my dev machine. So javascript compression is taking 3minutes and 20 seconds. We are not compiling here the boost C++ libraries!! – bradgonesurfing Mar 16 '12 at 19:53
  • I don't think that is the answer. I mean I still want compression. That it takes so long requires fixing rather than turning off the feature. – bradgonesurfing Mar 16 '12 at 19:55
  • This is totally wierd. By default RAILS does not compress CSS, it just strips out whitespace and comments. Why would it be so slow? – bradgonesurfing Mar 16 '12 at 22:11
  • No it seems by default rails uses Sass::Rails::CssCompressor to compress CSS and this is the bad boy! – bradgonesurfing Mar 16 '12 at 22:21

4 Answers4

6

I am on Rails 3.2.13 - I had the same problem with css compression taking an extremely long time. To fix:

In Gemfile add:

gem 'yui-compressor'

In config/environments/production.rb:

config.assets.css_compressor = :yui
config.assets.js_compressor = :yui

rake assets:precompile without those changes: 325 seconds

rake assets:precompile with those changes: 79 seconds

rake assets:precompile with no compression: 45 seconds

Yoni Baciu
  • 2,667
  • 1
  • 22
  • 28
  • This did not work for me. The time was roughly the same, around 6 minutes! – Isaac Betesh Jun 20 '13 at 15:21
  • Are you sure you precompiled in production mode? – Yoni Baciu Jun 20 '13 at 19:51
  • I was using capistrano. I am quite sure of it. – Isaac Betesh Jul 03 '13 at 17:33
  • 1
    I updated my answer to include config.assets.js_compressor = :yui this made a big difference – Yoni Baciu Sep 13 '13 at 20:30
  • Thanks. I tried `config.assets.js_compressor = :yui` and my capistrano deployment process dropped from 4 minutes to about 45 seconds. – Isaac Betesh Sep 16 '13 at 19:48
  • This was a great tip. My production compile time went from 25 minutes to 5. ckeditor has tons of assets, which is what was causing the problem. I also had to use version 0.11 of yui-compressor to work around a problem where 0.12's version of the yui compressor (2.4.8) crashes when compiling empty JS files. yui compressor 2.4.7 does not have this problem. – Matt Schwartz Feb 28 '14 at 03:24
3

The hackety hack solution seems to be to monkey patch the standard sass compression engine out of the way. I added this to the top of my application.rb

module Sass
  module Rails
    class CssCompressor
      def compress(css)
        css
      end
    end
  end
end

The difference in file size was 124k before the monkey patch and 125k after and an order of magnitude speed improvement.

bradgonesurfing
  • 30,949
  • 17
  • 114
  • 217
1

We had orders of magnitude speedup using this answer:

EXECJS_RUNTIME='Node' JRUBY_OPTS="-J-d32 -X-C" RAILS_ENV=development bundle exec rake war

http://avinmathew.com/improving-rails-asset-precompile-times-on-jruby/

Elmer
  • 317
  • 1
  • 13
1

The best option is compile locally, commit and deploy as normal, disabling the precompile task for production. I am doing this for all my production apps now.

To get around those compiled assets being served in Development mode (overriding dynamic pipeline compilation, which you need) do the following.

In development.rb place the following line:

config.assets.prefix = "/dev-assets"

This over-rides whatever is set in application.rb (normally "/assets").

You will also need this in application.rb:

config.assets.initialize_on_precompile = false

That stops the task trying to connect to your database. (Beware if you are referring to ActiveRecord models in your assets, as this won't work).

These changes allow you to compile and commit the assets to your repository locally, and have those files in your working development tree, but for development requests to still be sent to Sprockets. Plus, you only have to precompile and commit when something has actually changed.

Ref my blog post

Richard Hulse
  • 10,383
  • 2
  • 33
  • 37
  • Please read the comments and details. There is a problem with the CSS compressor that takes a long time either compiled locally or in production. – bradgonesurfing Mar 17 '12 at 08:22