webpack-dev-server にRailsアプリケーションからプロキシされない問題を解決する
背景
(時代的にはwebpack離れが進んでいるのですが、誰かの役に立つかもしれないのでメモ)
Rails × Webpackerを使ってアプリケーション開発をする際に、Webpackのコンパイルが遅いと開発効率が落ちてしまいます。
そこで webpack-dev-server を使うと変更があったJavaScriptファイルを自動でコンパイル、リロードをしてくれるので待ち時間が少なく開発を進めることができます。
webpack-dev-serverを使わなくてもWebpackerがオンデマンドでコンパイルしてくれますが、10秒くらいかかっていたので効率が落ちていました。
問題
webpack-dev-server
を起動しているのにも関わらず、Railsアプリケーションからプロキシされず、Webpackerがコンパイルをしてしまうのが問題でした。
コンソールには以下のようなログが出て、オンデマンドでコンパイルしていることがわかります。
[Webpacker] Compiling...
Webpackerのドキュメントには以下のように記載があり、webpack-dev-server
が起動していれば自動的にプロキシを行ってくれると記載がありました。
Once you start this development server, Webpacker will automatically start proxying all webpack asset requests to this server. When you stop the server, it'll revert back to on-demand compilation.
https://github.com/rails/webpacker/tree/5-x-stable#development
環境
- Webpacker: 5.2.1
- webpack-cli: 4.10.0
- webpack-dev-server: 4.9.0
簡単なまとめ
- webpack-dev-serverがどのポートでリッスンしているか確認(設定値ではなく
lsof
コマンド)して、Webpackerの設定と一致しているか確認する - Webpacker v5ではwebpack-dev-server v4に対応していない
- webpack-dev-serverをv3に落とすか、Webpacker v6にバージョンアップする必要あり。
- Webpackerの設定値が適用されていないので、webpack-dev-serverは
localhost:8080
で起動していた。
-
config/webpack/development.js
で設定値を適用することで任意のポートで起動させることができる。
調査の過程
以下、調査したメモを記録
webpack-dev-serverの設定
設定できる項目は以下のドキュメントにまとめられています。
私は環境変数で webpack-dev-server のホストとポートを指定していました。
WEBPACKER_DEV_SERVER_HOST=localhost
WEBPACKER_DEV_SERVER_PORT=3035
この状態で webpack-dev-server
を起動すると localhost:3035
で起動するはずです。
Webpacker がプロキシしているコード
Webpackerのソースコードを確認すると、以下の箇所で webpack-dev-server
にプロキシしていることが分かりました。
ログを仕込んでみると13行目のdev_server.running?
がfalse
を返却していることが分かりました。
dev_server.running?
のソースコードは以下です。
設定したホストとポートに関してTCPで接続して応答があればtrue
を返却しています。
しかし、dev_server.running?
がfalse
ということは設定したlocalhost:3035
の応答がないということが分かりました。
手動で応答を確認
curl
でリクエストを送っても当然のごとく、接続できませんでした。
❯ curl localhost:3035
curl: (7) Failed to connect to localhost port 3035 after 9 ms: Connection refused
lsof
コマンドで確認
今回の調査で初めて知ったのですが、lsof
というどのプロセスがファイルやポートを利用しているか分かるコマンドがあるようです。
❯ lsof -i :3035
何も反応なし。
ログを確認していると 8080 番ポートを利用していることが判明!
webpack-dev-serverのログを確認してみたところ、起動時に以下のようなログがありました。
❯ bin/webpack-dev-server
<i> [webpack-dev-server] Project is running at:
<i> [webpack-dev-server] Loopback: http://localhost:8080/
<i> [webpack-dev-server] On Your Network (IPv4): http://192.168.3.7:8080/
<i> [webpack-dev-server] On Your Network (IPv6): http://[fe80::1]:8080/
<i
おや? http://localhost:8080/
?
もしや 8080 番ポートが使われているのかと思い調べてみたところ、
❯ lsof -i :8080
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
node 69268 yuma.ito 25u IPv6 0x79ce86334b27cdbb 0t0 TCP *:http-alt (LISTEN)
node
のプロセスが使っていることが分かりました!(webpack-dev-serverは内部でexpress.js
を使ってWebサーバを起動しています)
そこで、Railsアプリケーションの起動時にポートを指定してみると、
WEBPACKER_DEV_SERVER_PORT=8080 bundle exec rails server
無事に dev_server.running?
がtrue
を返却し、webpack-dev-serverにプロキシされました!👏
ですが、もともとの設定していた3035番ポートで webpack-dev-server を起動したいです。
環境変数WEBPACKER_DEV_SERVER_PORT=3035
を指定してwebpack-dev-serverを起動したところ、残念なことに8080番ポートで起動しました。
❯ WEBPACKER_DEV_SERVER_PORT=3035 bin/webpack-dev-server
<i> [webpack-dev-server] Project is running at:
<i> [webpack-dev-server] Loopback: http://localhost:8080/
<i> [webpack-dev-server] On Your Network (IPv4): http://192.168.3.7:8080/
<i> [webpack-dev-server] On Your Network (IPv6): http://[fe80::1]:8080/
<i>
bin/webpack-dev-server
コマンドはWebpacker経由で yarn webpack-dev-server
を起動しているのですが、yarn webpack-dev-server
の実行時にはうまくポートの情報が伝わっていない様子。
Webpackerのドキュメントにちゃんと載っているのだが...。
You can use environment variables as options supported by webpack-dev-server in the form WEBPACKER_DEV_SERVER_<OPTION>. Please note that these environmental variables will always take precedence over the ones already set in the configuration file, and that the same environmental variables must be available to the rails server process.
https://github.com/rails/webpacker/tree/5-x-stable#development
Webpackerのソースコードを読み進めると、デフォルトの設定ファイルを見つけた。
ここで3035番ポートで起動するように設定されている。
そして、以下の箇所でWEBPACK_DEV_SERVER
という環境変数をセットするとデフォルトの設定を読み込んでくれるようだ。
実行してみたところ、webpack-cliからwatchOptions
というオプションがないというエラーが発生した。
❯ WEBPACK_DEV_SERVER=true bin/webpack-dev-server
[webpack-cli] Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
- options has an unknown property 'watchOptions'. These properties are valid:
object { allowedHosts?, bonjour?, client?, compress?, devMiddleware?, headers?, historyApiFallback?, host?, hot?, http2?, https?, ipc?, liveReload?, magicHtml?, onAfterSetupMiddleware?, onBeforeSetupMiddleware?, onListening?, open?, port?, proxy?, server?, setupExitSignals?, setupMiddlewares?, static?, watchFiles?, webSocketServer? }
webpack-dev-serverにv4へ移行するための手順が載っており、そこにもwatchOptions
オプションが変更されたことが記載されていた。
(手元の環境では webpack-dev-server: v4.9.0
, webpack-cli: v4.10.0
であった。)
Webpacker v6で解消済みであった
以下のPRで webpack-dev-server v4
への対応が行われていた。
しかし、Webpacker v6のstableバージョンが出る前に開発が終了してしまった。
Webpacker v5では webpack-dev-serverは v3 にしか対応していないと判明
webpack-dev-serverはv3に留めるようなPRがマージされている。
つまり、Webpacker v5と webpack-dev-server v4はデフォルトの設定が反映されない。
解決案
かなり強引だが、下記のようにconfig/webpack/development.js
でdevServer
の設定して対応できそう。
const environment = require('./environment')
+ const devServerConfig = {
+ host: process.env.WEBPACKER_DEV_SERVER_HOST,
+ port: process.env.WEBPACKER_DEV_SERVER_PORT,
+ }
+ environment.config.set('devServer.host', devServerConfig.host)
+ environment.config.set('devServer.port', devServerConfig.port)
module.exports = environment.toWebpackConfig()
実行してみると指定した通りのポートでwebpack-dev-serverが起動した。
❯ WEBPACKER_DEV_SERVER_PORT=3035 bin/webpack-dev-server
<i> [webpack-dev-server] Project is running at:
<i> [webpack-dev-server] Loopback: http://localhost:3035/, http://127.0.0.1:3035/