sprocketsは面倒だし、babelやwebpackなどの最新JSテクノロジーを使うためにnodejsを使ってassetsを組み立てたいという欲求があると思います。
簡単に解決するなら gulp build
したものをgitリポジトリに追加してしまえばいいのですが、挙動がおかしかった時にバグがあるのか、それともソースがちゃんと git-add できていなくて古いことが原因なのか、とか考える必要が生じて嫌な感じです。できればデプロイ時にビルドしたい。
そういう風な感じでassetsを管理しているRailsアプリをHerokuにデプロイするときに色々ハマったので備忘録としてその方法を書き残します。
忘れずにrails_12factorをbundleする
nodejsは関係無いですが、HerokuでRailsを動かすには必須らしいですね。
gem "rails_12factor", :group => :production
rubyとnodejsのbuildpackを指定する
Herokuでrubyとnodejsが必要なのでbuildpackを2つ指定します。
heroku create --buildpack https://github.com/heroku/heroku-buildpack-ruby.git APP_NAME
heroku buildpacks:add https://github.com/heroku/heroku-buildpack-nodejs.git
昔は1アプリに複数のbuildpackを指定するにはmulti-buildpackを使う必要があったけど、最近は buildpacks:add
するだけで問題無いとのこと。
NPM_CONFIG_PRODUCTION=false
package.jsonで指定したパッケージをインストールして開発を行います。Railsでgulpやらを使う場合、それ自体は開発にしか使わないものなので devDependencies
に入れたくなりますが、そのままだとnodejs buildpackが dependencies
しかインストールしないので上手く行きません。
一つの回避方法は全部 dependencies
に入れてしまうことですが、気持ちが悪いので変わりに NPM_CONFIG_PRODUCTION=false
環境変数を設定します。
heroku config:set NPM_CONFIG_PRODUCTION=false
これで devDependencies
と dependencies
の両方がインストールされるようになります。
postinstallで全てビルドする
nodejs buildpackを使っているとgit-push時に自動的に npm install
が走ります。その後で heroku run gulp build
とすることを考えましたが、ビルド結果が永続化されず参照エラーになりました。heroku run
でファイルを書き出しても消えちゃうんですかね?Heroku弱者なのでよく分かりません。
この問題を回避するには全てを npm install
で生成すればいいということなので postinstall
scriptで全てビルドするようにしました。
{
"scripts": {
"postinstall": "node_modules/.bin/bower install && node_modules/.bin/gulp build"
}
}
bower install
していますが、これだけだと bower_components ディレクトリ以下が永続化されません。
ファイルを吐き出すディレクトリは全て cacheDirectories に追加する
cacheDirectories
に指定していないディレクトリに生成したファイルは npm install
中だろうと消えてしまいます
{
"cacheDirectories": [
"bower_components",
"node_modules"
]
}
まとめ
そういう感じで設定をちゃんとすると、Heroku上でgulpでビルドしたものを使うことができるようになります。