ボクココ

サービス開発を成功させるまでの歩み

Rails 5.1 アプリを Heroku にデプロイする

ども、@kimihom です。 この記事は Heroku Advent Calendar 8日目の記事です。まだ3枠空きがありますので、Heroku ユーザーの方はぜひご登録を!

f:id:cevid_cpp:20170929233715p:plain

Rails 5.1 から Yarn のサポートが入り、フロントエンドの JavaScript ライブラリの管理が容易になった。そこで Rails 5.1 で作った破壊的イノベーションを生むアプリを意気揚々と Heroku へデプロイしようとしたところ、色々詰まったので残しておく。

遭遇した問題と対応

Rails 5.1 の Yarn サポートにより、yarn install を実行しないといけなくなった。 しかし、 Heroku の Ruby ビルドパックに yarn install のコマンド実行が入っていないので、git push した時点で JavaScript パッケージをインストールしてくれない問題が発生した。結果、JavaSciript を読み込むことができず Heroku 側で JavaScript エラーが発生してしまった。

こういう時こそ Release Phase の出番かと思ってやってみたけど、うまくいかず。

色々と調べていると、Node.js のビルドパックを追加する方法があった。具体的には

heroku buildpacks:add --index 1 heroku/nodejs

とすることで、 heroku/ruby の前に nodejs のビルドパックを埋め込んでくれるようだ。ビルドパックを複数指定して、git push heroku master 後にその順番でビルドしてくれる。そうすれば、Node.js のビルドパックには yarn.lock を読み込んで node_modules を生成してくれるので、デプロイがうまくいく。実際に以下のコマンドを叩いてみると、

$ heroku buildpacks
=== my-awesome-app Buildpack URLs
1. heroku/nodejs
2. heroku/ruby

といった感じで複数のビルドパックが入っていることが確認できる。この状態で、git push heroku master をやってやると、Rails ルートにある yarn.lock を読み込んで勝手にライブラリをインストールし始めてくれる。

$ git push heroku master

Counting objects: 7, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (7/7), done.
Writing objects: 100% (7/7), 676 bytes | 0 bytes/s, done.
Total 7 (delta 6), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Node.js app detected
remote:
remote: -----> Creating runtime environment
remote:
remote:        NPM_CONFIG_LOGLEVEL=error
remote:        NPM_CONFIG_PRODUCTION=true
remote:        NODE_VERBOSE=false
remote:        NODE_ENV=production
remote:        NODE_MODULES_CACHE=true
remote:
remote: -----> Installing binaries
remote:        engines.node (package.json):  unspecified
remote:        engines.npm (package.json):   unspecified (use default)
remote:        engines.yarn (package.json):  unspecified (use default)
remote:
remote:        Resolving node version 8.x...
remote:        Downloading and installing node 8.9.1...
remote:        Using default npm version: 5.5.1
remote:        Resolving yarn version 1.x...
remote:        Downloading and installing yarn (1.3.2)...
remote:        Installed yarn 1.3.2
remote:
remote: -----> Restoring cache
remote:        Loading 2 from cacheDirectories (default):
remote:        - node_modules
remote:        - bower_components (not cached - skipping)
remote:
remote: -----> Building dependencies
remote:        Installing node modules (yarn.lock)
remote:        yarn install v1.3.2
remote:        [1/4] Resolving packages...
remote:        success Already up-to-date.
remote:        Done in 0.12s.
remote:
remote: -----> Caching build
remote:        Clearing previous node cache
remote:        Saving 2 cacheDirectories (default):
remote:        - node_modules
remote:        - bower_components (nothing to cache)
remote:
remote: -----> Build succeeded!
remote: -----> Ruby app detected
remote: -----> Compiling Ruby/Rails
remote: -----> Using Ruby version: ruby-2.4.2
remote: -----> Installing dependencies using bundler 1.15.2
remote:        Running: bundle install --without development:test --path vendor/bundle --binstubs vendor/bundle/bin -j4 --deployment
remote:        Warning: the running version of Bundler (1.15.2) is older than the version that created the lockfile (1.16.0). We suggest you upgrade to the latest version of Bundler by running `gem install bundler`.
remote:        Fetching gem metadata from https://rubygems.org/...........
remote:        Fetching version metadata from https://rubygems.org/..
remote:        Fetching dependency metadata from https://rubygems.org/.
remote:        Using rake 12.2.1
remote:        Using concurrent-ruby 1.0.5

... 以下 Ruby のビルドパックの実行

その他の方法

どうやら Webpacker を入れておけば、勝手に Yarn のインストールが走る? そうだ。参照元がどこだか忘れたので、もしかしたら間違ってるかも。

ただ自分は AssetPipeline で普通に Rails のフロントエンドを扱いたかったのでそのために Webpacker の形式に最適化することはしたくなかったので、やっていない。

(余談) Webpacker を入れると、以下のコマンドを実行するわけだけども、

bundle exec rails webpacker:install

てすると

app/javascript:
  ├── packs:
  │   # only webpack entry files here
  │   └── application.js
  └── src:
  │   └── application.css
  └── images:
      └── logo.svg

っていうディレクトリ構成になる。なんかもうこの構成の時点で使いたくなくなるよね。なぜ javascript の中に csssvg が入るのか?そして layouts に <%= javascript_pack_tag 'application' %> という 記載しなければならないもクールじゃないので使用するのを止めた。今後のアップデートに期待、かな。

終わりに

現在、heroku.yml という機能が Developer Preview で公開されていて、今後は heroku.yml でこの問題が対応できるようになりそうだ。これも注目していきたい。

まだまだ Rails のフロントエンドの開拓は進んでる最中なので、色々と躓くところがあるかとは思う。でもYarn をちゃんと使って JavaScript ライブラリの管理ができれば、それはそれで良いに越したことはない。

Heroku は Ruby の最新版をリリースした数時間後に最新版 Ruby のサポートを発表したり、最新の Rails アプリケーションもどんどんサポートしてくれるので、新しい何かを試すのにいいプラットフォームだと思う。

Rails 5.1 以降のフロントエンド周りの発展にも期待していきたい。