官方文档:http://guides.ruby-china.org/asset_pipeline.html

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

在 Rails 的早期版本中,所有静态资源文件都放在 public 文件夹的子文件夹中,例如 imagesjavascripts 和 stylesheets 子文件夹。当 Rails 开始使用 Asset Pipeline 后,就推荐把静态资源文件放在 app/assets 文件夹中,并使用 Sprockets 中间件处理这些文件。

当然,静态资源文件仍然可以放在 public 文件夹及其子文件夹中。只要把 config.public_file_server.enabled 选项设置为 true,Rails 应用或 Web 服务器就会处理 public 文件夹及其子文件夹中的所有静态资源文件。但对于需要预处理的文件,都应该放在 app/assets 文件夹中。

在生产环境中,Rails 默认会对 public/assets 文件夹中的文件进行预处理,经过预处理的静态资源文件将由 Web 服务器直接处理,app/assets 文件夹中的文件不会直接交由 Web 服务器处理。

1 针对控制器的静态资源文件

使用生成器生成控制器时,Rails 会同时为控制器生成以下文件:

  • JavaScript 文件,如果 Gemfile 中包含了 coffee-rails gem,那么生成的是 CoffeeScript 文件
  • CSS 文件,如果 Gemfile 中包含了 sass-rails gem,那么生成的是 SCSS 文件

在生成脚手架时,Rails 还会生成

  • scaffolds.css 文件,如果 Gemfile 中包含了 sass-rails gem,那么生成的是 scaffolds.scss 文件

针对控制器的 JavaScript 文件和 CSS 文件也可以只在相应的控制器中引入:

<%= javascript_include_tag params[:controller] %> 或 <%= stylesheet_link_tag params[:controller] %>

此时,千万不要使用 require_tree 指令,否则就会重复包含这些静态资源文件。

在进行静态资源文件预编译时,请确保针对控制器的静态文件是在按页加载时进行预编译的。默认情况下,Rails 不会自动对 .coffee 和 .scss 文件进行预编译。

要使用 CoffeeScript,就必须安装支持 ExecJS 的运行时。macOS 和 Windows 已经预装了此类运行时。

通过在 config/application.rb 配置文件中添加下述代码,可以禁止生成针对控制器的静态资源文件:

config.generators do |g|
g.assets false
end

2 静态资源文件的组织方式

应用的 Asset Pipeline 静态资源文件可以储存在三个位置:app/assetslib/assets 和 vendor/assets

  • app/assets 用于储存应用自有的静态资源文件,例如自定义图像、JavaScript 文件和 CSS 文件。
  • lib/assets 用于储存自有代码库的静态资源文件,这些代码库或者不适合放在当前应用中,或者需要在多个应用间共享。
  • vendor/assets 用于储存第三方代码库的静态资源文件,例如 JavaScript 插件和 CSS 框架。如果第三方代码库中引用了同样由 Asset Pipeline 处理的静态资源文件(图像、CSS 文件等),就必须使用 asset_path 这样的辅助方法重新编写相关代码。
从 Rails 3 升级而来的用户需要注意,通过设置应用的清单文件, 我们可以包含 lib/assets 和 vendor/assets 文件夹中的静态资源文件,但是这两个文件夹不再是预编译数组的一部分。

2.1 搜索路径

当清单文件或辅助方法引用了静态资源文件时,Sprockets 会在静态资源文件的三个默认存储位置中进行查找。

这三个默认存储位置分别是 app/assets 文件夹的 imagesjavascripts 和 stylesheets 子文件夹,实际上这三个文件夹并没有什么特别之处,所有的 app/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

可以像下面这样进行引用:

//= require sub/something

通过在 Rails 控制台中检查 Rails.application.config.assets.paths 变量,我们可以查看搜索路径。

除了标准的 app/assets/* 路径,还可以在 config/application.rb 配置文件中为 Asset Pipeline 添加其他路径。例如:

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

Rails 会按照路径在搜索路径中出现的先后顺序,对路径进行遍历。因此,在默认情况下,app/assets 中的文件优先级最高,将会遮盖 lib 和 vendor 文件夹中的同名文件。

千万注意,在清单文件之外引用的静态资源文件必须添加到预编译数组中,否则无法在生产环境中使用。

2.2 使用索引文件

对于 Sprockets,名为 index(带有相关扩展名)的文件具有特殊用途。

例如,假设应用中使用的 jQuery 库及多个模块储存在 lib/assets/javascripts/library_name 文件夹中,那么 lib/assets/javascripts/library_name/index.js 文件将作为这个库的清单文件。在这个库的清单文件中,应该按顺序列出所有需要加载的文件,或者干脆使用require_tree 指令。

在应用的清单文件中,可以把这个库作为一个整体加载:

//= require library_name

这样,相关代码总是作为整体在应用中使用,降低了维护成本,并使代码保持简洁。

3 创建指向静态资源文件的链接

Sprockets 没有为访问静态资源文件添加任何新方法,而是继续使用我们熟悉的 javascript_include_tag 和 stylesheet_link_tag 辅助方法:

<%= stylesheet_link_tag "application", media: "all" %>
<%= javascript_include_tag "application" %>

如果使用了 Rails 默认包含的 turbolinks gem,并使用了 data-turbolinks-track 选项,Turbolinks 就会检查静态资源文件是否有更新,如果有更新就加载到页面中:

<%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => "reload" %>
<%= javascript_include_tag "application", "data-turbolinks-track" => "reload" %>

在常规视图中,我们可以像下面这样访问 app/assets/images 文件夹中的图像:

<%= image_tag "rails.png" %>

如果在应用中启用了 Asset Pipeline,并且未在当前环境中禁用 Asset Pipeline,那么这个图像文件将由 Sprockets 处理。如果图像的位置是 public/assets/rails.png,那么将由 Web 服务器处理。

如果文件请求包含 SHA256 哈希值,例如 public/assets/rails-f90d8a84c707a8dc923fca1ca1895ae8ed0a09237f6992015fef1e11be77c023.png,处理的方式也是一样的。

Sprockets 还会检查 config.assets.paths 中指定的路径,其中包括 Rails 应用的标准路径和 Rails 引擎添加的路径。

也可以把图像放在子文件夹中,访问时只需加上子文件夹的名称即可:

<%= image_tag "icons/rails.png" %>

如果对静态资源文件进行了预编译,那么在页面中链接到并不存在的静态资源文件或空字符串将导致该页面抛出异常。因此,在使用 image_tag 等辅助方法处理用户提供的数据时一定要小心。

3.1 CSS 和 ERB

Asset Pipeline 会自动计算 ERB 的值。也就是说,只要给 CSS 文件添加 .erb 扩展名(例如 application.css.erb),就可以在 CSS 规则中使用 asset_path 等辅助方法。

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

上述代码中的 asset_path 辅助方法会返回指向图像真实路径的链接。图像必须位于静态文件加载路径中,例如 app/assets/images/image.png,以便在这里引用。如果在 public/assets 文件夹中已经存在此图像的带指纹的版本,那么将引用这个带指纹的版本。

要想使用 data URI(用于把图像数据直接嵌入 CSS 文件中),可以使用 asset_data_uri 辅助方法:

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

asset_data_uri 辅助方法会把正确格式化后的 data URI 插入 CSS 源代码中。

注意,关闭标签不能使用 -%> 形式。

3.2 CSS 和 Sass

在使用 Asset Pipeline 时,静态资源文件的路径都必须重写,为此 sass-rails gem 提供了 -url 和 -path 系列辅助方法(在 Sass 中使用连字符,在 Ruby 中使用下划线),用于处理图像、字体、视频、音频、JavaScript 和 CSS 等类型的静态资源文件。

  • image-url("rails.png") 会返回 url(/assets/rails.png)
  • image-path("rails.png") 会返回 "/assets/rails.png"

或使用更通用的形式:

  • asset-url("rails.png") 返回 url(/assets/rails.png)
  • asset-path("rails.png") 返回 "/assets/rails.png"

3.3 JavaScript/CoffeeScript 和 ERB

只要给 JavaScript 文件添加 .erb 扩展名(例如 application.js.erb),就可以在 JavaScript 源代码中使用 asset_path 辅助方法:

$('#logo').attr({ src: "<%= asset_path('logo.png') %>" });

上述代码中的 asset_path 辅助方法会返回指向图像真实路径的链接。

同样,只要给 CoffeeScript 文件添加 .erb 扩展名(例如 application.coffee.erb),就可以在 CoffeeScript 源代码中使用 asset_path 辅助方法:

$('#logo').attr src: "<%= asset_path('logo.png') %>"

4 清单文件和指令

Sprockets 使用清单文件来确定需要包含和处理哪些静态资源文件。这些清单文件中的指令会告诉 Sprockets,要想创建 CSS 或 JavaScript 文件需要加载哪些文件。通过这些指令,可以让 Sprockets 加载指定文件,对这些文件进行必要的处理,然后把它们连接为单个文件,最后进行压缩(压缩方式取决于 Rails.application.config.assets.js_compressor 选项的值)。这样在页面中只需处理一个文件而非多个文件,减少了浏览器的请求次数,大大缩短了页面的加载时间。通过压缩还能使文件变小,使浏览器可以更快地下载。

4.1 javascript

在默认情况下,新建 Rails 应用的 app/assets/javascripts/application.js 文件包含下面几行代码:

// ...
//= require jquery
//= require jquery_ujs
//= require_tree .

在 JavaScript 文件中,Sprockets 指令以 //=. 开头。上述代码中使用了 require 和 require_tree 指令。require 指令用于告知 Sprockets 哪些文件需要加载。这里加载的是 Sprockets 搜索路径中的 jquery.js 和 jquery_ujs.js 文件。我们不必显式提供文件的扩展名,因为 Sprockets 假定在 .js 文件中加载的总是 .js 文件。

require_tree 指令告知 Sprockets 以递归方式包含指定文件夹中的所有 JavaScript 文件。在指定文件夹路径时,必须使用相对于清单文件的相对路径。也可以通过 require_directory 指令包含指定文件夹中的所有 JavaScript 文件,此时将不会采取递归方式。

清单文件中的指令是按照从上到下的顺序处理的,但我们无法确定 require_tree 指令包含文件的顺序,因此不应该依赖于这些文件的顺序。如果想要确保连接文件时某些 JavaScript 文件出现在其他 JavaScript 文件之前,可以在清单文件中先行加载这些文件。注意,require 系列指令不会重复加载文件。

4.2 css

在默认情况下,新建 Rails 应用的 app/assets/stylesheets/application.css 文件包含下面几行代码:

/* ...
*= require_self
*= require_tree .
*/

无论新建 Rails 应用时是否使用了 --skip-sprockets 选项,Rails 都会创建 app/assets/javascripts/application.js 和 app/assets/stylesheets/application.css 文件。因此,之后想要使用 Asset Pipeline 非常容易。

我们在 JavaScript 文件中使用的指令同样可以在 CSS 文件中使用,此时加载的是 CSS 文件而不是 JavaScript 文件。在 CSS 清单文件中,require_tree 指令的工作原理和在 JavaScript 清单文件中相同,会加载指定文件夹中的所有 CSS 文件。

上述代码中使用了 require_self 指令,用于把当前文件中的 CSS 代码(如果存在)插入调用这个指令的位置。

要想使用多个 Sass 文件,通常应该使用 Sass @import 规则,而不是 Sprockets 指令。如果使用 Sprockets 指令,这些 Sass 文件将拥有各自的作用域,这样变量和混入只能在定义它们的文件中使用。

和使用 require_tree 指令相比,使用 @import "*" 和 @import "**/*" 的效果完全相同,都能加载指定文件夹中的所有文件。

我们可以根据需要使用多个清单文件。例如,可以用 admin.js 和 admin.css 清单文件分别包含应用管理后台的 JS 和 CSS 文件。

CSS 清单文件中指令的执行顺序类似于前文介绍的 JavaScript 清单文件,尤其是加载的文件都会按照指定顺序依次编译。例如,我们可以像下面这样把 3 个 CSS 文件连接在一起:

/* ...
*= require reset
*= require layout
*= require chrome
*/

5 预处理

静态资源文件的扩展名决定了预处理的方式。在使用默认的 Rails gemset 生成控制器或脚手架时,会生成 CoffeeScript 和 SCSS 文件,而不是普通的 JavaScript 和 CSS 文件。在前文的例子中,生成 projects 控制器时会生成 app/assets/javascripts/projects.coffee和 app/assets/stylesheets/projects.scss 文件。

在开发环境中,或 Asset Pipeline 被禁用时,会使用 coffee-script 和 sass gem 提供的处理器分别处理相应的文件请求,并把生成的 JavaScript 和 CSS 文件发给浏览器。当 Asset Pipeline 可用时,会对这些文件进行预处理,然后储存在 public/assets 文件夹中,由 Rails 应用或 Web 服务器处理。

通过添加其他扩展名,可以对文件进行更多预处理。对扩展名的解析顺序是从右到左,相应的预处理顺序也是从右到左。例如,对于 app/assets/stylesheets/projects.scss.erb 文件,会先处理 ERB,再处理 SCSS,最后作为 CSS 文件处理。同样,对于app/assets/javascripts/projects.coffee.erb 文件,会先处理 ERB,再处理 CoffeeScript,最后作为 JavaScript 文件处理。

记住预处理顺序很重要。例如,如果我们把文件名写为 app/assets/javascripts/projects.erb.coffee,就会先处理 CoffeeScript,这时一旦遇到 ERB 代码就会出错。

Rails的静态资源管理(二)—— 如何使用 Asset Pipeline的更多相关文章

  1. Rails的静态资源管理(六)—— Asset Pipeline缓存存储方式、预处理、升级等

    官方文档:http://guides.ruby-china.org/asset_pipeline.html http://guides.rubyonrails.org/asset_pipeline.h ...

  2. Rails的静态资源管理(一)——Asset Pipeline是什么

    官方文档:http://guides.ruby-china.org/asset_pipeline.html http://guides.rubyonrails.org/asset_pipeline.h ...

  3. Rails的静态资源管理(五)—— 自定义 Asset Pipeline

    官方文档:http://guides.ruby-china.org/asset_pipeline.html http://guides.rubyonrails.org/asset_pipeline.h ...

  4. Rails的静态资源管理(四)—— 生产环境的 Asset Pipeline

    官方文档:http://guides.ruby-china.org/asset_pipeline.html http://guides.rubyonrails.org/asset_pipeline.h ...

  5. Rails的静态资源管理(三)—— 开发环境的Asset Pipelin

    官方文档:http://guides.ruby-china.org/asset_pipeline.html http://guides.rubyonrails.org/asset_pipeline.h ...

  6. Ruby Rails学习中:Sass 和 Asset Pipeline,布局中的链接(Rails路由,具名路由),用户注册: 第一步

    接上篇: 一.Sass 和 Asset Pipeline Rails 中最有用的功能之一是 Asset Pipeline, 它极大地简化了静态资源文件(CSS.JavaScript 和图像)的生成和管 ...

  7. 使用Asset Pipeline管理rails生产环境静态资源实现步骤

    1.    修改项目中指向静态资源文件的链接 a)     访问静态资源文件 <%= stylesheet_link_tag "application", media: &q ...

  8. 已有项目使用Asset Pipeline管理静态资源

    1.    修改项目中指向静态资源文件的链接 a) 访问静态资源文件 <%= stylesheet_link_tag "application", media: " ...

  9. NodeJS中的静态资源管理服务

    欢迎大家指导与讨论 : ) 一.什么是静态资源 静态资源就是放在服务器中的特定的文件.比较常见的有.css,.png, .js的这一些后缀的文件.下图中的这个html页面便要获取到logo.png和a ...

随机推荐

  1. window7 共享wifi(不通过wifi软件)

    1.新建共享网络账号 管理员登录cmd输入:netsh wlan set hostednetwork mode=allow ssid=4Gtest key=12345678 ssid是无线网络名称.k ...

  2. SqlCacheDependency轮询数据库表的更改情况的频率

    下面的示例向 ASP.NET 应用程序添加一个 SqlCacheDependency.   <sqlCacheDependency enabled="true" pollTi ...

  3. 批处理BAT(一)

    批处理 全盘根目录下查找文件夹并删除(1)@echo offfor %%a in (C D E F G H) DO (cd\if exist "%%a:\123\" rd /s / ...

  4. ll 1164 线段树

    http://www.ifrog.cc/acm/problem/1164 1164 - 战舰萝莉 Time Limit:2s Memory Limit:256MByte Submissions:85S ...

  5. C#下利用正则表达式实现字符串搜索功能的方法(转)

    关键字:正则表达式.元字符.字符串.匹配: 1.正则表达式简介:正则表达式提供了功能强大.灵活而又高效的方法来处:.NET框架正则表达式并入了其他正则表达式实现的: 2.字符串搜索:正则表达式语言由两 ...

  6. Object.assign()与深拷贝(一)

    深拷贝与浅拷贝 所谓深拷贝与浅拷贝,是围绕引用类型变量的拷贝进行的讨论. 在ECMAScript中,变量分为基本类型和引用类型两种.其本质区别是不可变性,基本类型是不可变的,而引用类型是可变的. 所谓 ...

  7. js杨辉三角

    function Tree() { this.lines = [ [] ] } var pp = Tree.prototype pp.genNode = function(line, i) { , , ...

  8. JS开发页面小组件:table组件

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  9. jdbc connection为什么放在webINF的lib里面

    jdbc connection为什么放在webINF的lib里面

  10. VI编辑器、ipython、jupyter及进程

    VI编辑器.ipython.jupyter及进程知识总结 https://www.cnblogs.com/thoughtful-actors/p/9650959.html VI编辑器.ipython. ...