Rails的静态资源管理(二)—— 如何使用 Asset Pipeline

摘要:
在Rails开始使用AssetPipeline之后,建议将静态资源文件放在app/assets文件夹中,并使用Sprockets中间件处理这些文件。通过将以下代码添加到config/application.rb配置文件,可以禁用控制器静态资源文件的生成:config。generatorsdo|g|g.assetsfalseend2静态资源文件的组织应用的assetPlance静态资源文件可以存储在三个位置:app/sets、lib/sets和vendor/assets。如果在第三方代码库中引用了同样由AssetPipeline处理的静态资源文件,则必须使用asset_path等辅助方法重写相关代码。除了标准app/sets/*路径之外,还可以在config/application.rb配置文件中为AssetPipeline添加其他路径。

官方文档: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》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Java集合(五) Set 添加元素百度地图在前端开发中的运用下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

必应词典使用体验及改进建议

必应词典使用体验及改进建议 一、发现的BUG 1、使用PC客户端(版本号3.5.0),因为是第一次使用必应词典,之前一直习惯用有道,有自己的生词本,以xml格式保存,这次希望通过必应词典把有道词典旧有的生词本中的内容同步到必应词典当中来,结果发生了如下的事情: 选择导入 点打开出现弹窗: 我觉得很纳闷:都是xml格式的文件,为什么有道能正确打开并解析...

【转】Win7注册表的使用(更新中)

一、注册表的存储结构和数据类型 1、基本概念:   Windows 7的注册表主要由“键”和“键值”构成,称HKEY为根键(RootKey),SubKey为子键。   键(Key):“位于左侧窗格如同文件夹图标一样的就是键”,类似于我的电脑中的文件夹。   键值(Value):“而在右侧窗格中一行行的选项,就称它为键值”,每个键值都有名称、类型、数据三项信...

Vue项目加载本地的json数据模拟请求后台数据

1. 安装express和axios npm i express --save & npm i axios --save 网速不好的,可以安装淘宝镜像,使用cnpm 2. 在main.js中引入axios,并挂载到全局 import axios from ‘axios’; Vue.prototype.$axios = axios; 3.在项目中st...

pdf.js兼容ie9浏览器及以上版本

本插件不兼容ie8,兼容ie9及以上版本,官网最新的几个版本都不兼容ie9 pdf.js是一款优秀的pdf在线浏览的插件,使用很容易上手,具备打印、下载、关键词查找高亮显示等很多功能 目录结构如下图:  使用: 直接把下载下来的pdf.js放到tomcat下运行,index.html是我写的demo,直接访问这个页面 下图是ie9下运行效果 网盘地址:...

应用性能监控(二)

Zipkin 是一款开源的分布式实时数据追踪系统(Distributed Tracking System),基于 Google Dapper 的论文设计而来,由 Twitter公司开发贡献。其主要功能是聚集来自各个异构系统的实时监控数据,用来追踪微服务架构下的系统延时问题。应用系统需要进行装备(instrument)以向 Zipkin 报告数据。Zipki...

iframe的基本使用及利用nginx解决iframe跨域

一.场景 在前端大屏页面中,用iframe嵌套了手机模拟器,手机模拟器进入某个页面,这个页面调用接口实现单点登录 前端大屏地址:https://域名1:7443/1.html    通过nginx访问的页面 不可以调用成功接口的手机端地址:https://域名1/st_app/zlj_homepage/tourists_ys.html?utype=999...