Rails3.1アプリの本番サーバにJSのエンジンを入れない方法

rails-3.1 いえーい!っていうわけでついついcoffee scriptを使ったんだけど、ステージング環境のRedhatにデプロイしてみたら、画面上で動くはずのJSが動かない。
見てみるとapplication.jsの中身が

throw Error("ExecJS::RuntimeUnavailable: Could not find a JavaScript runtime. See https://github.com/sstephenson/execjs for a list of available runtimes.\n  (in /home/tengine/sources/tengine_console/app/assets/javascripts/application.js)")

という一行だけ。

https://github.com/sstephenson/execjs を読んでみると、JSのエンジンをインストールしとろか言ってる。
ちょw、RailsサーバにJSのエンジンなんてインストールしたくないんですけど?

ググってみるとそんな情報だらけ。うーん、本番でそんなことしたら怒られる、っていうか僕が怒る。

しょうがないので自力での解決を目指す。

まずは

rake -Tでrake assets:precompile

を見つけたのでやってみた。public/assets以下にちゃんと uglifierによってぐちゃぐちゃに短くなったapplication.jsが作られた。

開発環境でproductionで画面を動かしてみる。ちゃんと動く。でもapplication.jsはとってもキレイ。再生成されてやがる。そんなのしたくないんだってば。public/assets/application.js を返してよ。

ソースコードgrepしてみると、execjs-1.2.9/lib/execjs/runtime.rb の ExecJS.autodetect で例のメッセージを出してやがっている。そいつが呼ばれるのは、なんとexecjs.rbがロードされたときだ。

じゃあロードされないようにすればいい。リリースするパッケージに execjsやcoffee-scriptなどが含まれないように、

bundle install --path vendor/bundle --without development test assets

としてGemfile.lockから再生成させる

vendor/bundleには確かに不要なgemファイルは入らないが、Gemfile.lock には思いっきり書かれている。大丈夫なのか?使われちゃうんじゃないの?
調べてみると、本家にちゃんと書いてあった http://gembundler.com/rationale.html
FAQ: Why Is Bundler Downloading Gems From --without Groups?

デプロイ時に依存するものが変わっちゃって、bundlerの利点がないからだって。
まあ、そういうもんなんだろうね。了解。

じゃあ本番に持っていく必要なgemを全てそろえたパッケージを

bundle package

で作成する。vendor/cacheにdevelop, test, assetsのgemがコピーされる。
どうせ使われないのは分かっているけど、tarで固めてコピーする

で、本番環境で、

bundle install --gemfile ./Gemfile --path ./vendor/bundle --deployment --without development test assets

とかやってセットアップすれば、vendor/bundleにちゃんと使用するものだけが展開される。




前後しちゃったけど、config/environments/production.rbの以下の場所を変更する必要もある。

  # Disable Rails's static asset server (Apache or nginx will already do this)
  config.serve_static_assets = true

  # Compress JavaScripts and CSS
  config.assets.compress = false