Rails Asset Pipeline 资源管线(笔记)
细节小记:
# Search Paths in assets
The default locations are: app/assets/images
and the subdirectories javascripts
and stylesheets
in all three asset locations, but these subdirectories are not special. Any path under assets/*
will be searched.
也就是说,在assets目录下的任何第一层目录,都可作为搜索的目录。默认的是3个:images、stylesheets,javascripts。
# 除了搜索assets,其他目录也是可以配置的
Besides the standard assets/*
paths, additional (fully qualified) paths can be added to the pipeline in config/application.rb
. For example:
config.assets.paths << Rails.root.join("lib", "videoplayer", "flash")
Paths are traversed in the order that they occur in the search path. By default, this means the files in app/assets
take precedence, and will mask corresponding paths in lib
and vendor
.
#必须添加到precompile
It is important to note that files you want to reference outside a manifest must be added to the precompile array or they will not be available in the production environment.
# Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) config.assets.precompile += ['admin.css','admin.js']如果不这样做也可以,但是不太好。如下:
在production。rb文件里面,配置如下:
# Don't fallback to assets pipeline if a precompiled asset is missed config.assets.compile = true
# Coding Links to Assets
用而且只应该用着3个:
stylesheet_link_tag
javascript_include_tag
image_tag
# Manifest Files and Directives
不光能编译单个文件,也能够把一些文件连接在一起形成一个文件。
好处:减少请求次数
坏处:导致单个文件过大,响应时间增长;万一其中一个文件修改了,整个文件的cache将失效;
等等,坏处很多的,注意使用啊!
# Using Index Files
Sprockets uses files named index
(with the relevant extensions) for a special purpose.
For example, if you have a jQuery library with many modules, which is stored in lib/assets/library_name
, the file lib/assets/library_name/index.js
serves as the manifest for all files in this library. This file could include a list of all the required files in order, or a simple require_tree
directive.
这种方法挺好了,适合有很多组件和分拆的情况。
#Preprocessing
For example, a stylesheet called app/assets/stylesheets/projects.css.scss.erb
is first processed as ERB, then SCSS, and finally served as CSS.
很不错这种思想。
一、综述
1、可以将JS和CSS合并和压缩,有写CoffeeScript、Sass和ERB的能力(可以处理这些语言的代码)
2、在Rails的3.1版本集成了Sprockets的组件。开发人员利用这个功能可以将静态资源预执行、压缩、最小化,这是Rails默认最快策略的一部分。所以在Rails3.1版本中默认生效。当然,可以在config/application.rb的文件中更改config.assets.enabled = false禁用资源管线的功能,亦可在新建Rails工程时禁用这个功能,只在当前工程有效:rails new appname --skip-sprockets。
主要特性
管线的首要特性是连接资源,这在生产环境中非常重要,可以快速的生成页面。在Rails3.1以上的版本中,Sprockets将所有的JS和CSS文件合并成一个 .js 和 .css 文件,在生产环境中Rails为合并后的文件名中加入 MD5 的指纹识别,这在开启缓存时非常有效。每当文件更改后,指纹识别码会更改,之前的缓存会自动失效。
第二个是资源最小化或者压缩。执行这一过程时,CSS文件中的空格和注释、换行符会被删除;JS文件会复杂些,支持自定义的配置。
第三个是,默认支持预编译脚本,比如:CSS的Sass,JS的CoffeeScript,适用于CSS和JS的ERB。
二、使用资源管线
当资源管线生效时,JS和CSS资源的首选位置在app/assets下,该目录下的文件由包含在Sprockets Gem中的Sprockets中间件负责提供服务。
在生产环境中,Rails预编译app/assets中的资源默认放到public/assets中,该目录下的文件会被当作静态资源对待,app/assets中的文件将不再使用。
当创建控制器时,Rails会为其生成一个JS文件(若在Gemfile文件中添加coffee-rails的gem,会生成CoffeeScript文件)和一个CSS文件(若添加了sass-rails的gem,会生成SCSS文件)。例如:创建 ProjectController 后,会看到生成了app/assets/javascripts/projects.js和app/assets/stylesheets/projects.css.scss文件。在控制器对应的资源中可以加入任何独立的JS和CSS文件,因为这些资源可以通过下面的方式由控制器加载,比如:<%= javascript_include_tag params[:controller] %> 或者 <%= stylesheet_link_tag params[:contrFller] %>。
1、组织资源
资源管线可以放在app/assets、lib/assets、vendor/assets等位置。app/assets下的资源属于应用程序,包括自定义图片,JS和CSS文件;lib/assets下的文件属于自定义类库或者共享库,不在应用程序的范畴;vendor/assets下的文件属于外部对象,比如外部JS插件和CSS框架。
a、搜索路径
当文件在资源清单或帮助器中引用时,Sprockets会默认搜索这三个位置。例如:
app/assets/javascripts/home.js
lib/assets/javascripts/movinator.js
vendor/assets/javascripts/slider.js
资源清单的书写方式为:
// =require home
// =require movinator
// =require slider
子文件夹下的资源也可以访问到,例如:
app/assets/javascripts/sub/something.js
资源清单如下:
//= require sub/something
这些配置可以在config/application.rb文件中找到,默认的为下面的语句:
config.assets.paths << Rails.root.join("app", "assets", "data")
在Rails控制台中输入 Rails.application.config.assets.paths 可以看到配置。
注意:在资源清单外引用文件时,需将其添加到预编译数组中,否则在生产环境下不可用。预编译数组在下面会有介绍。
b、使用索引文件
比如,有多个模块的jQuery,存储在 lib/assets/library_name下,lib/assets/library_name/index.js文件作为所以模块的资源清单文件。这个文件中按顺序列出所有的资源。文件的内容如下:
//= require library_name
有了这个文件管理资源很方便。
2、编写链接资源的代码
Sprockets不需要添加新的方法来访问资源,使用熟悉的javascript_include_tag和stylesheet_link_tag,例如:
<%= stylesheet_link_tag "application" %>
<%= javascript_include_tag "application" %>
访问图片例子:
<%= image_tag "rails.png" %>
app/assets下面的资源由Sprockets负责提供服务。而在public/assets/下面资源,比如public/assets/rails.png由web服务器直接提供服务。Sprockets也会搜索在配置文件中指定的config.assets.paths值。图片也可以指定放在子文件夹中,使用方法如下:
<%= image_tag "icons/rails.png" %>
a、CSS 和 ERB
资源管道自动处理ERB。一旦在CSS资源上加上erb的扩展名(比如:app.css.erb),那么像asset_path这样的帮助器就可以用在css中,例如:
.class {background-image: url(<%= asset_path 'image.png' %>)}
在资源加载时会指向 app/assets/images/image.png。若采用 data URI的方式,可以使用asset_data_uri帮助器,这会在CSS中插入图片数据,例如:
#logo {background: url(<%= asset_data_uri 'logo.png' %>)}
b、CSS和Sass
使用资源管道时,定位到图片、字体、视频、音频、JS和CSS等资源的路径必须重写,并且 sass-rails 提供了 -url和 -path 帮助器,如下:
url(/assets/rails.png) 的方式变成 image-url("rails.png")
"/assets/rails.png" 的方式变成 image-path("rails.png")
也可以使用更常用的方法,但是必须指定资源路径而且类型也必须要指定:
url(/asset/rails.png) 的方式变成 asset-url("rails.png", image)
"/assets/rails.png" 的方式变成 asset-path("rails.png", image)
c、JS/CoffeeScript 和 ERB
若在JS文件后加上erb的后缀(比如:app.js.erb),那么在JS代码中就可以使用asset_path 帮助器,比如:
$('#logo').attr({src: "<%= asset_path('logo.png') %>"});
与之类似,在CoffeeScript文件后加上erb后缀(比如:app.js.coffee.erb),可以使用asset_path帮助器,比如:
$('#logo').attr src: "<%= asset_path('logo.png') %>"
3、资源清单和指令
Sprockets 使用资源清单文件,以此来决定哪些文件会被包含,并提供服务。这些文件中包含指令,Srockets可以识别哪些文件可以按顺序合并成单独的css文件和js文件。可以使用的指令包括 require和require_tree。require指令告诉Sprockets哪些文件是必须的。require_tree指令告诉Sprockets在指定的目录下所有的js文件都需要,这个路径必须是相当资源清单文件的地址。当然也可以使用require_directory,指定某个目录,但不包含递归。还有其他的指令,比如require_self等。
4、预处理
文件的扩展名决定其是否会被预处理。使用默认的gem生成控制器时,一个CoffeeScript和一个SCSS文件会生成,比如:app/assets/javascripts/project.js.coffee和app/assets/stylesheets/project.css.scss。当请求这些文件时,coffee-script 和sass的gem包会将他们处理成对应的css和js文件。预处理可以加入其他的层,扩展名会被自右向左处理,比如:app/assets/stylesheets/projects.css.scss.erb文件,会先由ERB处理,再由SCSS处理,最后提供css。
三、开发环境
开发模式下,资源清单中的文件会被单独显示,不会被合并成独立的文件。
1、关闭调试:
在config/environments/development.rb文件中更改为config.assets.debug = false。当关闭调试时,Sprockets会对所有的文件进行连接并进行必要的预处理。资源清单中的文件会被合并成单独的文件。服务启动后第一次访问时,资源会被编译并缓存。Sprockets会设置 must-revalidate Cache-Control 请求头验证,以便减少服务器压力。如果在服务期间,资源清单中的文件更改,服务器会响应新的文件。
调试模式可以内嵌到在Rails帮助器中,比如:
<%= stylesheets_link_tag "application", :debug => true %>
<%= javascript_include_tag "application", :debug => true %>
四、生产环境
在生产环境中,Rails使用指纹方案。默认Rails会假设资源已经预编译并且会以静态文件的方式提供服务。
1、预编译资源
Rails捆绑了一个 rake 命令,可以编译资源清单和资源管线中的其他文件并生成到硬盘中,默认位置为 public/assets 目录。
在创建资源的编译版本并部署时,调用这个任务。rake任务如下:
bundle exec rake assets:precomile
为了更快的执行资源预编译,可以通过在config/application.rb文件中设置config.assets.initialize_on_precompile为false执行预加载应用。但在这种情况下,模版不能扫描到应用程序对象和方法。
默认编译application.js,application.css和所有非js和css的文件(.coffee和.scss不会被自动包含进去,因为他们编译成js和css文件)
[ Proc.new{ |path| !File.extname(path).in?(['.js', '.css']) }, /application.(css|js)$/ ]
若有其他的资源清单或者分离的css和js文件需要包含进去,可以将他们放到预编译数组中,例如:
config.assets.precompile += ['admin.js', 'admin.css', 'swfObject.js']
rake 命令会生成一个 manifest.yml 的文件,包含所有的资源名称和他们对应的指纹码。典型的资源清单如下:
---
rails.png: rails-bd9ad5a560b5a3a7be0808c5cd76a798.png
jquery-ui.min.js: jquery-ui-7e33882a28fc84ad0e0e47e46cbf901c.min.js
jquery.min.js: jquery-8a50feed8d29566738ad005e19fe1c2d.min.js
application.js: application-3fdab497b8fb70d20cfc5495239dfc29.js
application.css: application-8af74128f904600e41a6e39241464e03.css
默认的资源清单在config.assets.prefix指定的路径根目录下(默认为/assets)。可以在 config.assets.manifest选项中指定绝对路径:
config.assets.manifest = '/path/to/some/other/location'
2、服务配置
预编译过的资源放在磁盘上并且通过web服务器提供服务。但是并不会默认设置销毁头,因此为了体现指纹的优势,需要做以下配置:
Apache的配置:
<LocationMatch "^/assets/.*$">
Header unset ETag
FileETag None
# RFC says only cache for 1 year
ExpiresActive On
ExpiresDefault "access plus 1 year"
</LocationMatch>
Nginx的配置:
location ~ ^/assets/ {
expires 1y;
add_header Cache-Control public;
add_header ETag "";
break;
}
Sprockets会创建资源的gzip压缩版本。web服务器的典型配置是使用中度压缩,但是由于已经进行了预编译,Sprocket会使用最大的压缩率,因此减少了数据传输量。另一方面,web服务器可配置成从硬盘中获取压缩好的内容直接提供服务。Nginx的配置如下:
location ~ ^/(assets)/ {
root /path/to/public;
gzip_static on; # to serve pre-gzipped version
expires max;
add_header Cache-Control public;
}
3、及时编译(Live Compilation)
某些情况下,需要使用及时编译模式。在这个模式中所有的资源的请求都由Sprockets直接处理,可以通过下面的语句开启:
config.assets.compile = true
第一次请求时资源会被编译并缓存,而且在帮助器中使用的资源名称也会加上 MD5的标识。Sprockets会为这些资源加上 Cache-Control 的HTTP头,其中max-age=31536000
这种模式会消耗更多的内存,性能较差,不推荐使用。
若部署生产应用时不存在任何的JavaScript运行时,会出错,需要在Gemfile文件中加入以下引用:
group :production do
gem 'therubyracer'
end
五、自定义管线
1、CSS 压缩
有一个可选的CSS压缩工具 YUI。启用YUI压缩如下:
config.assets.css_compressor = :yui
config.assets.compress = true
需要添加 yui-compressor 的gem。
2、JS压缩
JS压缩工具有 closure,uglifier,yui,他们对应的gem如下:closure-compiler,uglifier,yui-compressor。Ruby默认的压缩是uglifier。
3、使用自己的压缩工具
CSS和JS的的压缩配置需要定义一个对象,并且对应必须存在 compress的方法,该方法有个字符串参数,必须返回一个字符串,范例如下:
class Transformer
def compress(string)
do_something_returning_a_string(string)
end
end
在application.rb中按下面的方式修改,会使配置生效:
config.assets.css_compressor = Transformer.new
4、改变 assets 的路径
Sprockets的默认公共路径为 /assets。更改路径的设置为:
config.assets.prefix = "/some_other_path"
这在已经存在的工程中,使用新的资源的路径时很有用。
5、X-Sendfile Headers
X-Sendfile 头表示指向web服务器忽略应用的响应,并从磁盘上直接提供文件服务。这个功能默认关闭。如果打开,文件服务会更快。Apache和Nginx支持这个配置:
config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
From:http://hi.baidu.com/superwanderman/item/51942441fe1037fedd0f6cce
+
+
+
-
+
+
+