TL;DR; 我不確定有沒有人對這個主題有興趣。不過我承認我是蠻神經病才這樣幹的...
[警告] 這樣作有危險。而且我並不會回答讀者為何你的專案跑不起來的問題。(這是一個超級拼裝車的架構)
起因
我們公司內部的幾個 Project,因為現在一開始都會作 Landing Page,所以 Asset 略顯壅腫。在以往的 Deploy 流程中,我們都是使用 Capistrano 這套工具,策略是到機器上再 compile asset,然後重起整個 project。
這樣的想法是不要卡住 developer 端 deploy 的流暢度。開個新窗放著讓它跑就可以。
只是在機器上 project 越大,compile 越跑越慢。我想我已經是非常會 tune aseet pipeline 的開發者了,但是還是對這樣的情形越來越沒輒。
所以我決定改變策略,改成在本機跑,再 Deploy,測試效率,於是找到這套 Gem https://github.com/spagalloco/capistrano-local-precompile。可以無痛掛上去在本機編完,rsync,再清掉 asset。
Rails 4
在 Rails4 的 project 真的非常有效。因為我的開發機非常的暴力,加上 Rails 4 Sprocket 底層又大改效能提升不少。所以在本機編完效率再 deploy 效率是在遠端環境的非常多倍。
Rails 3
在本機上編和在遠端編速度其實差不多 :/
Pros & Cons
在本機端編,好處是本機機器暴力可以編的很快。但是在遠端編,因為遠端有程式版本可比對,可以做到如果 Asset 不變動,就不重編。
所以這個 Gem 在 Rails 3 的 project 上就顯得十分雞肋。因為如果改到本地端編,若無法十分迅速的編譯,反而會比原先更痛苦...
瘋狂的 Idea :把 Sprocket2 拆到 Rails 3 project 上跑...
Rails 4 用的是 Sprocket2。我已經見識到 Rails 4 編 Asset 是多麼變態了。要是可以拆到 Rails 3 上跑應該會很過癮。
不過這是一個很危險的想法,因為 Asset Pipeline 出了名的...嗯...正常人不會想要去解裡面的問題。(這是一個很長的故事)
當然,我不是第一個有這樣想法的人。很快的我就在網路上找到了這篇 :
https://discussion.heroku.com/t/using-the-rails-4-asset-pipeline-in-rails-3-apps-for-faster-deploys/205
但是這個解法是沒有用的。因為 Sprocket Team 雖然釋出了 backport。但是,在跟 saas-rails 一起跑得時候,不會動....( sass-rails 3.2.6 使用的 resolver,跟 sprocket2 放在一起的時候,resolver 會出錯...)
而這並不是一個 bug。也不能責怪 sass-rails team。(因為...另外一個故事)
總之,要解決這個問題只能靠自己。
解法
我先寫解法,再講過程
焊接方法:
1.(更改 Gemfile 裡面的整組 Asset Gem)
2. 變更 config/enviorments/production.rb
3. 更改 config/deploy.rb
請先掛上 capistrano-local-precompile
這個 Gem 在 deploy 流程裡。
再加掛一個這樣的指令 override 掉 precompile 的參數:
解說
我對這件事情的假設是:sprocket / sass-rails / compass 的三方架構是獨立在 Rails 外的。所以 asset 裡的架構再怎樣變應該都跟 Rails 版本無關。但鎖版本的原因應該是 railtie 版本架構的原因。(長期研究過這三方的架構與恩怨情仇..)
所以理當硬焊可以 work,而不用去改接口 API(因為 Rails 4.0.0 穩定了)。但問題就在於要改哪些參數..
1. 改 sprocket-rails,讓它支援 sprocket 2.2 +
https://github.com/logdown/sprockets-rails/commit/7f6d8d7241ee8f7cff151461d8afe5bd64c6aa92
sprockets-rails
在 gem 'sprockets-rails', '2.0.0.backport1'
這個版本是爛的。但我發現 master 是好的。不過因為 sprocket-rails 只吃 sporocket
2.8 以上版本。所以要欺騙他去吃 sprockets 2.2 的版本。
2. 使用最新版的 sass-rails,但是跑在 rails 3 版本下
https://github.com/logdown/sass-rails/commit/8e23667f86e3b3669835957bb6604ab06eb9256b
sprockets 改動了架構,所以才會在 3.2.6 的 sass-rails 有問題。我「猜」最新版的 sass-rails 應該是沒有問題的,所以硬是把 sass-rails 4.0.1 掛在 Rails 3 下面跑。
3. 更改 compass-rails 的 strategy,讓它誤以為自己跑在 Rails 4 下。
https://github.com/logdown/compass-rails/commit/67779b4f388ff4d56f7683c18c4e24d2ad2ecf78
在上一步的 hack,成功的讓 project 跑起來了,但是新的問題又產生了:只要牽涉到 compass mixin 的地方都會讀不到。根據以前多年與 compass mounting 問題纏鬥的經驗。compass 作者為了對付不負責任的 sprocket 行為,採取的策略是每一個版本寫一個 Resolver Strategy 去應對(因為用 if/else condition 顯然是閃不掉)。
所以我「猜」關鍵點應該也在這,就看要怎麼改。不過運氣好,我猜對了而且也只要改一行就能動。
4. 蓋掉 precompile 參數
本來到了解開 compass-rails 這一步之後,我認為已經完成了。沒想到 deploy 到 production 才是另一個挑戰的開始...
真正的問題在於 Rails 3 與 Rails 4 的編譯行為與機制不同。
在 Rails 3 會有個預設的 asset group
但 Rails 4 取消掉了。
在 Rails 3 設計的原始原因是要在 production 用最小的 gemset 可以編 asset。但是在 Rails4 被拿掉了。任何環境都可以鞭。但問題這台拼裝車要用哪個策略呢?
而在 Rails 4 + Sprocket 2。直接在 local 執行 "bundle exec rake assets:precompile" 是沒問題的,會編出正確的 asset。但是在 Rails 3 + Sprocket 2 是不行的。這個指令只會編出一個「串接」在一起的 asset,無壓縮,也不會針對 webfonts 的 import 特別處理(放在第一行)。
deploy 到遠端就悲劇了。(結果是會出現一個有 debug 訊息、無壓縮且隨意亂合成的 css )
所以要加上這一行...
5. 編輯 config/production.rb 的參數
參數要調過。
到這一步就可以動了。
後續注意事項
https://github.com/rails/sprockets-rails#changes-from-rails-3x
Sprockets 2 架構有不少更改的地方。deploy 上去有一些以前的 import 和 url 的寫法,可能會失效或者 decrapted 掉,所以要自己 debug 閃掉這些地方。
再次強調,這樣焊接是有風險的事。請自行斟酌風險...
特別是這樣的 debug 要 deploy 測試非常多遍。