docker-composeでwebpack-dev-serverを使う

docker-composeを使って開発をしているとき、webpack-dev-serverを別サービスとして起動させたくなる。Rails + webpackerの環境でうまく実現できたのでメモを残しておく。

docker-compose.ymlのうちポイントとなる箇所だけ抽出した。

services:
  rails:
    environment:
      WEBPACKER_DEV_SERVER_HOST: webpack-dev-server
    volumes:
      - ./public/packs:/myapp/public/packs
    depends_on:
      - webpack-dev-server
  webpack-dev-server:
    environment:
      WEBPACKER_DEV_SERVER_HOST: 0.0.0.0
    ports:
      - 3035:3035
    volumes:
      - ./public/packs:/myapp/public/packs

webpackerとwebpack-dev-server

webpackerをセットアップするとwebpack-dev-serverもついてくる。そして、config/webpacker.ymlにはwebpack-dev-serverの設定も含まれている。

開発環境において、webpackerはアセットへのリクエスト受信時にwebpackを実行してアセットをコンパイルするが、webpack-dev-serverの起動が確認できればアセットへのリクエストをwebpack-dev-serverに転送するようになっている。

Railsがwebpack-dev-serverに接続する際、config/webpacker.ymlに記載されたhostとportを参照する。ただし、WEBPACKER_DEV_SERVER_*のようなパターンの環境変数を設定することでYAMLファイルの設定を上書きできるようになっており、それを利用しているのが、上のdocker-compose.yml内で指定している環境変数WEBPACKER_DEV_SERVER_HOSTとなる。これでwebpack-dev-serverのhostを設定できる。

このdocker-composeでは、depends_onで設定したサービスのaliasを設定することでRailsからwebpack-dev-serverにアクセスできるようにしている。また、webpack-dev-serverサービスで0.0.0.0を指定しているのは、このコンテナ外からアクセスできるようにするためだ。

マニフェストファイルの共有

Railsがwebpackでコンパイルしたアセットにアクセスする際、マニフェストファイルに記載されたアセットのファイルパスを利用している。マニフェストファイルはコンパイル時に生成されるため、webpack-dev-serverを実行するコンテナでマニフェストファイルが生成されることになる。

そこで、マニフェストファイルが生成されるpublic/packsディレクトリをホストとマウントすることでRailsコンテナからマニフェストファイルを参照できるようにしている。

live reload

webpack-dev-serverはアセットのソースコードが変更されたときにブラウザを自動更新させるlive reloadの機能も備えている。live reloadはwebpack-dev-serverがアセットをコンパイルする際にlive reloadするスクリプトを挿入することで実現している(はず)。そのスクリプトはwebpack-dev-serverを参照するため(ここら辺の詳しい仕組みはちゃんと把握できていない)、3025番でホストとのポートマッピングを行っている。