[Rails] 靜態檔案處理(The AssetPipeline)
keywords: rails
, assets
, public
, static
, manifest
Sprockets
透過 Rails 的 pipeline 可以對檔案(例如,SCSS, CoffeeScript, ERB)進行前處理(pre-process),這些是透過 sprockets-rails
這個 gem 完成的。
Sprockets 會打包(編譯、最小化、壓縮)所有的 .js
, .css
檔案成為一支 .js
和 .css
檔。在開發環境下,所有的檔名都會加入一段 SHA256 的編碼,若檔案沒有變更,則使用 cache 的資料,減少伺服器的負擔;一旦檔案有變更,這個編碼就會改變,以此避免 cache 問題。
# 檔名
global-908e25f4bf641868d8683022a5b62f54.css
設定打包方式
一般來說我們會在 ./config/application.rb
中看到
# ./config/application.rb
require "sprockets/railtie"
我們可以在 ./config/environments/production.rb
中設定要打包的方法:
# ./config/environments/production.rb
# 如果有安裝 sass-rails 這個 gem,則這會預設作為 css_compressor 的社竟
config.assets.js_compressor = :uglifier
config.assets.css_compressor = :sass
assets 建立與管理
這些要打包的檔案會放在 ./app/assets/
這個資料夾中; 如果是其他不需要打包的檔案,則可以放在 ./public
這個資料夾中,這些檔案會被當作靜態檔案(config.public_file_server.enabled = true
)
# ./config/environments/production.rb
# 設定能否以靜態檔案的方式存取 public 中的檔案
config.public_file_server.enabled = true
在開發環境下, Rails 預設會將打包好的檔案放到 ./public/assets
中,接著會以靜態檔案的方式存取,因此在開發環境下,是無法直接透過 server 讀取道 app/assets
中的檔案。
Scaffold
在預設的情況下,當我們使用產生器 (generate)來建立檔案時,例如,建立 ProjectsController
,Rails 會自動在 ./app/assets
產生 JS 檔和 SCSS 檔,這些檔案將可以透過 require_tree
來載入:
# 如果有安裝 coffee-rails 和 sass-rails 的 gem
./app/assets/javascripts/projects.coffee
./app/assets/stylesheets/projects.scss
你也可以在特定的頁面中指定特定要載入的 stylesheets 和 JS 檔,但要留意,當這樣使用時,不要使用 require_tree
,否則同樣的 assets 可能會多次載入:
<%= javascript_include_tag params[:controller] %> or <%= stylesheet_link_tag
params[:controller] %>
當只在特定的頁面載入 JS 或 CSS 時,要留意不要使用
require_tree
,否則同樣的 assets 可能會多次載入。
避免自動產生 JS 和 CSS 檔
如果不希望在使用產生器時自動產生 JS 和 CSS 檔,可以在 application.rb
中設定:
# ./config/application.rb
#
module Passer
class Application < Rails::Application
config.generators do |g|
# g.stylesheets false
# g.javascripts false
g.assets false
end
end
end
Assets 檔案位置
Pipeline assets 的檔案可以放在下面三個位置 app/assets
, lib/assets
或 vendor/assets
:
app/assets
:通常放應用程式自身的檔案,例如自己寫的圖檔、JS 或 CSS。lib/assets
:通常放的是自己寫的函式庫(library),通常不限於在這個應用程式中使用。vendor/assets
:通常放的第三方的函式庫。
當我們透過 manifest(安裝設定檔)或 helper 要使用 asset 檔案時,Sprockets 會從這三個預設的位置搜尋檔案,任何在 assets/*
裡面的檔案都將被搜尋。舉例來說,當 manifest 檔案要載入下述檔案時:
//= require home
//= require moovinator
//= require slider
//= require phonebox
//= require sub/something
require 也可以直接載入 npm(如果有安裝 webpacker)的套件。 安裝的 gem 會自動被 require,不用重複寫(因此不要安裝用不到的 gem)。
下面這些檔案都會被處理:
# 在 app/assets, lib/assets, vendor/assets 裡面的檔案
app/assets/javascripts/home.js
lib/assets/javascripts/moovinator.js
vendor/assets/javascripts/slider.js
vendor/assets/somepackage/phonebox.js
# assets/* 的檔案都可以被處理到
app/assets/javascripts/sub/something.js
# gems/* 的檔案也會自動被 require 到
可以在下面的檔案中,看到會搜尋的路徑有哪些:
# ./config/initializers/assets.rb
Rails.application.config.assets.paths << Rails.root.join('node_modules')
如果不確定有檔案載入的順序或有哪些資料夾被載入,可以
//= require xxx
一個不存在的檔案讓它噴錯,就可以看到載入的路徑:
使用 index 檔名的檔案
Sprockets 會自動以名為 index
的檔案當作 manifest 檔來加載其他檔案,舉例來說,如果你的 jQuery 函式庫包含許多的模組,儲存在 lib/assets/javascripts/library_name
中,則 lib/assets/javascripts/library_name/index.js
這支檔案會被當作 manifest 檔案,並根據它在加載其他檔案。
透過 Helper 使用 Assets 檔案
透過 pipeline 使用的檔案會由 Sprockets 提供;如果是將檔案放在 public/assets/rails.png
則會是由伺服器直接提供:
javascript_include_tag
stylesheet_link_tag
image_tag
asset_path
asset_data_uri
<%= 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" %>
<style>
.class { background-image: url(<%= asset_path 'image.png' %>) }
.logo { background: url(<%= asset_data_uri 'logo.png' %>) }
</style>
asset-url("rails.png") <!-- url(/assets/rails.png) -->
asset-path("rails.png") <!-- "/assets/rails.png" -->