react-rails on Docker Compose (Docker) でムダに苦労した

2 min read読了の目安(約2400字

こんばんは、sasumasa です。

今日は僕がムダに react-rails の導入に苦労してしまったことについて、自戒をこめて書いていきます。

ここに書いてあることはとても基本的なことなのですが「普通こうだろう」と思い込んだ結果時間を思ったより食ったという話です。

駆け出しエンジニアの方などに役に立てれば嬉しいです。

この記事はこんな人に役に立つかも

  1. Docker Compose (Docker) コンテナ内で Rails アプリケーションを起動している
  2. Rails コンテナに react-rails 入れたいけど React コンポーネントがうまくレンダリングされない

結論

  • README の通りにセットアップする
  • package のインストールとか初期ファイルの generate はコンテナ内で行う
  • コンテナ内の変更をホストにも反映させるために Volume を指定する
  • 自動生成された JS をちゃんと View で読み込む

これでだいたい解決するはずです。というかハマる代物ではないはず・・・

React-Rails とは

これです

https://github.com/reactjs/react-rails

Integrate React.js with Rails views and controllers, the asset pipeline, or webpacker. とあるように、React を Rails でいい感じに使うためのものです。

SPA にするのではなく View の一部で React コンポーネントを使う時とかに使うイメージです。

README 通りにセットアップする

webpacker を使っている場合、以下のコマンドを順に実行すると README に書いてあります。

$ bundle install
$ rails webpacker:install
$ rails webpacker:install:react
$ rails generate react:install

Docker でコンテナを立ち上げている場合、上の 3 つ目のコマンド以降はコンテナ内で実行することになると思います(Dockerfile に書いて毎度実行するものではないため)。

そこで docker-compose run ... だったりコンテナ内に入って直接実行するだったりすることになるでしょう。

ホストにも変更を反映させる

コンテナ内で直接実行したコマンドは、例えば react_ujs などの package を作成します。

これらをホストの方にも反映させないと GitHub で実際に利用される package などが同期されなくなります(このことは Gemfile も同じです)。

仮にコンテナで利用している gem や package をちゃんと Git 管理したいのであれば、Docker Compose などの Volume を使ってホストとコンテナどちらからもマウントすることでファイルを同期できるようにしておきましょう。

ちなみに僕の「当たり前」の誤算の 1 つ目はこれでした。コンテナ内のライブラリ・パッケージ管理ファイルがマウントされていなかったのです。

その後設定を変更し、ちゃんとホストのファイルに反映されるようにしました。

自動生成された JS をちゃんと View で読み込む

上のコマンドを実行すると、以下に書いてあるとおり components ディレクトリや ReactRailsUJS のセットアップ、server_rendering.js ファイルが作成されます。

This gives you:
app/javascript/components/ directory for your React components
ReactRailsUJS setup in app/javascript/packs/application.js
app/javascript/packs/server_rendering.js for server-side rendering

ここまできて僕は React をレンダリングできなかったのですが、prerender: true を指定するとレンダリングすることができました。

それもあって「うまく JS ファイルは読み込めているが、他の問題が起きている」と仮説を立ててしまいました。

結論からいうと、実際は ReactRailsUJS のある application.js は読み込めておらず、管理画面用の JS ファイルを読み込んでいたのが原因でした。

prerender: true なら動いた」のは上記の server_rendering.js が packs 直下にあり、管理画面においてもユーザー画面においても読み込まれていたからなのでした。

まとめ

超初歩的なことで時間を食ってしまった自戒を込めて記事を書きました。コンテナ内でうまくライブラリが利用できない時は、以下を疑ってみましょう。

  • README の通りにセットアップしたか?
  • ライブラリのインストールは初期ファイルの generate はコンテナ内で行う必要があるか?
  • コンテナ内の変更をホストにも反映させる必要があるか?そうだとしたらちゃんと Volume を指定しているか?
  • ちゃんとライブラリを読み込めているか?
  • 普通はこうセットアップされているだろう」「こういうコードが書いてあるだろう」と思い込んでいることはないか?

とても簡単にでしたが、雑記をまとめました。