一次搞懂 Assets Pipeline

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/

你可能感兴趣的:(部署,预编译,Rails,assets,produciton)