Assets Pipeline 是 Rails 3.1 一��重要的功能,一直�K�]有很去了解其特性,但因�樽罱�都在��前端的�|西在 assets pipeline 的�|西上跌跌撞撞了不少次(尤其在 deploy 上 production 後常爆炸,爆到我�o�自容),�@篇就是好好研究後的心得以及�P�。
Assets Pipeline 有什�N好�,不用��怎��?
不用��然不��怎�樱�你可以在 confing/application.rb 中把他�P掉:
1
config.assets.enabled = false
但是 Assets Pipeline 有著�S多��良的好�,�椭�你�理的�^去一些需要由第三方元件�硖�理的事情,像是:
�⑺�有的 js 或是 css �嚎s打包成�我�n案,�p少 http request 的大小�c�盗浚�增加你�W站的效能及速度。
支援像是 SCSS 及 CoffeeScript �@�拥� high-lever �Z言,你可以用更��胃�棒的方式��� css 及 js。
取代原先不可靠的 query string 改用 MD5 的 fingerprint,query string 的用意在於���n案�热莞��拥�r候也��一�愀���n案的 query string,�@�涌梢苑直�n案是否有更�舆^,因此客�舳丝梢员A艨烊�K比�ψ约�碛械陌姹疽约八欧�器上的版本是否一致,�p少每次的 request,�o奈 query string 的作法�是有些���},像是在部分 CDN 上根本不��快取、在多伺服器的�h境中�n案名�Q可能����印⒁约霸S多�o效的 cache ���},因此在 Rails 3.1 改使用 MD5 的 Fingerprinting �斫�Q了�@�����}。
Assets Pipeline 的功能主要由���重要的元件提供:Sprockets 以及 Tilt。Sprockets 用��哪愕� assets 路�街写虬��嚎s你所有的 assets 後包�b成一���n案,然後放到你目的地路��(public/assets),而 Tilt 主要是一���影逡�擎,用�碜� Sprockets 可以去解析像是 SCSS、CoffeeScript 或是 ERB 等各�N�影澹�你可以�⒖� Tilt 的 Readme �砹私庵г�哪些�影濉�
Assets 的�Y��
首先必�了解 Assets 的�Y��,在 Rails 的目��Y��中有三��地方:
app/assets(通常放置我��自己�榱俗约旱某淌剿���的 js、css 或是 images)
lib/assets(通常是我��所使用的套件中去用到的 assets)
vendor/assets(通常是放一些我����e的地方借用的 assets,例如�f一些 jQuery 的套件)
�@三��目�,在�A�O情�r下�@三���Y料�A的�|西是共通的(因�槎��被打包成一���n案),你可以把你的 rails app 跑起�磲嵩� http://localhost:3000/assets/application.js 中看到你所有的 js 都在�@支�n案中,css 同理亦然,你可以在 terminal 中�入 Rails.application.config.assets.paths �聿榭此�有的 assets 路�健D憧梢园l�F,除了原本我�������f的三�� assets 目�之外,�出�F了包含在我�� GemFile 中的 jquery,�@代表你的 assets �F在也可以包成 gem �碛茫�如果你有很多�� projects 常重�}使用一些共通的 assets,不妨考�]包成 gem �硎褂茫�方便又愉快。
Assets 的�d入
再�硎� assets 目�下的�n案 import 方式,以 app/asset/javascripts/application.js �@支�n案�槔�,�@是一支 manifest �n案,主要用�砀嬖V Sprockets �f哪些�n案是要被�d入最後要被包起��嚎s的,最後�@支�n案�e面所有的�|西就��被包成 application.js �@支�n案,也是我�� layout/application.html.erb 中的 javascript_include_tag 'application' 中的�n案,打�_�@支�n案除了上面的�f明外只有�@三行:
//= require jquery
//= require jquery_ujs
//= require_tree .
上面�尚泻苊黠@的就是要�d入 jquery 以及 jquery_ujs �@�芍�n案,�@�芍�n案����有提到他其��是被包含在我��所使用的 Gem 中,而下面那行 require_tree . 表示是把三�� assets/javascript 目�下的�n案或是子目��鹊�n案全部都包�M�恚��@�r候你一定��想��如果有些 js 或是 css 我只想在某些特定�面中使用的��怎�N�k,例如�f假�O我��今天有�� admin_functions.js 的�n案只想在我��的後台使用,有�煞N方法可以使用:
你可以�� require_tree 的目�改成其他目�,例如在 app/assets/javascript 目�下建�� common �Y料�A,把 require_tree . 改成 require_tree ./common,�@�幼铀��a生的 application.js �@支�n案就不��用到 admin_functions.js �@支�n案。
你可以建立一��新的�Y料�A�矸拍悴幌胍�被 application.js �d入的�n案,例如我��在 app/assets/javascript 下建立一�� admin �Y料�A把����的 admin_functions.js �n案放�M去,然後把原先 application.js 中的 require_tree . 改�� require_directory . �@�幼又��抓�c apllication.js �n案同目�底下的所有�n案而不��去�d入子目�中的�n案。
最後再建立另外一支 manifest 用�� import 那些我��要��立出�淼� assets,例如我��建立一支 admin.js 的�n案用�磔d入其他功能,一�邮褂� require_tree 或是 require_directory 的方式�磔d入,然後在你需要用到的�面中使用 javascript_include_tag 'admin' �泶嫒 �
千千�f�f要�得,��你使用 application.js 以外的 manifest �n案�r,一定要在你�h境�O定�n中�⑦@支�n案加入 precompile 的清�危�否�t上了 staging 或是 production �r你就��收到一堆 500 Error XXXX isn’t precompiled,加入的位置在�h境�O定�n像是 production.rb 中的 config.assets.precompile += %w( search.js ) 中。
除了 require_tree 及 require_directory 之外,�有其他的用法,你都可以使用�^��或是相�β��碇付�n案位置,副�n名可有可�o:
require [路��] �d入某支特定�n案,如果�@支�n案被�d入多次,Sprockets 也��很�明的只�湍爿d入一次。
include [路��] �c require 一�樱�差�e在即使是被�d入�^的�n案也��再被�d入。
require_directory [路��] �⒙�较虏话�含子目�的�n案按照字母�序依次�d入。
require_tree [路��] ���⒙�较掳�含子目�的�n案全部�d入。
require_self [路��] 告�V Sprockets 再�d入其他的�n案前,先�⒆约旱�热莶迦搿�
depend_on [路��] 宣告依�於某支 js,在需要通知某支快取的 assets �^期�r非常��用。
stub [路��] �⒙�街械� assets 加入黑名�危�所有其他的 require 都不���⑺��d入。
你可以看 Sprockets 的 Readme �慝@得更多的�Y�。
Preprocessing
另外就是 Sprockets 在 Tilt 的�f助下有 preprocessing 的功能,例如你可以使用像是 something.js.coffee.erb �@�拥�n名,Sprockets ����n名的最後面一直解析回去成最後的�n案,因此你可以在 js 中使用 CoffeeScript 的��法��� js,�K在�e面�� ruby code �懋a生你想要的�|西,例如:
jQuery ->
number = <%= 1 + 1 %>
不用我�f我想你也知道��有什�N�Y果。
Helper
Assets 提供了很多路�� helper �碜�你指向你的 assets:
audio_path("horse.wav") # => /audios/horse.wav
audio_tag("sound") # => <audio src="/audios/sound" />
font_path("font.ttf") # => /fonts/font.ttf
image_path("edit.png") # => "/images/edit.png"
image_tag("icon.png") # => <img src="/images/icon.png" alt="Icon" />
video_path("hd.avi") # => /videos/hd.avi
video_tag("trailer.ogg") # => <video src="/videos/trailer.ogg" />
Sass �提供了像是 -url 和 -path �@�拥� helper ��f助你,因此你也可以�@�邮褂茫�
image-url("rails.png") # => url(/assets/rails.png)
image-path("rails.png") # => "/assets/rails.png".
asset-url("rails.png", image) # => url(/assets/rails.png)
asset-path("rails.png", image) # => "/assets/rails.png"
Production
在�不熟悉的情�r下,很容易上了 production �h境後�l�F原本在本�C好好的�|西全部炸掉了,因此我��必�了解一下在 production �\作�r的情形,如果你直接在 console 中打 rails s -e production ���� production �h境�r,你���l�F�R上就���e�` application.css isn't precompiled,�@是因�樵� production 的�h境下我��的 assets 是必�被 compile �^後存在 public/assets 底下的,你可以在 console 中打 rake assets:precompile,Rails ���湍惆阉�有的 assets �n案依照你 manifests 以及�h境�O定打包�嚎s成�我坏�n案後放在 public/assets 目�底下,所有的�n案名�Q�K��加入 MD5 的 fingerprinting 用�肀硎酒�热莨┛烊。��@些 assets ��被 Rack Cache middleware 自�拥谋豢烊。�如果你想要使用自己的 server �砣〈� middleware 的功能你也可以自己 precompile 後上�鳌�
在你 precompile 後你再打�_ localhost:3000 ���l�F�@�r已��]有�e�`,但是�W站看起�砭褪�]有 css 的感�X,�@�r候查看 log 你��看到 Rails 找不到 assets �n案的�e�`,�@是因�樵� production �h境中是不�理�o�B�n案的,因此你必�先在 production.rb 中�� config.serve_static_assets = false 改成 true,�@�r候重�_一次就��看到一切正常,我��已��利在本�C上跑起 production �h境了,你就可以在本�C上�y�你的 assets pipeline 是否正常,如果你去�z� precompile 後的�n案你���l�F它��都加上了我��之前提到的 MD5 digest,用�肀嬲J其�n案�热菔欠裼兴�更�樱�因此你可以�⒛愕� Server �O定中的 expires �r�g�{到最�L,因�樵�n案�]有更�拥那�r下他都��保持相同的�n名,�使用者可以�_到最快的效能。
Deploy 的小技巧
在本�C precompile �砉�省在 server 上 precompile 的����w使用量
一般我��都��使用 Capistrano �� Deploy,�得要�� Capfile 中的 load 'deploy/assets' 的�]解取消,Deploy 的�^程中��使用 production server �� compile 你的 assets,如果你很在意 production server 的效能,你可以在本�C先 compile 後再上�鞯� Server,我��只需要覆��原本 Capistrano 所提供的 assets:precompile 功能,在你的 deploy.rb 中加入下面的 Code:
namespace :deploy do namespace :assets do desc "Precompile assets on local machine and upload them to the server." task :precompile, :roles => web, :except => {:no_release => true} do run_locally "bundle exec rake assets:precompile" find_servers_for_task(current_task).each do |server| run_locally "rsync -vr --exclude='.DS_Store' public/assets #{user}@#{server.host}:#{shared_path}/" end end end end
�@���在本�C precompile 後使用 rsync ��n案上�魃先ィ�如果你有使用 Git 的��e忘了把 public/assets 加到 .gitignore 中。
如果 assets �]有更新�r,就不要跑 precompile
precompile ���是整�� deploy �^程中最漫�L的一段�r�g,即使你�]有更新 assets �r也免不了�o你跑一下,你可以一�痈�� assets:precompile �砼�嗍欠裼懈�新 assets,如果�]有才�绦� precompile:
namespace :deploy do
namespace :assets do
task :precompile, :roles => :web, :except => { :no_release => true } do
from = source.next_revision(current_revision)
if capture("cd #{latest_release} && #{source.local.log(from)} vendor/assets/ app/assets/ | 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
��然你可以�⑸厦�啥� Code 合而�橐唬�有更新 assets 的情�r就在本�C precompile 後才上�鞯剿欧�器:
namespace :deploy do
namespace :assets do
task :precompile, :roles => :web, :except => { :no_release => true } do
from = source.next_revision(current_revision)
if capture("cd #{latest_release} && #{source.local.log(from)} vendor/assets/ app/assets/ | wc -l").to_i > 0
run_locally "bundle exec rake assets:precompile"
find_servers_for_task(current_task).each do |server|
run_locally "rsync -vr --exclude='.DS_Store' public/assets #{user}@#{server.host}:#{shared_path}/"
end
else
logger.info "Skipping asset pre-compilation because there were no asset changes"
end
end
end
end
�⒖假Y料:
RailsGuides Asset Pipeline
Asset Pipeline for Dummies
#279 Understanding the Asset Pipeline
#341 Asset Pipeline in Production
Speed up assets:precompile with Rails 3.1/3.2 Capistrano deployment
转自:http://gogojimmy.net/2012/07/03/understand-assets-pipline/