一次搞懂 Assets Pipeline

Assets Pipeline 是 Rails 3.1 一�重要的功能,一直��有很去了解其特性,但因�最近都在�前端的�西在 assets pipeline 的�西上跌跌撞撞了不少次(尤其在 deploy 上 production 後常爆炸,爆到我��自容),�篇就是好好研究後的心得以及��。


Assets Pipeline 有什�好�,不用�怎�?


不用�然不�怎�,你可以在 confing/application.rb 中把他�掉:


1

config.assets.enabled = false

但是 Assets Pipeline 有著�多�良的好�,�助你�理的�去一些需要由第三方元件��理的事情,像是:


�所有的 js 或是 css ��打包成�一�案,�少 http request 的大小��量,增加你�站的效能及速度。

支援像是 SCSS 及 CoffeeScript ��的 high-Lever �言,你可以用更��更棒的方式�� css 及 js。

取代原先不可靠的 query string 改用 MD5 的 fingerprint,query string 的用意在於��案�容更�的�候也�一�更��案的 query string,��可以分辨�案是否有更��,因此客�端可以保留快取�比�自己�有的版本以及伺服器上的版本是否一致,�少每次的 request,�奈 query string 的作法�是有些��,像是在部分 CDN 上根本不�快取、在多伺服器的�境中�案名�可能���、以及�多�效的 cache ��,因此在 Rails 3.1 改使用 MD5 的 Fingerprinting �解�了����。

Assets Pipeline 的功能主要由��重要的元件提供:Sprockets 以及 Tilt。Sprockets 用��你的 assets 路�中打包��你所有的 assets 後包�成一��案,然後放到你目的地路�(public/assets),而 Tilt 主要是一��板引擎,用�� Sprockets 可以去解析像是 SCSS、CoffeeScript 或是 ERB 等各��板,你可以�考 Tilt 的 Readme �了解支援哪些�板。


Assets 的��


首先必�了解 Assets 的��,在 Rails 的目���中有三�地方:


app/assets(通常放置我�自己�了自己的程式所�的 js、css 或是 images)

lib/assets(通常是我�所使用的套件中去用到的 assets)

vendor/assets(通常是放一些我���的地方借用的 assets,例如�一些 jQuery 的套件)

�三�目�,在��情�下�三��料�的�西是共通的(因�都�被打包成一��案),你可以把你的 rails app 跑起�後在 http://localhost:3000/assets/application.js 中看到你所有的 js 都在�支�案中,css 同理亦然,你可以在 terminal 中�入 Rails.application.config.assets.paths �查看所有的 assets 路�。你可以��,除了原本我����的三� assets 目�之外,�出�了包含在我� GemFile 中的 jquery,�代表你的 assets �在也可以包成 gem �用,如果你有很多� projects 常重�使用一些共通的 assets,不妨考�包成 gem �使用,方便又愉快。


Assets 的�入


再�是 assets 目�下的�案 import 方式,以 app/asset/javascripts/application.js �支�案�例,�是一支 manifest �案,主要用�告� Sprockets �哪些�案是要被�入最後要被包起���的,最後�支�案�面所有的�西就�被包成 application.js �支�案,也是我� layout/application.html.erb 中的 javascript_include_tag 'application' 中的�案,打��支�案除了上面的�明外只有�三行:


//= require jquery

//= require jquery_ujs

//= require_tree .

上面�行很明�的就是要�入 jquery 以及 jquery_ujs ��支�案,��支�案��有提到他其�是被包含在我�所使用的 Gem 中,而下面那行 require_tree . 表示是把三� assets/javascript 目�下的�案或是子目��的�案全部都包��,��候你一定�想�如果有些 js 或是 css 我只想在某些特定�面中使用的��怎��,例如�假�我�今天有� admin_functions.js 的�案只想在我�的後台使用,有��方法可以使用:


你可以� require_tree 的目�改成其他目�,例如在 app/assets/javascript 目�下建� common �料�,把 require_tree . 改成 require_tree ./common,��子所�生的 application.js �支�案就不�用到 admin_functions.js �支�案。

你可以建立一�新的�料��放你不想要被 application.js �入的�案,例如我�在 app/assets/javascript 下建立一� admin �料�把��的 admin_functions.js �案放�去,然後把原先 application.js 中的 require_tree . 改� require_directory . ��子只�抓� apllication.js �案同目�底下的所有�案而不�去�入子目�中的�案。

最後再建立另外一支 manifest 用� import 那些我�要�立出�的 assets,例如我�建立一支 admin.js 的�案用��入其他功能,一�使用 require_tree 或是 require_directory 的方式��入,然後在你需要用到的�面中使用 javascript_include_tag 'admin' �存取。


千千��要�得,�你使用 application.js 以外的 manifest �案�,一定要在你�境�定�中��支�案加入 precompile 的清�,否�上了 staging 或是 production �你就�收到一堆 500 Error XXXX isn’t precompiled,加入的位置在�境�定�像是 production.rb 中的 config.assets.precompile += %w( search.js ) 中。


除了 require_tree 及 require_directory 之外,�有其他的用法,你都可以使用��或是相�路��指定�案位置,副�名可有可�:


require [路�] �入某支特定�案,如果�支�案被�入多次,Sprockets 也�很�明的只�你�入一次。

include [路�] � require 一�,差�在即使是被�入�的�案也�再被�入。

require_directory [路�] �路�下不包含子目�的�案按照字母�序依次�入。

require_tree [路�] ��路�下包含子目�的�案全部�入。

require_self [路�] 告� Sprockets 再�入其他的�案前,先�自己的�容插入。

depend_on [路�] 宣告依�於某支 js,在需要通知某支快取的 assets �期�非常�用。

stub [路�] �路�中的 assets 加入黑名�,所有其他的 require 都不��他�入。

你可以看 Sprockets 的 Readme ��得更多的��。


Preprocessing


另外就是 Sprockets 在 Tilt 的�助下有 preprocessing 的功能,例如你可以使用像是 something.js.coffee.erb ��的�名,Sprockets ���名的最後面一直解析回去成最後的�案,因此你可以在 js 中使用 CoffeeScript 的�法�� js,�在�面� ruby code ��生你想要的�西,例如:


jQuery ->

number = <%= 1 + 1 %>

不用我�我想你也知道�有什��果。


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 ��助你,因此你也可以��使用:



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


在�不熟悉的情�下,很容易上了 production �境後��原本在本�好好的�西全部炸掉了,因此我�必�了解一下在 production �作�的情形,如果你直接在 console 中打 rails s -e production ��� production �境�,你����上就��� application.css isn't precompiled,�是因�在 production 的�境下我�的 assets 是必�被 compile �後存在 public/assets 底下的,你可以在 console 中打 rake assets:precompile,Rails ��你把所有的 assets �案依照你 manifests 以及�境�定打包��成�一的�案後放在 public/assets 目�底下,所有的�案名���加入 MD5 的 fingerprinting 用�表示其�容供快取,�些 assets �被 Rack Cache middleware 自�的被快取,如果你想要使用自己的 server �取代 middleware 的功能你也可以自己 precompile 後上�。


在你 precompile 後你再打� localhost:3000 �����已��有��,但是�站看起�就是�有 css 的感�,��候查看 log 你�看到 Rails 找不到 assets �案的��,�是因�在 production �境中是不�理���案的,因此你必�先在 production.rb 中� config.serve_static_assets = false 改成 true,��候重�一次就�看到一切正常,我�已��利在本�上跑起 production �境了,你就可以在本�上��你的 assets pipeline 是否正常,如果你去�� precompile 後的�案你���它�都加上了我�之前提到的 MD5 digest,用�辨�其�案�容是否有所更�,因此你可以�你的 Server �定中的 expires ���到最�,因�在�案�有更�的情�下他都�保持相同的�名,�使用者可以�到最快的效能。


Deploy 的小技巧


在本� precompile ��省在 server 上 precompile 的���使用量


一般我�都�使用 Capistrano � Deploy,�得要� Capfile 中的 load 'deploy/assets' 的�解取消,Deploy 的�程中�使用 production server � compile 你的 assets,如果你很在意 production server 的效能,你可以在本�先 compile 後再上�到 Server,我�只需要覆�原本 Capistrano 所提供的 assets:precompile 功能,在你的 deploy.rb 中加入下面的 Code:


namespace:deploydo
namespace:assetsdo
desc"Precompileassetsonlocalmachineanduploadthemtotheserver."
task:precompile,:roles=>web,:except=>{:no_release=>true}do
run_locally"bundleexecrakeassets:precompile"
find_servers_for_task(current_task).eachdo|server|
run_locally"rsync-vr--exclude='.DS_Store'public/assets#{user}@#{server.host}:#{shared_path}/"
end
end
end
end

���在本� precompile 後使用 rsync ��案上�上去,如果你有使用 Git 的��忘了把 public/assets 加到 .gitignore 中。


如果 assets �有更新�,就不要跑 precompile


precompile ��是整� deploy �程中最漫�的一段��,即使你�有更新 assets �也免不了�你跑一下,你可以一�覆� 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 的情�就在本� precompile 後才上�到伺服器:


namespace :deploy do

namespace :assets do

task :precompile,: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

�考�料:


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/

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


迭代器模式(Iterator)迭代器模式(Iterator)[Cursor]意图:提供一种方法顺序访问一个聚合对象中的每个元素,而又不想暴露该对象的内部表示。应用:STL标准库迭代器实现、Java集合类型迭代器等模式结构:心得:迭代器模式的目的是在不获知集合对象内部细节的同时能对集合元素进行遍历操作
高性能IO模型浅析服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种:(1)同步阻塞IO(BlockingIO):即传统的IO模型。(2)同步非阻塞IO(Non-blockingIO):默认创建的socket都是阻塞的,非阻塞IO要求socket被设置为NONBLOCK。注意这里所说的N
策略模式(Strategy)策略模式(Strategy)[Policy]意图:定义一系列算法,把他们封装起来,并且使他们可以相互替换,使算法可以独立于使用它的客户而变化。应用:排序的比较方法、封装针对类的不同的算法、消除条件判断、寄存器分配算法等。模式结构:心得:对对象(Context)的处理操作可
访问者模式(Visitor)访问者模式(Visitor)意图:表示一个作用于某对象结构中的各元素的操作,它使你在不改变各元素的类的前提下定义作用于这些元素的新操作。应用:作用于编译器语法树的语义分析算法。模式结构:心得:访问者模式是要解决对对象添加新的操作和功能时候,如何尽可能不修改对象的类的一种方
命令模式(Command)命令模式(Command)[Action/Transaction]意图:将一个请求封装为一个对象,从而可用不同的请求对客户参数化。对请求排队或记录请求日志,以及支持可撤消的操作。应用:用户操作日志、撤销恢复操作。模式结构:心得:命令对象的抽象接口(Command)提供的两个
生成器模式(Builder)生成器模式(Builder)意图:将一个对象的构建和它的表示分离,使得同样的构建过程可以创建不同的表示。 应用:编译器词法分析器指导生成抽象语法树、构造迷宫等。模式结构:心得:和工厂模式不同的是,Builder模式需要详细的指导产品的生产。指导者(Director)使用C
设计模式学习心得《设计模式:可复用面向对象软件的基础》一书以更贴近读者思维的角度描述了GOF的23个设计模式。按照书中介绍的每个设计模式的内容,结合网上搜集的资料,我将对设计模式的学习心得总结出来。网络上关于设计模式的资料和文章汗牛充栋,有些文章对设计模式介绍生动形象。但是我相信“一千个读者,一千个
工厂方法模式(Factory Method)工厂方法模式(Factory Method)[Virtual Constructor]意图:定义一个用于创建对象的接口,让子类决定实例化哪一个类,使一个类的实力化延迟到子类。应用:多文档应用管理不同类型的文档。模式结构:心得:面对同一继承体系(Produc
单例模式(Singleton)单例模式(Singleton)意图:保证一个类只有一个实例,并提供一个访问它的全局访问点。应用:Session或者控件的唯一示例等。模式结构:心得:单例模式应该是设计模式中最简单的结构了,它的目的很简单,就是保证自身的实例只有一份。实现这种目的的方式有很多,在Java中
装饰者模式(Decorator)装饰者模式(Decorator)[Wrapper]意图:动态的给一个对象添加一些额外的职责,就增加功能来说,比生成子类更为灵活。应用:给GUI组件添加功能等。模式结构:心得:装饰器(Decorator)和被装饰的对象(ConcreteComponent)拥有统一的接口
抽象工厂模式(Abstract Factory)抽象工厂模式(Abstract Factory)[Kit]意图:提供一个创建一系列相关或相互依赖对象的接口,而无须指定他们具体的类。应用:用户界面工具包。模式结构:心得:工厂方法把生产产品的方式封装起来了,但是一个工厂只能生产一类对象,当一个工厂需要生
桥接模式(Bridge)桥接模式(Bridge)[Handle/Body]意图:将抽象部分与它的实现部分分离,使他们都可以独立的变化。应用:不同系统平台的Windows界面。模式结构:心得:用户所见类体系结构(Window派生)提供了一系列用户的高层操作的接口,但是这些接口的实现是基于具体的底层实现
适配器模式(Adapter)适配器模式(Adapter)[Wrapper]意图:将类的一个接口转换成用户希望的另一个接口,使得原本由于接口不兼容而不能一起工作的类可以一起工作。应用:将图形类接口适配到用户界面组件类中。模式结构:心得:适配器模式一般应用在具有相似接口可复用的条件下。目标接口(Targ
组合模式(Composition)组合模式(Composition)意图:将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。应用:组合图形、文件目录、GUI容器等。模式结构:心得: 用户(Client)通过抽象类(Component)提供的公用接口统一
原型模式(Prototype)原型模式(Prototype)意图:用原型实例制定创建对象的种类,并且通过拷贝这些原型创建新的对象。应用:Java/C#中的Clonable和IClonable接口等。模式结构:心得:原型模式本质上就是对象的拷贝,使用对象拷贝代替对象创建的原因有很多。比如对象的初始化构
什么是设计模式一套被反复使用、多数人知晓的、经过分类编目的、代码 设计经验 的总结;使用设计模式是为了 可重用 代码、让代码 更容易 被他人理解、保证代码 可靠性;设计模式使代码编制  真正工程化;设计模式使软件工程的 基石脉络, 如同大厦的结构一样;并不直接用来完成代码的编写,而是 描述 在各种不同情况下,要怎么解决问题的一种方案;能使不稳定依赖于相对稳定、具体依赖于相对抽象,避免引
单一职责原则定义(Single Responsibility Principle,SRP)一个对象应该只包含 单一的职责,并且该职责被完整地封装在一个类中。Every  Object should have  a single responsibility, and that responsibility should be entirely encapsulated by t
动态代理和CGLib代理分不清吗,看看这篇文章,写的非常好,强烈推荐。原文截图*************************************************************************************************************************原文文本************
适配器模式将一个类的接口转换成客户期望的另一个接口,使得原本接口不兼容的类可以相互合作。
策略模式定义了一系列算法族,并封装在类中,它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。