about 10 years ago

自從開始用 Rails4 以後,一直踢到類似的 asset compiling 爛賬。在 development 端是好的,在 production 一壓卻是爛的。但是在 Rails 3 行為卻是好好的。

一直踢到類似的鐵板,很難試出 root cause 是什麼。最近在用別人包的 Gem,覺得再遇到這種狀況會抓狂,於是認真找了 root cause 是什麼。

Asset Pipeline 的邏輯

基本上在

  • app/assets
  • lib/assets
  • vendor/assets

上掛的東西應該都是有效的。上 production 也會壓得過。(在 Rails 3 是成立的,但在 Rails4 變成圖片時常會找不到,然後鬼打牆一直 debug 不出來 )。

經過人工暴力和看熱門的 Gem (如 font-awesome-rails ) 的作法,發現把 assets 搬到 app/assets 是絕對會動。

Root Cause

花了一堆時間找討論串,發現是 https://github.com/rails/rails/pull/7968 (一年前 Josh Peek 的即興 Design)造成的。底下可以看到一堆熱門的 repo 都 ref 了這支可惡的 pull-request。

原因是 Josh 認為 app/assetslib/assets / vendor/assets 之間的行為要分開。app/assets 是你自己開發的,應該要自動 load。lib 和 vendor 則應該要手掛。

所以如果 image 或 icon-font 放在 lib/assets & vendor/assets。開發者要自己在 config/enviorments/production.rbconfig.assets.precompile 下自動一個一個加入想壓的(非 css/js 的 asset) 才可以。

嚴重的問題點:慣例原則

Rails 的 Asset Gem 維護者大多很嚴謹的維持一個原則。把 Asset 儘量都放在 vendor/assets,表示裡面這份 code 他不是原作者。而且這個 Gem 很明顯是 3rd party libraray。

但是依據開發慣例,如果你把 CSS 放在 vendor/assets下面。那麼相關的 images 基本上 100% 也會放在 vendor/assets/images/, vendor/assets/*/images/。基本上你不會吃飽沒事幹,一份放 app/assets,一份放 vendor/assets

那麼 Johs Peek 的這個強迫行為,造成了原始採用 vendor/assets 設計且有非 css / 非 js 的 Gem,在 Rails 4 全部出事。(而且這個 bug 在 Rails 3 沒有)

然後查了這個一年以前的 Deisgn,竟然沒有在 sprocket-rails 官方文件清楚的指出來。( 去送了一個 pull-request 才發現原先的 README 講的非常含糊)。

暴力解決法

1. 在你的 project 加入這行
config/enviorments/production.rb
config.assets.precompile += %w(*.png *.jpg *.jpeg *.gif)
2. 把你維護的 Gem 從 vendor/assets 搬到 app/assets

結論

不過雖然可以解決問題。但是這兩個解決方法只是讓 Rails project 變得更髒而已 -_-。實在非常不爽 sprocket-rails 這個team。如果你長期有在追 compass-rails 與 sprocket-rails 這場戰爭的話,應該會非常非常討厭後者..。

← 再來 3 招實用Asset Pipeline 加速術 由 RailsConf CFP 2014 談客觀的海選辦法 →
 
comments powered by Disqus