Rail4.1 Asset Pipeline

来源:互联网 发布:为什么叫云计算 编辑:程序博客网 时间:2024/06/05 14:15

原文:http://guides.rubyonrails.org/asset_pipeline.html

此篇主讲资源通道。

从中你可以知道:

  • l  资源通道是什么以及它可以做什么
  • l  如何适当的组织应用的资源
  • l  资源通道的好处
  • l  如何添加预先处理机制到通道
  • l  如何使用gem来打包资源

1          什么是资源通道?

资源通道提供了一个可以将Javascript和CSS资源进行压缩、连接的框架。它同时也支持使用CoffeeScript、Sass和ERB等语言编写资源的预处理。

资源通道已不再是Rails4的核心特性,已经从Rails框架中被提取到sprockets-railsgem中。

资源通道默认被开启。

在新建项目时,可以通过—skip-sprockets选项来禁止资源通道。

         rails new appname –skip-sprockets

              Rails4会在Gemfile文件中自动添加sass-rails,coffee-rails和uglifier 3个gem包,这些gem被Sprockets用于压缩资源。

                            gem‘sass-rails’

                            gem‘uglifier’

                            gem‘coffee-rails’

             使用—skip-sprockets参数,将阻止Rails4自动添加sass-rails和uglifier2个gem包。若在开发过程中,想使用资源通道特性,需要手动在Gemfile中添加以上两个gem包。若在创建是使用了—skip-sprockets参数,Rails4将会自动生成轻便型的config/application.rb文件,在该文件中注释着一条sprocket railtie语句。若在开发过程中,想继续使用资源通道,也必须将此句反注释。

                            #require “sprockets/railstie”

            可以在production.rb中设定资源的压缩方式,如config.assets.css_compressor是用于设定CSS的压缩方式;config.assets.js_compressor是用于设定Javascript的压缩方式。

                            config.assets.css_compressor= :yui

                            config.assets.js_compressor= :uglify

           注意:若使用sass-railsgem包,在没有配置config.assets.css_compressor的前提下,将自动将此gem包设置为CSS的压缩方式。

1.1         主要特性

通道的首要特性是链接资源,减少浏览器渲染页面的请求数量。浏览器同一时间可处理的请求数量是一定的,因此越少的请求数量,页面加载的就越快。

Sprockets将所有的Javascript脚本合并到一个.js文件中,并将所有的CSS文件合并到一个.css文件中。在接下来的教程中,将学到如何自定义合并文件的策略。在生产环境中,Rails为每个文件插入一个MD5指纹,以便该文件被浏览器缓存。当文件内容改变后,将自动改变文件的指纹,使得浏览器缓存中的文件无效。

             资源通道的第二个特性是资源轻便化/压缩化。对于CSS文件,将对文件中的空行和注释进行去除。对于javascript脚本,处理过程将更复杂。你可以从内置的参数集合中进行自定义。

             资源通道的第三个特性是允许使用高级语言来编写资源,并对资源通过预编译变成实际资源。支持的语言包括:编写CSS的Sass,编写Javascript的CoffeeScript以及Rails框架默认的ERB。

1.2         什么是指纹?为什么注意它?

指纹是使得文件的名称依赖于文件内容的一项技术。当文件的内容改变后,文件的名字也改变。由于文件的内容是静态的、不经常变更的,因此通过内容来识别不同版本的文件是否一致是很便捷的,甚至可识别不同服务器以及发布日期的文件。

当文件名是唯一的,并通过对文件内容的识别,HTTP头部能够设置为允许在任何地方进行缓存(包括CDNs,ISPs,网络设备以及浏览器),允许保存一份文件内容拷贝。当文件内容更新后,指纹也相应的变化。指纹的变化,将会使得远程客户端重新请求一份文件内容。此过程通常称为缓存清除。

Rails中sprockets使用的指纹技术是在文件名最后中插入根据文件内容生成的哈希码。例如CSS文件global.css的指纹形式为:

         global-908e25f4bf641868d8683022a5b62f54.css

此策略也是资源通道采用的策略。

Rails就策略是在通道链接的最后使用内容的帮助方法插入基于日期的查询字符串。生成的指纹形式:

                                     /stylesheets/global.css?1309495796

添加查找字符串策略的缺点:

  • l  不是所有的缓存可通过查找参数来识别文件的不同。

Steve Souders”…避免使用查询字符串策略识别缓存资源”。他发现请求用例的5-20%将不被缓存,更重要的是无法很好的工作于某些CDNs。

  • l  文件名能在多服务器环境的不同节点上被改变。

在Rails 2.x中采用的查询字符串策略,是基于文件的修改时间。当资源被部署到服务器群时,不能够保证所有的时间戳都一致,导致根据响应请求的服务器不同生成的查询字符串也会不同。

  • l  过多的无效缓存。

当静态资源随着新发布的代码被部署时,这些文件的最终修改时间将改变,强制令所有远程客户端重新获取文件,即使这些文件资源的内容并未改变。

指纹技术通过避免使用查询字符串修复了这些问题,并确保了文件内容一致的情况下文件名也一致。

指纹技术默认在生产环境下开启,在其他环境下关闭。你可以通过config.assets.digest参数来配置是否开启指纹功能。

 更多内容请阅读:

缓存优化(http://code.google.com/speed/page-speed/docs/caching.html)

加速资源:请不要使用查询字符串(http://www.stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring/)

2          如何使用资源通道?

在Rails的先前版本中,所有的资源都被放在public目录下,如images、javascripts和stylesheets。使用资源通道后,选择了更好的路径放置资源,即将所有的资源放到app/assets目录下。在该目录下的文件会被Sprockets中间件调用。

资源仍可以放置在public目录结构中。任何public下的资源将web服务器/应用看做是静态资源。你应该将需要预先编译的资源,放置到app/assets目录中。

在生产环境中,Rails默认将预先编译的资源放入到public/assets目录中。这些预先编译的拷贝将会被web服务器看做静态资源。对于app/assets目录中的资源,在生产环境中将不会被服务器直接调用。

2.1         针对具体控制器的特定资源

在你生成脚手架或者控制器时,Rails将自动为控制器生成JavaScript脚本文件(若包含有coffee-rails gem包将会生成CoffeeScript脚本文件)和CSS文件(若包含有sass-rails gem包将会生成SCSS文件)。

 例如,若你生成了ProjectsController控制器,Rails将会自动生成app/assets/javascripts/projects.js.coffee文件和app/assets/stylesheets/projects.css.scss文件。这些文件,将会通过默认的require_tree指令被控制器直接调用。可查看资源清单和指令了解详情(http://guides.rubyonrails.org/asset_pipeline.html#manifest-files-and-directives)。

你也能够为控制器分别设定不同的样式表和Javascript脚本文件,如下所示:

<%= javascript_include_tagparams[:controller] %> or <%= stylesheet_link_tag params[:controller]%>

当你如此做的时候,要确保不使用require_tree指令,否则将导致你的资源被重复包含。

注意:当使用资源预编译时,在页面加载时你需要确保控制器的资源已经被预编译成静态资源。默认的.coffee文件和.scss文件不会进行自动预编译。而在开发环境中,资源文件将会在使用时被自动预编译成静态资源。在生产环境中,你将遇到500错误,这是因为自动预编译默认被关闭。详情请查看预编译资源(http://guides.rubyonrails.org/asset_pipeline.html#precompiling-assets)。

若你使用CoffeeScript,你必须有ExecJS运行环境支持。若你使用MacOS X或者Windows,你需要在系统中安装JavaScript运行环境。详情请查看ExecJS文档(https://github.com/sstephenson/execjs#readme)。

你可以通过配置config/application.rb来取消使用特定资源文件,如下:

                            config.generatorsdo |g|

                                     g.assetsfalse

                            end

2.2         资源组织结构

应用的资源通道路径有三处:app/assets,lib/assets或vendor/assets。

  • l  app/assets是用于存储应用本身的资源,例如自定义的图片以及脚本文件或者样式表。
  • l  lib/assets是用于存储你所拥有的分享库的代码,此类代码不一定是必须的。
  • l  vendor/assets用于存储第三方所有的代码,例如Javascript插件和CSS框架。

注意:若从Rails 3更新上来的应用,需要注意lib/assets或vendor/assets目录中的资源虽然可以通过应用清单进行来包含,但是不能够进行预编译操作。详情请查看预编译资源章节(http://guides.rubyonrails.org/asset_pipeline.html#precompiling-assets)。

2.2.1    搜索路径

当文件在清单或帮助方法中被引用,Sprockets将从3处默认的资源位置查找文件。

默认的路径是:app/asset文件夹下images,Javascript和stylesheets子目录,但是这些子目录并不一定——位于assets/*路径下的所有子目录都可被搜索。

例如,这些文件:

app/assets/javascripts/home.js

lib/assets/javascripts/moovinator.js

vendor/assets/javascripts/slider.js

vendor/assets/somepackage/phonebox.js

可被在清单文件中这样引用:

//= require home

//= require moovinator

//= require slider

//= require phonebox

子目录中的资源也能够被访问到。

app/assets/javascripts/sub/something.js

可以如此的引用:

 //= requiresub/something

你可以通过在RailsConsole中输入Rails.application.config.assets.paths来查看搜索路径。

除了标准的assets/*路径外,Rails也允许自定义添加路径,通过配置config/application.rb即可,如下:

config.assets.paths<< Rails.root.join(“lib”,”videoplayer”,”flash”)

 如上配置后,路径将会出现在搜索路径中。默认情况下,在app/assets目录中的文件优先被引用,并且将隐藏lib和vendor中同名的文件。

若想引用清单文件以外的资源,你必须将该资源添加到预编译数组中,否则无法在生产环境中使用。

2.2.2    使用索引文件

Sprockets通过文件命名索引(和关联性扩展)来指向具体的文件。

例如:若你需要包含lib/assets/library_name目录下的JQuery库,并且在此目录的app/assets/library_name/index.js文件可作为该目录的清单文件。这个文件能够包含需要文件的有序列表或简单的require_tree指令。

此库也可以通过如下方式被应用清单访问:

         //= requirelibrary_name

这样便于维护并且包含之前先对相关代码进行分组有助于保持代码的清洁。

2.3         资源的链接地址

Sprockets并没有实现任何其他的访问资源的方法,你仍需要使用javascript_include_tag和stylesheet_link_tag标签来包含:

         <%= stylesheet_link_tag “application”,media: “all” %>

         <%= javascript_include_tag “application”%>

若使用了trubolinks gem包(此包在Rails4中默认包含),通过包含’data-turbolinks-track’参数来让turbolinks检查资源是否被更新,若被更新,将资源重新加载到页面中。

         <%= stylesheet_link_tag “application”,media: “all”, “data-turbolinks-track” => true %>

         <%= javascript_include_tag “application”,“data-turbolinks-track” => true %>

同常情况下,可以在视图中,通过如下方式访问public/assets/images目录下的资源文件:

         <%= image_tag “rails.png” %>

请确保资源通道在当前环境中是被开启的,该文件可被Sprockets访问。若public/assets/rails.png文件存在,将可通过web 服务器访问。

同样的,对于包含MD5码的文件哈希请求链接 public/assets/rails-af27b6a414e6da00003503148be9b409.png也是同样的原理。链接中的哈希值如何生成的,请参考生产环境小节内容。

         Sprockets同样过多查看config.assets.paths来获取应用的标准路径以及通过Rails添加的路径。

         若需要,图像可以被包含在子目录中,访问时只需要增加子目录相对路径即可。

                   <%= image_tag “icons/rails.png”%>

         注意:若你正在对资源进行预编译(查看接下来的生产环境小节),资源的链接将找不到资源文件,将会在页面报出异常。此类链接将会为空。因此,小心使用image_tag标签和其他使用用户数据的帮助方法。

2.3.1    CSS 和 ERB

资源通道会自动执行ERB。这意味着若你在CSS文件后缀添加.erb(如application.css.erb),那么帮助方法将可在此文件中使用。

         .class { background-image: url(<%=asset_path ‘image.png’ %>) }

如上的写法,自动生成固定资源引用链接。在此例子中,意味着在资源通道加载路径中存在app/assets/images/image.png的资源。若public/assets目录下已存在该文件的指纹形式,此条路径将被引用。

         若你想使用数据URI形式路径---可以通过在CSS文件中使用asset_data_uri帮助方法来生成。

         #logo { background: url(<%=assert_data_uri ‘logo.png’ %>) }

此种方法,在CSS中插入了正确格式的URI形式路径。

注意,此种方法的使用不能以’-%>’形式闭合标签。

2.3.2    CSS 和 Sass

当使用资源通道后,对于资源路径的生成方法必须重写,并且sass-rails提供-url和-path的帮助函数(Sass中为破折号,Ruby中为下划线),来获取一下资源的类型的路径:图像,字体,视频,音频,JS脚本和样式表。

         image-url(“rails.png”)将变成url(/assets/rails.png)

         image-path(“rails.png”)将变成”/assets/rails.png”

可更通用的使用:

         assert-url(“rails.png”) 将变成url(/assets/rails.png)

         assert-path(“rails.png”) 将变成”/assets/rails.png”

2.3.3    JavaScript/CoffeeScript and ERB

你可为JS脚本文件添加后缀.erb,例如application.js.erb形式。意味着,你将可在此文件中使用asset_path等帮助方法。

         $(‘#logo’).attr({ src: “<%=asset_path(‘logo.png’) %>” });

此种写法,将自动生成资源引用路径。

同样的你可以通过为CoffeeScript文件添加.erb后缀,来使用帮助函数。例如application.js.coffee.erb

         $(‘#logo’).attr src: “<%=asset_path(‘logo.png’) %>”

2.4         清单文件和指令

Sprockets通过清单文件决定哪些资源可以被包含和服务。这些清单文件包含一些指令——用于指示Sprockets生成单个CSS或JS文件的时候需要包含哪些文件。通过这些指令,Sprockets将加载需要的文件,对需要预处理的进行预编译,并将它们连接压缩到一个文件中(如果Rails.application.config.assets.compress是true)。通过只对一个文件提供服务,使得浏览器加载页面的速度更快,更由于压缩后的文件比较小,有助于浏览器快速的下载。

例如,Rails 4应用包含默认的app/assets/javascripts/application.js文件如下所示:

         // …

         //= require jquery

         //= require jquery_ujs

         //= require_tree .

在Javascript文件中,Sprockets包含指令以”//=”开头。如上指令,文件通过require和require_tree指令被包含。require指令告诉Sprockets应该包含哪些文件。在此例中,jquery.js和jquery_ujs.js文件需要放置在可查询的资源路径中。你不必添加额外的文件后缀。当你在.js文件中添加包含指令时,Sprockets假定你需要包含的是一个.js文件。

require_tree指令意思是告诉Sprockets对指定路径中存在的资源文件(包含子目录中的文件)进行包含。这些被搜索的路径必须在清单文件标明。你也可以通过require_directory指令包含单个目录下的所有文件,此指令将不包含子目录文件。

指令的执行顺序是从上至下,但是通过require_tree指令包含的文件是无序的。因此,你不应该依赖于特别的先后顺序来包含资源。若你需要前置某些Javascript脚本文件,应该将这些文件使用require指令首先包含进来。注意:require系列指令可以防止重复包含。

Rails中也创建了app/assets/stylesheets/application.css文件,如下所示:

         /* …

         *= require_self

         *= require_tree

         */

Rails 4项目在创建时若未使用—skip-sprockets参数,将会自动创建app/assets/javascripts/application.js和app/assets/stylesheets/application.css文件。这些文件也可以在后续开启资源通道时添加。

作用于Javascript文件的这些require指令集,同样适用于CSS文件,反之亦然。

在上个例子中,使用了require_self指令,该指令用于使用该指令的文件自身,若该指令多次使用,以最后一次为准。

注意:若你想使用多个Sass文件,你应该使用Sass@import规则替代Sprockets中的这些指令。若使用Sprockets这些指令,在Sass文件定义的变量以及mixins的作用域只限于定义的文件。

         你可以通过在文件中使用@import“*”和@import “**/*”来实现与require_tree等效的结果。详情请查看sass-rails文档(https://github.com/rails/sass-rails#features)。

         你可以根据需要,创建多个清单文件。例如可以创建admin.js和admin.css文件来包含应用中管理员admin所需要的资源文件。

         同样需要特别注意一下清单文件中的顺序。在特别情况下,可以采用明确声明单个资源的先后包含顺序来达到目的。例如,你可以参考下面例子来实现将连接有序的CSS文件。

                                     /*…

                                     *=require reset

                                     *=require layout

                                     *=require chrome

                                     */

2.5         预处理

资源文件的后缀,决定了使用什么引擎来预处理。若默认的Rails配置生成控制器或脚手架,将自动生成CoffeeScript文件和SCSS文件来替代通常的Javascript和CSS文件。之前的例子中的控制器名为“projects”,在该控制器生成时,会自动生成app/assets/javascripts/projects.js.coffee和app/assets/stylesheets/projects.css.scss文件。

在开发模式或资源通道未开启的情况下,若这些资源被请求,将首先通过coffee-script和sass gem包进行预编译成Javascript和CSS文件,然后再传送给浏览器客户端。若在资源通道开启情况,这些资源将会被预处理,并放置到public/assets目录中,通过Rails应用或web服务器提供服务。

可以通过给文件添加不同的后缀名,来获取不同引擎的预处理,对后缀的处理顺序是自右向左。此方法可以在需要使用额外预处理策略时应用。例如app/assets/stylesheets/projects.css.scss.erb的文件,先通过ERB引擎处理,经过SCSS引擎处理,最后以CSS形式资源提供给用户。同理如app/assets/javascripts/projects.js.coffee.erb资源,首先通过ERB引擎预处理,再通过CoffeeScript引擎预处理,最后以JavaScript的形式提供给用户。

请注意这些预处理引擎调用的顺序,对是否能正常执行非常重要。例如对于app/assets/javascripts/projects.js.erb.coffee资源,将首先通过coffeescript引擎来预处理,将不会解析ERB语法,因此将会报错。

3          开发环境

在开发模式下,资源以清单文件中声明时的有序的单个文件来提供服务。

例如清单文件app/assets/Javascripts/application.js

         //= require core

         //= require projects

         //= require tickets

将生成如此的HTML:

         <script src=”/assets/core.js?body=1”></script>

         <script src=”/assets/projects.js?body=1”></script>

         <script src=”/assets/tickets.js?body=1”></script>

此body的参数,为Sprockets需要。

3.1         运行时错误检查

默认情况下,在开发模式中,资源通道将在运行时检查潜在的错误。可以通过如下配置来取消检查:

         config.assets.raise_runtime_errors =false

当raise_runtime_errors被设置为false时,sprockets将不会检测声明资源的依赖性。例如此中情况下:

         如果你在application.css.erb文件中调用logo.png资源,如:

                   #logo { background:url(<%= asset_data_uri ‘logo.png’ %>) }

         那么你在application.css.erb文件中,必须声明logo.png的依赖性,只有这样文件才能被正常预编译成目标资源格式。你可以使用”//= depend_on_asset”来声明:

         //= depend_on_asset “logo.png”

         #logo { background: url(<%=asset_data_uri ‘logo.png’ %>) }

若没有依赖声明,你将会在生产环境中碰到去多奇怪的错误行为,并且很难debug查找。若设置raise_runtime_errors为true,将会在运行时检查依赖性是否正常。

3.2         关闭调试功能

可通过config/environments/development.rb文件来配置关闭调试功能。

         config.assets.debug = false

若关闭调试,Sprockets将对所有的资源文件合并并运行必要的预编译处理。在debug模式关闭情况下,清单文件将生成如下形式:

         <script src=”/assets/application.js”></script>

服务启动后,资源会在第一次请求时被编译并缓存。Sprockets设置了must-revalidate缓存控制HTTP头部标记来减少对于资源的重复访问—在浏览器中会获得304(未修改状态码)的响应。

若资源清单中文件在请求过程中被改变,服务器将会返回新的被编译的资源文件。

Debug模式能够以helper方法方式来使用:

         <%= stylesheet_link_tag “application”,debug: true %>

         <%= javascript_include_tag “application”,debug: true %>

若debug模式已被开启,那么:debug选项会变得冗余了。

在开发环境中,你也能够开启压缩功能,来获取更全的检查,但若需要debug,需要关闭压缩功能。

4          生产环境

在生产环境中,Sprockets采用上文提到过的指纹策略。默认情况下,Rails假定资源已被编译,并已作为静态资源形式提供服务。

在预编译过程工,根据被编译文件的内容自动生成一个MD5码,并在文件写入硬盘前将该码插入到文件名中。这些指纹名称,将通过帮助方法替换掉资源文件清单的引用。

例如:

     <%= stylesheet_link_tag“application” %>

     <%=javascript_include_tag “application” %>

将会生成如下形式:

                  <script src="/assets/application-908e25f4bf641868d8683022a5b62f54.js"></script>

<link href="/assets/application-4dd5b109ee3439da54f5bdfd78a80473.css" media="screen"rel="stylesheet" />

注意:资源通道中的:cache和:concat选项已不再使用,请将sytlesheet_link_tag和javascript_include_tag中的该选项删除。

指纹功能通过config.assets.digest来控制是否开启,该选择的默认只在生产环境中开启。

在默认情况下,config.assets.digest选项不应会改变。若文件中没有指纹码,far-future头部被设置,那么远程客户端将永远无法查找到已改变的文件。

4.1         预编译资源

Rails通过rake任务来编译资源清单和其他文件。

被编译的资源默认写入到config.assets.prefix设定的目录中。默认情况下此目录为assets目录。

你能够在部署的时候,调用rake命令来直接对资源进行预编译处理,直接生成编译后可访问的静态资源。可查看下一节中有关本地编译的详细信息。

这个rake命令如下:

         $ RAILS_ENV=production bin/rakeassets:precompile

Capistrano(>=v2.15.1)包含了同样功能的指令。将如下指令,添加到Capfile文件中:

         load ‘deploy/assets’

此链接的文件夹,为config.assets.prefix指向的shared/assets文件夹。若你已经使用了该文件夹,那么你需要重写部署任务。

在部署过程中,被共享的该文件夹是非常重要的,该文件夹涉及到远程缓存的旧资源文件是否可以正常使用。

默认的资源匹配器包含app/assets文件夹下application.js,application.css和所有的非JS/CSS文件(自动包含所有的图片资源):

         [ Proc.new { |path,fn| fn=~/app\/assets/ && !%w(.js .css).include?(File.extname(path)) },/application.(css|js)$/ ]

注:此匹配器(以及其他的预编译数组(查看后面内容))主要应用于匹配最终编译后的资源文件的名称。这将意味着除了JS/CSS文件外,其他格式的资源将被排除。例如.coffee和.scss格式的文件在被预编译成JS/CSS格式文件后,将被自动排除。

若你有其他的清单文件或单独的样式文件以及JS脚本文件需要被包含,你可以通过config/initializers/assets.rb文件来配置。

         Rails.application.config.assets.precompile+= [‘admin.js’,’admin.css’,’swfObject.js’]

或者通过以下方式来预编译所有资源:

         # config/initializers/assets.rb

         Rails.application.config.assets.precompile<< Proc.new do |path|

                   if path =~ /\.(css|js)\z/

                            full_path =Rails.application.assets.resolve(path).to_path

                            app_assets_path =Rails.root.join(‘app’,’assets’).to_path

                            iffull_path.starts_with? app_assets_path

                                     puts “including assets: “ + full_path

                                     true

                                               else

                                                        puts“excluding assets: “ + full_path

                                                        false

                                               end

                                     end

         注:即使你要添加Sass或CoffeeScript格式的文件到预编译数组中,请确保需要预处理的文件的后缀名为.js或.css。

         通过rake任务,会自动生成包含所有资源文件和指纹的映射文件manifes-md5hash.json。此文件被Rails帮助方法调用,用来避免请求映射到Sprockets。映射文件格式如下:

         {"files":{"application-723d1be6cc741a3aabb1cec24276d681.js":{"logical_path":"application.js","mtime":"2013-07-26T22:55:03-07:00","size":302506,"digest":"723d1be6cc741a3aabb1cec24276d681"},"application-12b3c7dd74d2e9df37e7cbb1efa76a6d.css":{"logical_path":"application.css","mtime":"2013-07-26T22:54:54-07:00","size":1560,"digest":"12b3c7dd74d2e9df37e7cbb1efa76a6d"}}

    映射文件默认保存在config.assets.prefix(默认为/assets)的根目录下。

注:若在生产环境中缺失了某些预编译的文件,将会遇到Sprockets::Helpers::RailsHelper::AssetPaths::AssetNotPrecompiledError错误。

4.1.1  Far-future Expires头部信息

预编译的资源存在于文件系统中,并直接通过web服务器提供服务。默认情况下服务器不会返回far-future头部,因此为了使用指纹的好处,你需要设置服务器来返回far-future头部。

Apache:

# The Expires*directives requires the Apache module

# `mod_expires`to be enabled.

<Location/assets/>

  # Use of ETag is discouraged when Last-Modified ispresent

  Header unset ETag FileETag None

  # RFC says only cache for 1 year

  ExpiresActive On ExpiresDefault "access plus 1year"

</Location>

Nginx:

    location ~ ^/assets/{

  expires 1y;

  add_header Cache-Control public;

 

  add_header ETag "";

  break;

}

4.1.2    GZip压缩

当资源文件被预编译后,Sprockets也创建了gzipped(.gz)格式的资源压缩包。服务器通常以适中的压缩率压缩资源,但资源一旦被预编译,Sprockets将会以最大的压缩率来最大限度的减少资源包的大小。另一个方面,web服务器能够被配置为直接提供资源压缩包,而非未压缩的资源文件。

Nginx开启gzip_static后,可以自动进行压缩:

         location ~^/(assets)/  {

  root /path/to/public;

  gzip_static on; # to serve pre-gzipped version

  expires max;

  add_header Cache-Control public;

}

           若Nginx的核心模块支持压缩并和web服务器一同编译,那么该指令将可用。Ubuntu/Debian系统的包,甚至nginx-light,有已经编译好的模块。否则,你可能需要手动进行编译:

    ./configure –with-http_gzip_static_module

若你通过PhusionPassenger来编译nginx,你需要按照提示选择参数。

可以通过查找Google获取到Apache服务器的健壮性配置参数。

4.2         本地预编译

你可能会因以下原因进行本地预编译:

  • l  你没有生产环境系统上的写入权限。
  • l  同时部署多个服务器,为了避免重复的工作。
  • l  经常为了更新,进行部署,但很少更新资源文件。

本地编译允许你直接提交编译后的文件到代码管理系统中,并正常部署。

注意以下两种情况:

  • l  你不必每次都运行Capistrano的预编译部署任务。
  • l  你必须修改应用中以下两个配置文件。

对于config/environments/development.rb文件,配置如下:

config.assets.prefix=”/dev-assets”

 对于prefix的改变,将使得开发模式中Sprockets生成的资源文件URL会变更并将所有请求传入到Sprockets。该参数在生产环境中仍然设置为/assets目录。若不修改此参数,应用将在开发模式中调用/assets目录中的预编译资源,并且你无法知晓对于资源的变更,直到你重新编译资源为止。

             你要确保在你开发系统上,有必要的压缩引擎。

                   实际中,当你进行本地预编译后,编译后的文件将存在工作目录中,在需要时将编译后的文件提交到源代码版本管理系统中。开发模式仍将运行正常。

4.3         现场编译

在某些环境下,你需要进行现场编译。在现场编译情况下,所有对于资源通道的请求都将交由Sprockets直接处理。

开启现场编译模式:

         config.assets.compile= true

对于开发模式中,首次请求资源文件后,会对资源文件进行编译和缓存,并且帮助方法中可用的清单文件名将添加MD5哈希码。

Sprockets也设置了Cache-Control HTTP头部max-age=31536000。此标记将允许所有存在于浏览器与服务器之间的缓存,有效期限为1年。此方式,将减少请求服务器资源文件的次数;使用本地缓存或中间缓存机制,对于资源的使用,是一个很好的方式。

现场编译,会消耗过多内存,性能会下降,不建议使用。

如在部署应用到系统是,没有预先的Javascript运行环境,可以进行如下配置Gemfile文件:

group :production do

         gem ‘therubyracer’

end

4.4         CDNs

若你的资源通过CDN(内容分发网络)提供给用户,请确保资源缓存将不会永远有效。因为这会导致一些问题。若你已配置config.action_controller.perform_caching=true,Rack::Cache将使用Rails.cache来存储资源。这将导致你的缓存很快被装满。

每个缓存机制都有不同,请根据自身的CDN缓存机制要求,进行配置。你可能会找到很好的平衡方法,或许不能。默认使用nginx,例如,它能很好的提供HTTP缓存服务。

5          自定义通道

5.1         CSS 压缩

比较常使用的一个CSS压缩引擎是YUI。该压缩引擎提供了优化清单文件(http://yui.github.io/yuicompressor/css.html)。可以如下配置开启YUI,但是需要安装有yui-compressorgem包。

         config.assets.css_compressor = :yui

另一个位SASS,需要安装sass-railsgem包。

         config.assets.css_compressor = :sass

5.2         JavaScript 压缩

可用的JS压缩引擎有:closure,:uglifier,:yui,而这些也需要相应的gem包:closure-compiler,uglifier或yui-compressor。

Rails应用的Gemifle中默认包含uglifiergem包。此gem包是使用Ruby对UglifyJS(NodeJS使用的)进行来进一步封装。该压缩引擎会删除代码中的空格和注释,简写局部变量,并做其他一些微小的优化,例如在某些情况下,将if-else语句变为三目运算符。

如下配置,将使用uglifier:

         config.assets.js_compressor = :uglifier

注:若你使用uglifier,你还需要ExecJS的运行环境支持。若你使用的MacOS X或Windows,你需要在系统中安装JS运行环境。

注:Rails4中config.assets.compress初始选项已经不再使用。此选项已经无效。替代的配置选项为config.assets.css_compressor和config.assets.js_compressor。

5.3         使用你自己的压缩引擎

CSS和JavaScript脚本的压缩配置可通过任一对象实现。但该对象必须包含一个名为compress的方法,该方法带有一个参数并返回一个字符串。

         class Transformer

                   def compress(string)

                            do_something_returning_a_string(string)

                   end

         end

开启此功能,需要如此配置application.rb文件:

         config.assets.css_compressor =Transformer.new

5.4         修改资源的路径

Sprockets默认使用的是/assets目录。

可如此自定义:

         config.assets.prefix=”/some_other_path”

如此可以方便对旧版本应用进行升级来支持资源通道或添加新资源。

5.5         X-Sendfile头部

X-Sendfile头部指令会使web服务器忽略来自应用的其他响应,而替代性的直接使用硬盘中的指定文件。该选项默认情况下是关闭着的,若你的服务器支持也可开启。若开启此功能,将会将文件的传输工作转让给web前端服务器,在传输较大文件时候变得更快。详细可以查看send_file方法的具体使用说明。

Apache和nginx都支持该功能,可如下对config/environments/production.rb文件进行配置开启:

         #config.action_dispatch.x_sendfile_header = “X-Sendfile” # for apache

         #config.action_dispatch.x_sendfile_header = ‘X-Accel-Redirect’ # for nginx

注:若你需要对已存在应用进行升级并开启该功能,请确保正确配置了production.rb以及其他环境中有关生产行为的(非application.rb)。

扩展阅读—Apache—---Nginx

6          资源缓存存储

默认情况下,在开发模式和生产模式中将通过Sprockets来缓存资源。可通过如下进行配置:

         config.assets.cache_store =:memory_store

通过如此配置,将设定资源缓存的存储方式以及应用的缓存存储机制。

         config.assets.cache_store =:memory_store, { size: 32.megabytes }

7          添加资源到你的Gem包中

资源也可来自于外部的gem包。

比较典型的例子如jquery-railsgem包,提供了Rails需要的标准的JavaScript库。该gem包包含了一个自Rails::Engine继承来的引擎类。通过继承关系,Rails允许该gem调用资源,并将该引擎的app/assets,lib/assets和vendor/assets目录加入到Sprockets搜索路径中。

8          自定义库或做预编译Gem

由于Sprockets采用Tilt协议的模板接口,你的gem包应该实现该协议。通常你需要实现Tilt::Template子类中的prepare方法和evaluate方法,来初始化你的模板和返回要处理的源。原始的源代码存储在data中。详情请查看Tilt::Template源代码:

         module BangBang

                   class Template <::Tilt::Template

                            def prepare

                                     # Do anyinitialization here

                            end

                            # Adds a “!” tooriginal template

                            def evaluate(scope,locals, &block)

                                     “#{data}”

                            end

                    end

         end

既然已经有模板了,现在来应用该模板:

         Sprockets.register_engine ‘.bang’,BangBang::Template

9          从旧版本升级Rails应用

对于Rails3.0或Rails2.x版本的应用的升级需要注意几个问题。第一个就是将public/目录下的资源文件添加到新的路径中。请查看AssetOrganization获取不同类型文件的正确路径。

第二个是要避免重复的Javascript文件。自从Rails3.1开始,jQuery是默认的Javascript库,该库将自动进行包含,你不必拷贝jquery.js文件到app/assets目录中。

第三个就是确保正确设置各个环境下的配置文件。

在application.rb中:

# 设定资源的版本号,可以通过修改它使得资源全部失效

config.assets.version = '1.0'

# 修改资源路径

# config.assets.prefix = "/assets"

         在development.rb中:

# 资源加载时扩展

config.assets.debug = true

         在production.rb中:

# 设定JS和CSS压缩引擎

# config.assets.js_compressor  =:uglifier

# config.assets.css_compressor = :yui

# 若未预编译,不对资源通道进行回滚

config.assets.compile = false

#对资源URLs进行加密,此设置将会被遗弃。.

config.assets.digest = true

# 添加预编译资源,可以是JS、CSS或其他文件。

# config.assets.precompile += %w( search.js )

         Rails4不再在test.rb中设置Sprockets的配置信息。因此test.rb现在需要进行配置Sprockets。在老版本中的测试环境的默认配置指令为:config.assets.compile=true,config.assets.compress=false,config.assets.debug=false和config.assets.digest=false。

         下面的gem包也需要被添加:

                   gem‘sass-rails’, “~> 3.2.3”

                   gem‘coffee-rails’, “~> 3.2.1”

                   gem ‘uglifier’
0 0