自從開始用 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/assets
和 lib/assets
/ vendor/assets
之間的行為要分開。app/assets
是你自己開發的,應該要自動 load。lib 和 vendor 則應該要手掛。
所以如果 image 或 icon-font 放在 lib/assets
& vendor/assets
。開發者要自己在 config/enviorments/production.rb
的 config.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 加入這行
2. 把你維護的 Gem 從 vendor/assets 搬到 app/assets
結論
不過雖然可以解決問題。但是這兩個解決方法只是讓 Rails project 變得更髒而已 -_-。實在非常不爽 sprocket-rails 這個team。如果你長期有在追 compass-rails 與 sprocket-rails 這場戰爭的話,應該會非常非常討厭後者..。