3 招实用Asset Pipeline 加速 —by xdite
Asset Pipeline 最让人诟病的就是deploy 时花费速度过久。 在社群聚会时发现大家都对这个主题非常不熟。 所以把最近累积了的这方面技巧整理出来分享给大家。
1. Capistrano deployment speedup
使用capistrano 内建task 执行assets:precompie
capistrano内建了‘deploy/assets’
这个task。 只要在Capfile
里面
1 |
|
deploy 就会自动执行assets precompile 的动作。 由原始档可以看到这个task实际执行的是
“cd /home/apps/APP_NAME/releases/20120708184757 && bundle exec rake RAILS_ENV=production RAILS_GROUPS=assets assets:precompile”
而执行的时机是
after ‘deploy:update_code’, ‘deploy:assets:precompile’
许多开发者不知道有这一个task 可以用。 手动写task 去compile,造成了两个问题:
- 时机执行错误。 Compile 时机错误会造成站上出现空白css。
- 执行compile 机器负担太重。 如果是手写的task 通常会是load 整个production 的环境去compile。与只load assets 这个group 所吃的系统资源「有可能」差得非常多。
如果没有变更到assets 时,就不compile
请把这里面的内容贴到你的deploy.rb 档里面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# -*- encoding : utf-8 -*-
set :assets_dependencies, %w(app/assets lib/assets vendor/assets Gemfile.lock config/routes.rb)
namespace :deploy do
namespace :assets do
desc <<-DESC
Run the asset precompilation rake task. You can specify the full path \
to the rake executable by setting the rake variable. You can also \
specify additional environment variables to pass to rake via the \
asset_env variable. The defaults are:
set :rake, “rake”
set :rails_env, “production”
set :asset_env, “RAILS_GROUPS=assets”
set :assets_dependencies, fetch(:assets_dependencies) + %w(config/locales/js)
DESC
task :precompile, :roles => :web, :except => { :no_release => true } do
from = source.next_revision(current_revision)
if capture(“cd #{latest_release} && #{source.local.log(from)} #{assets_dependencies.join ’ ‘} | wc -l”).to_i > 0
run %Q{cd #{latest_release} && #{rake} RAILS_ENV=#{rails_env} #{asset_env} assets:precompile}
else
logger.info “Skipping asset pre-compilation because there were no asset changes”
end
end
end
end |
这是在Railsconf 2012的Stack Smashing上学到的一招。
如果你的assets 档案没有变动的话,只要执行copy 上一版本的assets 就好了。 这段task 会侦测
- app/assets
- lib/assets
- vendor/assets
- Gemfile.lock
- confir/routes.rb
是否有变动。 基本上已经含了所有可能assets 会变动的可能性。 有变动才会重新compile。
整体上会加速非常非常的多 。
2. use @import carefully
避免使用@import “compass”; 这种写法
compass是大家很爱用的SCSS framework。 大家写gradiant 或者css spriate 很常直接开下去。
但是你知道
1 |
|
和
1 |
|
这两种写法。
前者compile 的速度可能比后者慢到9 倍以上吗?
会这么慢的原因,是因为compass本身即是懒人包 , @import “compass”;
会把
- “compass/utilities”;
- “compass/typography”;
- “compass/css3”;
下面的东西通通都挂起来(还跑directory recursive)。
所以自然慢到爆炸。 如果要用什么helper,请直接挂它单支的CSS 就好了,不要整包都挂上来。
全挂其慢无比是正常的。
避免使用partial
我知道partial 是SCSS 整理术的大绝招。 但是若非必要,也尽量避免一直单档一路@import 到底。
1 2 3 |
|
1 2 3 |
|
这两个在asset pipeline 输出结果是一样的。 但后者会比前者快。
如果真的需要用到非得使用partial 的技巧(如需读变数用require 读不到,@import 才读得到)再使用即可,因为只要一牵涉到directory recursive compile 就会慢…
3. don’t require .scss & .coffee for no reason
避免使用require_tree
使用generator 产生controller 时,rails 会自动帮忙产生
- product.css.scss
- product.js.coffee
然后application.css 与application.js 会利用
1 |
|
这种技巧来把这些档案挂上去。
但是你知道吗? 就算这些档案里面只写了这几行注解:
1 2 3 |
|
而且实际执行结果也等于空输出。 compile 一支大概也要250ms。 你可以想想,多compile 10 支,就是2.5 秒了。 难怪超耗时。
可以使用.js 或.css 解决的不要用.scss 与.coffee 当结尾
1 2 3 4 5 |
|
其中custom.css 的档名是custom.css.scss
这样应该知道为什么不要乱用scss 当档名了吧?
小结
为了方便大家调整,我把具体加速assets precompile 过程的步骤罗列在下面。
1. 换掉deploy.rb 的assets precompile tasks
2. 观察logs/product.log。
- 找出慢的assets。
- 拿掉直接使用import “comppass”; 的SCSS,改用功能针对性写法。
- 不需要使用@import 写法的改用require
- 拿掉require_tree,改用//=require 一行一行挂上去
- 删掉空的scss 与coffeescript
- 单纯只是CSS 的不要自作聪明帮忙加上.scss 档名。
====
如果有什么问题,欢迎各位在底下留言讨论。
也欢迎大家有空来Rails Tuesday坐坐。 我很乐意帮大家解答问题。
PS如果你是要问Rails 101书上的问题,请找小蟹。