1 Asset Pipeline 是什麼?
asset pipeline 提供了一個框架來連線和縮小或壓縮 JavaScript 和 CSS 資產。它還增加了將這些資產寫入的能力 其他語言和預處理器,如 CoffeeScript、Sass 和 ERB。 它允許您應用程式中的資產自動與資產組合 來自其他寶石。
asset pipeline 由
sprockets-rails gem,
並預設啟用。您可以在建立新應用程式時禁用它
傳遞 --skip-sprockets
選項。
$ rails new appname --skip-sprockets
透過新增 sassc-rails
,Rails 可以輕鬆地與 Sass 一起使用
gem 到你的 Gemfile
,它被鏈輪用於 Sass 編譯:
gem 'sassc-rails'
要設定資產壓縮方法,請設定相應的設定選項
在 production.rb
- config.assets.css_compressor
中為您的 CSS 和
config.assets.js_compressor
用於您的 JavaScript:
config.assets.css_compressor = :yui
config.assets.js_compressor = :uglifier
sassc-rails
gem 會自動用於 CSS 壓縮(如果包含)
在 Gemfile
中並且沒有設定 config.assets.css_compressor
選項。
1.1 主要特點
管道的第一個特點是串聯資產,這可以減少 瀏覽器為呈現網頁而發出的請求數。網路瀏覽器是 他們可以並行發出的請求數量有限,所以更少 請求可能意味著您的應用程式載入速度更快。
Sprockets 將所有 JavaScript 檔案連線成一個主 .js
檔案和所有
CSS 檔案合併為一個主 .css
檔案。正如您將在本指南後面瞭解到的,您
可以自定義此策略以您喜歡的任何方式對檔案進行分組。在生產中,
Rails 在每個檔名中插入一個 SHA256 指紋,以便檔案
由瀏覽器快取。你可以透過改變這個來使快取無效
指紋,每當您更改檔案內容時都會自動發生。
asset pipeline 的第二個功能是資產縮小或壓縮。 對於 CSS 檔案,這是透過刪除空格和註釋來完成的。對於 JavaScript, 可以應用更復雜的過程。您可以從一組內建 選項或指定您自己的選項。
asset pipeline 的第三個特點是它允許透過 高階語言,預編譯到實際資產。支援的 語言包括用於 CSS 的 Sass、用於 JavaScript 的 CoffeeScript 和用於兩者的 ERB 預設。
1.2 什麼是指紋,我為什麼要關心?
指紋識別是一種使檔名依賴於 檔案的內容。當檔案內容改變時,檔名也隨之改變 改變了。對於靜態或很少更改的內容,這提供了一個 判斷一個檔案的兩個版本是否相同的簡單方法 不同的伺服器或部署日期。
當檔名是唯一的並根據其內容時,可以將 HTTP 標頭設定為 鼓勵無處不在的快取(無論是在 CDN、ISP、網路裝置、 或在網路瀏覽器中)以保留自己的內容副本。當內容是 更新,指紋會改變。這將導致遠端客戶端 請求內容的新副本。這通常稱為 cache busting。
Sprockets 用於指紋識別的技術是插入
內容進入名稱,通常在末尾。例如一個 CSS 檔案 global.css
global-908e25f4bf641868d8683022a5b62f54.css
這是Rails asset pipeline 採用的策略。
Rails 的舊策略是將根據日期的查詢字串附加到連結的每個資產 帶有內建的 helper。在原始碼中,生成的程式碼如下所示:
/stylesheets/global.css?1309495796
查詢字串策略有幾個缺點:
-
並非所有快取都能可靠地快取檔名僅不同的內容 查詢引數
Steve Souders 推薦, “...避免使用可快取資源的查詢字串”。他發現在這個 case 5-20% 的請求不會被快取。查詢字串尤其不 與一些 CDN 一起工作以進行快取失效。
-
檔名可以在多伺服器環境中的節點之間更改。
Rails 2.x 中的預設查詢字串是根據修改時間的 檔案。當資產部署到叢集時,不能保證 時間戳將相同,導致使用不同的 values,具體取決於 在哪個伺服器上處理請求。
-
快取失效過多
當每個新版本的程式碼都部署靜態資產時,mtime (最後修改時間)all這些檔案的變化,強制所有遠端 客戶端再次獲取它們,即使這些資產的內容沒有改變。
指紋透過避免查詢字串來解決這些問題,並確保 檔名根據其內容是一致的。
開發和生產預設啟用指紋識別
環境。您可以透過設定在您的設定中啟用或禁用它
config.assets.digest
選項。
更多閱讀:
2 如何使用 Asset Pipeline
在以前的 Rails 版本中,所有資源都位於
public
如 images
、javascripts
和 stylesheets
。隨著資產
管道,這些資產的首選位置現在是 app/assets
目錄。此目錄中的檔案由 Sprockets 中介軟體提供服務。
資產仍然可以放置在 public
層次結構中。 public
下的任何資產
當應用程式或 Web 伺服器將作為靜態檔案提供時
config.public_file_server.enabled
設定為 true。您應該將 app/assets
用於
在提供服務之前必須經過一些預處理的檔案。
在生產中,Rails 預設將這些檔案預編譯為 public/assets
。這
然後,預編譯的副本由 Web 伺服器作為靜態資產提供。檔案
在 app/assets
中,永遠不會直接在生產中提供服務。
2.1 Controller 特定資產
當你生成一個 scaffold 或一個 controller 時,Rails 也會生成一個
層疊樣式表文件(如果 sass-rails
在 Gemfile
中,則為 SCSS 檔案)
對於那個 controller。此外,當生成 scaffold 時,Rails 會生成
檔案 scaffolds.css
(或 scaffolds.scss
如果 sass-rails
在
Gemfile
。)
例如,如果生成一個 ProjectsController
,Rails 也會新增一個新的
檔案位於 app/assets/stylesheets/projects.scss
。預設情況下,這些檔案將是
可以立即使用 require_tree
指令供您的應用程式使用。看
清單檔案和指令 瞭解更多詳情
在 require_tree 上。
您還可以選擇包含 controller 特定的樣式表和 JavaScript 檔案 僅在各自的 controllers 中使用以下內容:
<%= javascript_include_tag params[:controller] %>
或 <%= stylesheet_link_tag
引數[:controller] %>
執行此操作時,請確保您沒有使用 require_tree
指令,因為
將導致您的資產被多次包含在內。
使用資產預編譯時,您需要確保您的
controller 資產將在按頁載入時進行預編譯。經過
預設的 .coffee
和 .scss
檔案不會自己預編譯。看
預編譯資產 瞭解更多關於如何
預編譯工作。
你必須有一個支援 ExecJS 的執行時才能使用 CoffeeScript。 如果您使用的是 macOS 或 Windows,則您已經安裝了 JavaScript 執行時 你的作業系統。檢查 ExecJS 文件以瞭解所有支援的 JavaScript 執行時。
2.2 資產組織
管道資產可以放置在應用程式中的三個位置之一:
app/assets
、lib/assets
或 vendor/assets
。
app/assets
用於應用程式擁有的資產,例如自定義 影象、JavaScript 檔案或樣式表。lib/assets
用於您自己的庫的程式碼,這些程式碼並不真正適合 應用程式的範圍或那些跨應用程式共享的庫。vendor/assets
用於外部實體擁有的資產,例如 JavaScript 外掛和 CSS 框架的程式碼。請記住,第三方 引用也由資產管道處理的其他檔案的程式碼(影象、 樣式表等),需要重寫以使用 helpers,如asset_path
。
2.2.1 搜尋路徑
當從清單或 helper 引用檔案時,Sprockets 會搜尋 它的三個預設資產位置。
預設位置為:images
、javascripts
和 stylesheets
app/assets
資料夾下的目錄,但這些子目錄
並不特殊 - 將搜尋 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
您可以透過檢查 view 搜尋路徑
Rails.application.config.assets.paths
在 Rails 控制檯中。
除了標準的 assets/*
路徑之外,還可以使用其他(完全限定的)路徑
新增到 config/initializers/assets.rb
中的管道中。例如:
Rails.application.config.assets.paths << Rails.root.join("lib", "videoplayer", "flash")
路徑按照它們在搜尋路徑中出現的順序遍歷。預設情況下,
這意味著 app/assets
中的檔案優先,並將遮蔽
lib
和 vendor
中的對應路徑。
請務必注意,您要在清單之外引用的檔案必須 被新增到預編譯陣列中,否則它們在生產中將不可用 環境。
2.2.2 使用索引檔案
Sprockets 使用名為 index
(帶有相關副檔名)的檔案來實現一個特殊的
目的。
例如,如果您有一個包含許多 modules 的 jQuery 庫,它儲存在
lib/assets/javascripts/library_name
,檔案 lib/assets/javascripts/library_name/index.js
作為
此庫中所有檔案的清單。這個檔案可能包括一個列表
所有必需的檔案,或一個簡單的 require_tree
指令。
可以在應用程式清單中訪問整個庫,如下所示:
//= require library_name
這透過允許相關程式碼來簡化維護並保持清潔 在包含在其他地方之前先分組。
2.3 編碼資產連結
Sprockets 不會新增任何新方法來訪問您的資產——您仍然使用
熟悉的 javascript_include_tag
和 stylesheet_link_tag
:
<%= stylesheet_link_tag "application", media: "all" %>
<%= javascript_include_tag "application" %>
如果使用 Rails 中預設包含的 turbolinks gem,則 包括“data-turbo-track”選項,這會導致 Turbo 檢查是否 資產已更新,如果是,則將其載入到頁面中:
<%= stylesheet_link_tag "application", media: "all", "data-turbo-track" => "reload" %>
<%= javascript_include_tag "application", "data-turbo-track" => "reload" %>
在正常 views 中,您可以訪問 app/assets/images
目錄中的影象
像這樣:
<%= image_tag "rails.png" %>
前提是在您的應用程式中啟用了管道(而不是禁用)
在當前環境上下文中),此檔案由 Sprockets 提供。如果一個檔案
存在於 public/assets/rails.png
它由 Web 伺服器提供服務。
或者,對具有 SHA256 雜湊值的檔案的請求,例如
public/assets/rails-f90d8a84c707a8dc923fca1ca1895ae8ed0a09237f6992015fef1e11be77c023.png
以同樣的方式對待。這些雜湊是如何生成的在 In
Production 部分在本指南的後面部分。
鏈輪還將檢視 config.assets.paths
中指定的路徑,
其中包括標準應用程式路徑和 Rails 新增的任何路徑
引擎。
如果需要,影象也可以組織到子目錄中,然後可以 透過在標籤中指定目錄名稱來訪問:
<%= image_tag "icons/rails.png" %>
如果您正在預編譯您的資產(請參閱 In Production
下面),連結到不存在的資產將在
呼叫頁面。這包括連結到一個空白字串。因此,請小心使用
image_tag
和另一個 helpers 帶有使用者提供的資料。
2.3.1 CSS 和 ERB
asset pipeline 自動評估 ERB。這意味著如果你新增一個
erb
擴充套件到 CSS 資產(例如,application.css.erb
),然後
helpers 和 asset_path
一樣可以在你的 CSS 規則中使用:
.class { background-image: url(<%= asset_path 'image.png' %>) }
這將寫入所引用的特定資產的路徑。在這個例子中,
在資產載入路徑之一中放置影象是有意義的,例如
app/assets/images/image.png
,這裡會引用。如果這張圖片是
已經在 public/assets
中作為指紋檔案可用,那麼該路徑是
參考。
如果您想使用 資料 URI -
一種將影象資料直接嵌入到 CSS 檔案中的方法 - 您可以使用
asset_data_uri
helper。
#logo { 背景: url(<%= asset_data_uri 'logo.png' %>) }
這會將格式正確的資料 URI 插入 CSS 源。
請注意,結束標記不能是 -%>
樣式。
2.3.2 CSS 和 Sass
使用 asset pipeline 時,必須重寫資產路徑並
sass-rails
提供 -url
和 -path
helpers(在 Sass 中連字元,
下劃線為 Ruby)用於以下資產類別:影象、字型、影片、音訊、
JavaScript 和樣式表。
-
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"
2.3.3 JavaScript/CoffeeScript 和 ERB
如果您將 erb
擴充套件新增到 JavaScript 資產,使其成為諸如
application.js.erb
,然後您可以在您的
JavaScript 程式碼:
document.getElementById('logo').src = "<%= asset_path('logo.png') %>"
這將寫入所引用的特定資產的路徑。
2.4 清單檔案和指令
Sprockets 使用清單檔案來確定要包含和提供哪些資產。
這些清單檔案包含 directives - 告訴 Sprockets 的指令
構建單個 CSS 或 JavaScript 檔案需要哪些檔案。和
這些指令,鏈輪載入指定的檔案,如果
必要時,將它們連線成一個檔案,然後壓縮它們
(根據 Rails.application.config.assets.js_compressor
的 value)。透過服務
一個檔案而不是多個檔案,頁面的載入時間可以大大減少,因為
瀏覽器發出更少的請求。壓縮還可以減小檔案大小,使
瀏覽器以更快地下載它們。
例如,一個 app/assets/javascripts/application.js
檔案包含
以下幾行:
// ...
//= require rails-ujs
//= require turbolinks
//= require_tree .
在 JavaScript 檔案中,鏈輪指令以 //=
開頭。在上述情況下,
該檔案正在使用 require
和 require_tree
指令。 require
指令用於告訴鏈輪您希望需要的檔案。這個給你
需要在某處可用的檔案 rails-ujs.js
和 turbolinks.js
在鏈輪的搜尋路徑中。您無需明確提供擴充套件。
當從 .js
內完成時,鏈輪假設您需要一個 .js
檔案
檔案。
require_tree
指令告訴鏈輪遞迴包含 all
將指定目錄中的 JavaScript 檔案放入輸出中。這些路徑必須是
相對於清單檔案指定。您還可以使用
require_directory
指令僅包含所有 JavaScript 檔案
指定的目錄,沒有遞迴。
指令從上到下處理,但檔案的順序
require_tree
包含的內容未指定。你不應該依賴任何特定的
其中的順序。如果您需要確保某些特定的 JavaScript 結束
在連線檔案中的其他檔案之上,首先需要先決條件檔案
在清單中。請注意,require
指令系列阻止檔案
從被包含在輸出中兩次。
Rails 還建立了一個預設的 app/assets/stylesheets/application.css
檔案
其中包含這些行:
/* ...
*= require_self
*= require_tree .
*/
Rails 會建立 app/assets/stylesheets/application.css
,無論
在建立新的 Rails 應用程式時使用 --skip-sprockets
選項。這是
因此,如果您願意,您可以在以後輕鬆新增資產流水線。
適用於 JavaScript 檔案的指令也適用於樣式表
(雖然顯然包括樣式表而不是 JavaScript 檔案)。這
CSS 清單中的 require_tree
指令的工作方式與 JavaScript 相同
一,需要當前目錄中的所有樣式表。
在本例中,使用了 require_self
。這會將 CSS 包含在
檔案(如果有)在 require_self
呼叫的精確位置。
筆記。如果要使用多個Sass檔案,一般應該使用Sass @import
規則
而不是這些鏈輪指令。使用鏈輪指令時,Sass 檔案存在於
它們自己的作用域,使變數或 mixin 僅在定義它們的文件中可用。
您也可以使用 @import "*"
和 @import "**/*"
新增整個樹,這與 require_tree
的工作方式相同,也可以進行檔案通配。檢視 sass-rails 文件 瞭解更多資訊和重要警告。
您可以根據需要擁有任意數量的清單檔案。例如,admin.css
和 admin.js
清單可以包含用於
應用程式的管理部分。
上述關於訂購的說明同樣適用。特別是,您可以指定 單個檔案,它們按指定的順序編譯。例如,你 可以透過這種方式將三個 CSS 檔案連線在一起:
/* ...
*= require reset
*= require layout
*= require chrome
*/
2.5 預處理
資產上使用的副檔名決定了應用什麼預處理。
當使用預設的 Rails gemset 生成 controller 或 scaffold 時,
生成 SCSS 檔案以代替正常 CSS 檔案。之前使用的例子
是一個名為“專案”的 controller,它生成了一個
app/assets/stylesheets/projects.scss
檔案。
在開發模式下,或者如果 asset pipeline 被禁用,當這個檔案被
請求它由 sass-rails
gem 提供的處理器處理,並且
然後作為 CSS 傳送回瀏覽器。當啟用資產流水線時,這
檔案被預處理並放置在 public/assets
目錄中以供服務
Rails 應用程式或 Web 伺服器。
可以透過新增其他擴充套件來請求額外的預處理層,
其中每個擴充套件都以從右到左的方式進行處理。這些應該是
以應用處理的順序使用。例如,一個樣式表
稱為 app/assets/stylesheets/projects.scss.erb
首先作為 ERB 處理,
然後是SCSS,最後擔任CSS。這同樣適用於 JavaScript 檔案 -
app/assets/javascripts/projects.coffee.erb
作為 ERB 處理,然後
CoffeeScript,並充當 JavaScript。
請記住,這些預處理器的順序很重要。例如,如果
你呼叫了你的 JavaScript 檔案 app/assets/javascripts/projects.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>
Sprockets 需要 body
引數。
3.1 未找到資產時引發錯誤
如果您使用 sprockets-rails >= 3.2.0,您可以設定會發生什麼 當執行資產查詢但未找到任何內容時。如果您關閉“資產回退” 那麼當找不到資產時將引發錯誤。
config.assets.unknown_asset_fallback = false
如果啟用了“資產回退”,那麼當找不到資產時,路徑將是 輸出而不是引發錯誤。預設情況下禁用資產回退行為。
3.2 關閉摘要
您可以透過更新 config/environments/development.rb
來關閉摘要
包括:
config.assets.digest = false
當此選項為真時,將為資產 URL 生成摘要。
3.3 關閉除錯
您可以透過更新 config/environments/development.rb
來關閉除錯模式
包括:
config.assets.debug = false
當除錯模式關閉時,鏈輪連線並執行必要的 所有檔案的預處理器。關閉除錯模式後,上面的清單會 改為生成:
<script src="/assets/application.js"></script>
資源在伺服器啟動後的第一個請求時被編譯和快取。
Sprockets 設定一個 must-revalidate
Cache-Control HTTP 頭來減少請求
後續請求的開銷 - 在這些請求上,瀏覽器會收到 304(未修改)
回覆。
如果清單中的任何檔案在請求之間發生了更改,則伺服器 以一個新的編譯檔案回應。
除錯模式也可以在 Rails helper 方法中啟用:
<%= stylesheet_link_tag "application", debug: true %>
<%= javascript_include_tag "application", debug: true %>
如果除錯模式已經開啟,則 :debug
選項是多餘的。
您還可以在開發模式下啟用壓縮作為完整性檢查,並且 根據除錯的需要按需禁用它。
4 生產中
在生產環境中,Sprockets 使用了概述的指紋識別方案 多於。預設情況下,Rails 假定資產已經被預編譯,並且會被 由您的 Web 伺服器用作靜態資產。
在預編譯階段,SHA256 從檔案的內容中生成 編譯檔案,並在寫入磁碟時插入到檔名中。 Rails helpers 使用這些指紋名稱代替清單 名稱。
例如這個:
<%= javascript_include_tag "application" %>
<%= stylesheet_link_tag "application" %>
生成這樣的東西:
<script src="/assets/application-908e25f4bf641868d8683022a5b62f54.js"></script>
<link href="/assets/application-4dd5b109ee3439da54f5bdfd78a80473.css" rel="stylesheet" />
與 Asset Pipeline 不使用 :cache
和 :concat
選項
再從 javascript_include_tag
中刪除這些選項並
stylesheet_link_tag
。
指紋行為由 config.assets.digest
控制
初始化選項(預設為 true
)。
一般情況下預設為 config.assets.digest
選項
不應該改變。如果檔名中沒有摘要,並且在很遠的將來
標頭已設定,遠端客戶端將永遠不會知道重新獲取檔案時
內容變化。
4.1 預編譯資源
Rails 捆綁了一個命令來編譯資產清單和其他 管道中的檔案。
編譯好的資源被寫入到 config.assets.prefix
中指定的位置。
預設情況下,這是 /assets
目錄。
你可以在部署的時候在伺服器上呼叫這個命令來建立編譯好的 直接在伺服器上的資產版本。請參閱下一節 有關本地編譯的資訊。
命令是:
$ RAILS_ENV=production rails assets:precompile
這會將 config.assets.prefix
中指定的資料夾連結到 shared/assets
。
如果您已經使用此共享資料夾,則需要編寫自己的部署
命令。
在部署之間共享此資料夾很重要,以便遠端 引用舊編譯資產的快取頁面在其生命週期內仍然有效 快取的頁面。
編譯檔案的預設匹配器包括 application.js
,
application.css
和所有非 JS/CSS 檔案(這將包括所有影象資產
自動)來自 app/assets
資料夾,包括您的寶石:
[ Proc.new { |filename, path| path =~ /app\/assets/ && !%w(.js .css).include?(File.extname(filename)) },
/application.(css|js)$/ ]
匹配器(和預編譯陣列的其他成員;見下文)是
應用於最終編譯的檔名。這意味著任何編譯為
不包括 JS/CSS,以及原始 JS/CSS 檔案;例如,.coffee
和
.scss
檔案在編譯為 JS/CSS 時不會自動包含在內。
如果您有其他清單或單獨的樣式表和 JavaScript 檔案
包括,您可以將它們新增到 config/initializers/assets.rb
中的 precompile
陣列中:
Rails.application.config.assets.precompile += %w( admin.js admin.css )
筆記。始終指定以 .js
或 .css
結尾的預期編譯檔名,
即使您想將 Sass 或 CoffeeScript 檔案新增到預編譯陣列中。
該命令還會生成一個 .sprockets-manifest-randomhex.json
(其中 randomhex
是
一個 16 位元組的隨機十六進位制字串),其中包含一個列表,其中包含您的所有資產及其各自的資產
指紋。 Rails helper 方法使用它來避免處理
將請求映射回鏈輪。典型的清單檔案如下所示:
{"files":{"application-aee4be71f1288037ae78b997df388332edfd246471b533dcedaa8f9fe156442b.js":{"logical_path":"application.js","mtime":"2016-12-23T20:12:03-05:00","size":412383,
"digest":"aee4be71f1288037ae78b997df388332edfd246471b533dcedaa8f9fe156442b","integrity":"sha256-ruS+cfEogDeueLmX3ziDMu39JGRxtTPc7aqPn+FWRCs="},
"application-86a292b5070793c37e2c0e5f39f73bb387644eaeada7f96e6fc040a028b16c18.css":{"logical_path":"application.css","mtime":"2016-12-23T19:12:20-05:00","size":2994,
"digest":"86a292b5070793c37e2c0e5f39f73bb387644eaeada7f96e6fc040a028b16c18","integrity":"sha256-hqKStQcHk8N+LA5fOfc7s4dkTq6tp/lub8BAoCixbBg="},
"favicon-8d2387b8d4d32cecd93fa3900df0e9ff89d01aacd84f50e780c17c9f6b3d0eda.ico":{"logical_path":"favicon.ico","mtime":"2016-12-23T20:11:00-05:00","size":8629,
"digest":"8d2387b8d4d32cecd93fa3900df0e9ff89d01aacd84f50e780c17c9f6b3d0eda","integrity":"sha256-jSOHuNTTLOzZP6OQDfDp/4nQGqzYT1DngMF8n2s9Dto="},
"my_image-f4028156fd7eca03584d5f2fc0470df1e0dbc7369eaae638b2ff033f988ec493.png":{"logical_path":"my_image.png","mtime":"2016-12-23T20:10:54-05:00","size":23414,
"digest":"f4028156fd7eca03584d5f2fc0470df1e0dbc7369eaae638b2ff033f988ec493","integrity":"sha256-9AKBVv1+ygNYTV8vwEcN8eDbxzaequY4sv8DP5iOxJM="}},
"assets":{"application.js":"application-aee4be71f1288037ae78b997df388332edfd246471b533dcedaa8f9fe156442b.js",
"application.css":"application-86a292b5070793c37e2c0e5f39f73bb387644eaeada7f96e6fc040a028b16c18.css",
"favicon.ico":"favicon-8d2387b8d4d32cecd93fa3900df0e9ff89d01aacd84f50e780c17c9f6b3d0eda.ico",
"my_image.png":"my_image-f4028156fd7eca03584d5f2fc0470df1e0dbc7369eaae638b2ff033f988ec493.png"}}
清單的預設位置是指定位置的根目錄
config.assets.prefix
(預設為“/assets”)。
如果生產中缺少預編譯檔案,您將獲得
Sprockets::Helpers::RailsHelper::AssetPaths::AssetNotPrecompiledError
指示丟失檔名稱的異常。
4.1.1 遠期到期標題
預編譯資產存在於檔案系統中,由您的網站直接提供 伺服器。預設情況下,它們沒有遠未來的標頭,因此要獲得 指紋識別你必須更新你的伺服器設定來新增那些 標題。
對於阿帕奇:
# Expires* 指令需要 Apache module
# `mod_expires` 被啟用。
<Location /assets/>
# Use of ETag is discouraged when Last-Modified is present
Header unset ETag
FileETag None
# RFC says only cache for 1 year
ExpiresActive On
ExpiresDefault "access plus 1 year"
</Location>
對於 NGINX:
location ~ ^/assets/ {
expires 1y;
add_header Cache-Control public;
add_header ETag "";
}
4.2 本地預編譯
有時,您可能不希望或無法在生產中編譯資產 伺服器。例如,您可能對生產的寫訪問許可權有限 檔案系統,或者您可能計劃頻繁部署而不對 你的資產。
在這種情況下,您可以 locally 預編譯資產 — 即新增一個最終確定的 將一組已編譯的、生產就緒的資產新增到您的原始碼儲存庫之前 推向生產。這樣,它們就不需要單獨預編譯 在每次部署時在生產伺服器上。
如上所述,您可以使用執行此步驟
$ RAILS_ENV=production rails assets:precompile
請注意以下注意事項:
-
如果預編譯資產可用,它們將被提供——即使它們沒有 更匹配原始(未編譯)資產,甚至在開發中 伺服器。
確保開發伺服器始終即時編譯資產(和 因此總是反映程式碼的最新狀態),開發 環境必須設定為將預編譯資產儲存在不同的 位置而不是生產。否則,任何預編譯用於 生產將在開發中破壞對它們的請求(即,隨後的 您對資產所做的更改不會反映在瀏覽器中)。
您可以透過將以下行新增到
config/environments/development.rb
:config.assets.prefix = "/dev-assets"
部署工具(e.g., Capistrano)中的資產預編譯任務應該 被禁用。
任何必要的壓縮器或壓縮器必須在您的開發中可用 系統。
4.3 現場編譯
在某些情況下,您可能希望使用實時編譯。在這種模式下所有 對管道中資產的請求由鏈輪直接處理。
要啟用此選項集:
config.assets.compile = true
在第一個請求中,資產被編譯和快取,如 資產 Cache Store,以及 helpers 中使用的清單名稱 被更改為包括 SHA256 雜湊。
Sprockets 還將 Cache-Control
HTTP 標頭設定為 max-age=31536000
。這
向您的伺服器和客戶端瀏覽器之間的所有快取發出訊號,表明此內容
(提供的檔案)可以快取 1 年。這樣做的效果是減少
您的伺服器對此資產的請求數;資產有很好的機會
位於本地瀏覽器快取或某些中間快取中。
這種模式使用更多的記憶體,比預設的效能更差,並且不 受到推崇的。
如果您將生產應用程式部署到沒有任何
預先存在的 JavaScript 執行時,您可能希望向 Gemfile
新增一個:
group :production do
gem 'mini_racer'
end
4.4 CDN
CDN 代表 內容交付 網路,他們是 主要用於快取世界各地的資產,以便當瀏覽器 請求資產,快取副本將在地理上靠近該瀏覽器。 如果您在生產環境中直接從 Rails 伺服器提供資源, 最佳實踐是在您的應用程式前使用 CDN。
使用 CDN 的一種常見模式是將您的生產應用程式設定為
“起源”伺服器。這意味著當瀏覽器從 CDN 請求資產並且
有一個快取未命中,它會從你的伺服器上即時抓取檔案,然後
然後快取它。例如,如果您正在執行 Rails 應用程式
example.com
並在 mycdnsubdomain.fictional-cdn.com
設定了 CDN,
然後當向mycdnsubdomain.fictional-發出請求時
cdn.com/assets/smile.png
,CDN 將在
example.com/assets/smile.png
並快取請求。下一個請求
進入相同 URL 的 CDN 將命中快取副本。當 CDN 可以
直接提供資產請求永遠不會觸及您的 Rails 伺服器。由於
來自 CDN 的資產在地理上更接近瀏覽器,請求是
更快,而且由於您的伺服器不需要花時間為資產提供服務,因此它可以
專注於盡快提供應用程式程式碼。
4.4.1 搭建CDN服務靜態資產
要設定您的 CDN,您必須讓您的應用程式在生產環境中執行
網際網路上公開可用的 URL,例如 example.com
。下一個
您需要從雲託管服務提供商處註冊 CDN 服務。當你
為此,您需要設定 CDN 的“來源”以指向您的
網站 example.com
,請檢查您的提供商以獲取有關設定
源伺服器。
您提供的 CDN 應該為您的應用程式提供自定義子域
例如 mycdnsubdomain.fictional-cdn.com
(注意虛構-cdn.com 不是
在撰寫本文時有效的 CDN 提供商)。現在你已經設定好了
您的 CDN 伺服器,您需要告訴瀏覽器使用您的 CDN 來抓取資產
而不是直接使用 Rails 伺服器。您可以透過將 Rails 設定為
將您的 CDN 設定為資產主機,而不是使用相對路徑。設定您的
在 Rails 中的資產主機,你需要設定 config.asset_host
config/environments/production.rb
:
config.asset_host = 'mycdnsubdomain.fictional-cdn.com'
您只需要提供“主機”,這是子域和根
域,您不需要指定協議或“方案”,例如 http://
或
https://
。當請求網頁時,連結到您的資產的協議
生成的將與預設情況下訪問網頁的方式相匹配。
您還可以透過 [environment] 設定此 value variable](https://en.wikipedia.org/wiki/Environment_variable) 使執行 更輕鬆地暫存網站副本:
config.asset_host = ENV['CDN_HOST']
您需要將伺服器上的 CDN_HOST
設定為 mycdnsubdomain
.fictional-cdn.com
使其工作。
一旦您在提供網頁時設定了伺服器和 CDN 有一項資產:
<%= asset_path('smile.png') %>
而不是返回諸如 /assets/smile.png
之類的路徑(省略了摘要
為了可讀性)。生成的 URL 將包含 CDN 的完整路徑。
http://mycdnsubdomain.fictional-cdn.com/assets/smile.png
如果 CDN 有 smile.png
的副本,它將提供給瀏覽器和您的
伺服器甚至不知道它被請求。如果 CDN 沒有副本
將嘗試在“原點” example.com/assets/smile.png
找到它然後儲存
以備將來使用。
如果您只想提供 CDN 中的某些資產,則可以使用自定義 :host
選擇您的資產 helper,它會覆蓋設定的 value
config.action_controller.asset_host
。
<%= asset_path 'image.png', host: 'mycdnsubdomain.fictional-cdn.com' %>
4.4.2 自定義 CDN 快取行為
CDN 透過快取內容來工作。如果 CDN 有陳舊或壞的內容,那麼它是 傷害而不是幫助您的應用程式。本節的目的是 描述大多數 CDN 的一般快取行為,您的特定提供商可能會 行為略有不同。
4.4.2.1 CDN 請求快取
雖然 CDN 被描述為有利於快取資產,但實際上快取的是
整個請求。這包括資產的主體以及任何標題。這
最重要的一個是 Cache-Control
,它告訴 CDN(和網路瀏覽器)
如何快取內容。這意味著如果有人請求資產
不存在 /assets/i-dont-exist.png
並且您的 Rails 應用程式返回 404,
那麼如果 Cache-Control
標頭有效,那麼您的 CDN 可能會快取 404 頁面
存在。
4.4.2.2 CDN頭除錯
檢查標頭是否正確快取在 CDN 中的一種方法是使用 curl。你 可以從您的伺服器和 CDN 請求標頭以驗證它們是 相同:
$ curl -I http://www.example/assets/application-
d0e099e021c95eb0de3615fd1d8c4d83.css
HTTP/1.1 200 OK
Server: Cowboy
Date: Sun, 24 Aug 2014 20:27:50 GMT
Connection: keep-alive
Last-Modified: Thu, 08 May 2014 01:24:14 GMT
Content-Type: text/css
Cache-Control: public, max-age=2592000
Content-Length: 126560
Via: 1.1 vegur
與 CDN 副本相對。
$ curl -I http://mycdnsubdomain.fictional-cdn.com/application-
d0e099e021c95eb0de3615fd1d8c4d83.css
HTTP/1.1 200 OK Server: Cowboy Last-
Modified: Thu, 08 May 2014 01:24:14 GMT Content-Type: text/css
Cache-Control:
public, max-age=2592000
Via: 1.1 vegur
Content-Length: 126560
Accept-Ranges:
bytes
Date: Sun, 24 Aug 2014 20:28:45 GMT
Via: 1.1 varnish
Age: 885814
Connection: keep-alive
X-Served-By: cache-dfw1828-DFW
X-Cache: HIT
X-Cache-Hits:
68
X-Timer: S1408912125.211638212,VS0,VE0
檢查您的 CDN 文件以瞭解他們可能提供的任何其他資訊
例如 X-Cache
或他們可能新增的任何其他標頭。
4.4.2.3 CDN 和快取控制標頭
快取控制
header 是 W3C
描述如何快取請求的規範。當不使用 CDN 時,一個
瀏覽器將使用此資訊來快取內容。這對
未修改的資產,因此瀏覽器不需要重新下載
每個請求的網站的 CSS 或 JavaScript。通常我們想要我們的 Rails 伺服器
告訴我們的 CDN(和瀏覽器)資產是“公開的”,這意味著任何快取
可以儲存請求。另外我們通常想設定 max-age
是多長時間
快取將在快取失效之前儲存物件。 max-age
value 設定為秒,最大可能 value 的 31536000
是一
年。您可以透過設定在 Rails 應用程式中執行此操作
config.public_file_server.headers = {
'Cache-Control' => 'public, max-age=31536000'
}
現在,當您的應用程式在生產中提供資產時,CDN 將儲存
資產長達一年。由於大多數 CDN 還快取請求的標頭,因此
Cache-Control
將傳遞給未來所有尋求此資產的瀏覽器,
然後瀏覽器知道它可以在很長一段時間之前儲存此資產
需要重新申請。
4.4.2.4 CDN 和根據 URL 的快取失效
大多數 CDN 將根據完整的 URL 快取資產的內容。這意味著 要求
http://mycdnsubdomain.fictional-cdn.com/assets/smile-123.png
將是一個完全不同的快取
http://mycdnsubdomain.fictional-cdn.com/assets/smile.png
如果你想在你的 Cache-Control
中設定遠未來的 max-age
(你這樣做),
然後確保在更改資產時快取無效。為了
例如,將影象中的笑臉從黃色更改為藍色時,您需要
您網站的所有訪問者都可以獲得新的藍臉。使用 CDN 時
Rails asset pipeline config.assets.digest
預設設定為 true 以便
每個資產在更改時將具有不同的檔名。這樣你
不必手動使快取中的任何專案無效。透過使用一個
取而代之的是不同的唯一資產名稱,您的使用者將獲得最新的資產。
5 自定義管道
5.1 CSS 壓縮
壓縮 CSS 的選項之一是 YUI。 YUI CSS 壓縮器 提供 縮小。
以下行啟用 YUI 壓縮,並需要 yui-compressor
寶石。
config.assets.css_compressor = :yui
如果安裝了 sass-rails gem,則壓縮 CSS 的另一個選項是
config.assets.css_compressor = :sass
5.2 JavaScript 壓縮
JavaScript 壓縮的可能選項是 :terser
、:closure
、:uglifier
和
:yui
。這些需要使用 terser
、closure-compiler
、uglifier
或
yui-compressor
寶石,分別。
以 terser
gem 為例。
這個 gem 包裝了 Terser(為
NodeJS) 在 Ruby 中。它透過刪除空格和註釋來壓縮您的程式碼,
縮短區域性變數名稱,並執行其他微最佳化,例如
儘可能將 if
和 else
語句更改為三元運算子。
以下行呼叫 terser
進行 JavaScript 壓縮。
config.assets.js_compressor = :terser
你需要一個 ExecJS
支援執行時以使用 terser
。如果您使用的是 macOS 或
Windows 您的作業系統中安裝了 JavaScript 執行時。
5.3 GZIP 壓縮您的資產
預設情況下,將生成編譯資產的 gzip 版本,以及
資產的非 gzip 版本。壓縮資產有助於減少傳輸
線上的資料。您可以透過設定 gzip
標誌來設定它。
config.assets.gzip = false # disable gzipped assets generation
有關如何提供壓縮資產的說明,請參閱您的 Web 伺服器的文件。
5.4 使用您自己的壓縮機
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.5 改變assets路徑
Sprockets 預設使用的公共路徑是 /assets
。
這可以更改為其他內容:
config.assets.prefix = "/some_other_path"
如果您要更新未使用 asset pipeline 並且已經使用此路徑或您希望將此路徑用於 一種新資源。
5.6 X-Sendfile 標頭
X-Sendfile 標頭是一個指令,讓 Web 伺服器忽略回應 從應用程式,而是從磁碟提供指定的檔案。這個選項 預設情況下是關閉的,但如果您的伺服器支援,可以啟用它。啟用時, 這會將提供檔案的責任傳遞給 Web 伺服器,即 快點。看看 send_file 關於如何使用此功能。
Apache 和 NGINX 支援這個選項,可以在
config/environments/production.rb
:
# config.action_dispatch.x_sendfile_header = "X-Sendfile" # Apache
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # 用於 NGINX
如果您正在升級現有應用程式並打算使用此應用程式
選項,注意僅將此設定選項貼上到 production.rb
中
以及您使用生產行為定義的任何其他環境(不是
application.rb
)。
提示:有關更多詳細資訊,請檢視您的生產網路伺服器的文件: - Apache - NGINX
6 資產快取儲存
預設情況下,鏈輪在開發中快取 tmp/cache/assets
中的資產
和生產環境。這可以更改如下:
config.assets.configure do |env|
env.cache = ActiveSupport::Cache.lookup_store(:memory_store,
{ size: 32.megabytes })
end
要禁用資產快取儲存:
config.assets.configure do |env|
env.cache = ActiveSupport::Cache.lookup_store(:null_store)
end
7 將資產新增到您的 Gems
資產也可以來自寶石形式的外部來源。
jquery-rails
gem 就是一個很好的例子。
這個 gem 包含一個繼承自 Rails::Engine
的引擎類。
透過這樣做,Rails 被告知這個目錄
gem 可能包含資產和 app/assets
、lib/assets
和
該引擎的vendor/assets
目錄被新增到搜尋路徑中
鏈輪。
8 使您的庫或 Gem 成為預處理器
Sprockets 使用處理器、變壓器、壓縮器和匯出器來擴充套件
鏈輪功能。看一下
擴充套件鏈輪
瞭解更多。這裡我們註冊了一個預處理器,在最後添加註釋
文字/css (.css
) 檔案。
module AddComment
def self.call(input)
{ data: input[:data] + "/* Hello From my sprockets extension */" }
end
end
現在你有一個修改輸入資料的 module,是時候註冊了 它作為您的 mime 型別的預處理器。
Sprockets.register_preprocessor 'text/css', AddComment
回饋
我們鼓勵您幫助提高本指南的品質。
如果您發現任何拼寫錯誤或資訊錯誤,請提供回饋。 要開始回饋,您可以閱讀我們的 回饋 部分。
您還可能會發現不完整的內容或不是最新的內容。 請務必為 main 新增任何遺漏的文件。假設是 非穩定版指南(edge guides) 請先驗證問題是否已經在主分支上解決。 請前往 Ruby on Rails 指南寫作準則 查看寫作風格和慣例。
如果由於某種原因您發現要修復的內容但無法自行修補,請您 提出 issue。
關於 Ruby on Rails 的任何類型的討論歡迎提供任何文件至 rubyonrails-docs 討論區。