25

The command "rake assets:precompile" works very slow for me. Especially on my Amazon EC2 Micro production server which does not have a lot of processor resources. On EC2 I have to wait 1 minute or more during each deployment just for this precompile task alone. Is there a way to make it faster?

Previously I used Jammit to compress/minify css and js. Jammit worked nearly 10 times faster on the same web site and servers.

Evgenii
  • 36,389
  • 27
  • 134
  • 170
  • 2
    you could precompile your assets before deploying – Marian Theisen Sep 24 '11 at 06:44
  • 1
    Right, I thought about that. But I do not know how I will deploy the precompiled assets to production easily. I am using capistrano and each time it will commit the precompiled assets to git. My concern is that git repository will grow fast in this case, keeping the history of all previous assets. And that is not just css/js - but all the asset images as well. – Evgenii Sep 25 '11 at 12:34
  • 2
    It's extremely slow for me too (135,987ms = ~2 minutes). I'll have to look into precompiling before deploying... I'm concerned about adding them to git as well, mostly because that would add a lot of noise to the git logs. I would recommend not adding them to git -- just rsync that directory from localhost to your webserver as part of your cap deploy script. – Tyler Rick Nov 18 '11 at 20:18
  • If you don't need to load the Rails environment, you should disable it with: `config.assets.initialize_on_precompile = false` – ndbroadbent Jan 16 '12 at 06:52

3 Answers3

30

If you don't need to load the Rails environment, you should disable that with:

config.assets.initialize_on_precompile = false

EDIT: I've just written a gem to solve this problem, called turbo-sprockets-rails3. It speeds up your assets:precompile by only recompiling changed files, and only compiling once to generate all assets.

It would be awesome if you could help me test out the turbo-sprockets-rails3 gem, and let me know if you have any problems.

ndbroadbent
  • 13,513
  • 3
  • 56
  • 85
10

There is a bug in Rails 3.1.0 that includes too many files in the precompile process. This could be the reason for the slowness if you have many assets js and css assets.

The other is that Sprockets (the gem doing the compilation) is more complex and has to allow for more options - scss, coffeescript and erb. Because of this I suspect it will be slower doing just concatenation and minification.

As suggested, you could precompile the files before deploying them if this is still an issue.

Richard Hulse
  • 10,383
  • 2
  • 33
  • 37
  • Thank you for the explanation. I also think it is slow because it needs to load the rails environment on production, which was not the case for Jammit. In any case, I am not going to return to Jammit. I like the asset pipeline a lot. – Evgenii Sep 25 '11 at 12:38
1

My solution is to exclude application.js .css and any other application related assets from from precompilation. So that i can use rake assets:precompile once to precompile engine related assets only.

Then on each deploy i use a simple rake task to build any application related assets and merge them into manifest.yml:

namespace :assets do
  task :precompile_application_only => :environment do
    require 'sprockets'

    # workaround used also by native assets:precompile:all to load sprockets hooks 
    _ = ActionView::Base

    # ==============================================
    # = Read configuration from Rails / assets.yml =
    # ==============================================

    env           = Rails.application.assets
    target        = File.join(::Rails.public_path, Rails.application.config.assets.prefix)
    assets        = YAML.load_file(Rails.root.join('config', 'assets.yml'))
    manifest_path = Rails.root.join(target, 'manifest.yml')
    digest        = !!Rails.application.config.assets.digest
    manifest      = digest


    # =======================
    # = Old manifest backup =
    # =======================

    manifest_old = File.exists?(manifest_path) ? YAML.load_file(manifest_path) : {}

    # ==================
    # = Compile assets =
    # ==================

    compiler = Sprockets::StaticCompiler.new(env,
                                            target,
                                            assets,
                                            :digest => digest,
                                            :manifest => manifest)
    compiler.compile

    # ===================================
    # = Merge new manifest into old one =
    # ===================================

    manifest_new  = File.exists?(manifest_path) ? YAML.load_file(manifest_path) : {}

    File.open(manifest_path, 'w') do |out|
       YAML.dump(manifest_old.merge(manifest_new), out)
    end

  end
end

To specify which assets to compile i use a YAML configuration file (config/assets.yml):

eg.

---
- site/site.css
- admin/admin.css
- site/site.js
- admin/admin.js
mcasimir
  • 678
  • 6
  • 12