タイトル通りそういうことをさせたかったのですが、実現に意外にハマったので備忘録的にメモしておきます。
背景
旧 webpack-dev-server では watchContentBase
というオプションがあって、ソースコードだけではなく contentBase、つまり静的ファイルの配信元ディレクトリも監視してファイルが更新されたらブラウザを更新するような設定ができました。これは割と便利なのだけど、我らが webpack-serve には公式にそんなオプションはありません。
かなり初期の issueで必要性が叫ばれていて、アドオンのレシピに追加されています。それが docs/addons/watch-content.config.js です。しかし、Watch content example is brokenなんて issue が立っているように、これは期待通り動かないです。
で、修正しようかなと思ったのだけど、取り急ぎ手元で作ってみたのでここに共有しておくことにしたわけです。
準備
webpackとwebpack-serveで静的なWeb環境を作るを下敷きにして作成する。なので、以下の説明はすべてそれをベースにしていることを断っておきます。
ライブラリのインストール
ファイル監視の chokidar
をインストールする。
npm install chokidar
ファイル監視時にブラウザリロードする処理を実装する
ここでのポイントは、webpack-serve
が利用している webpack-hot-client
の貼った WebSocketのコネクションを利用することです。これによって、WebSocketのポート管理とかクライアントサイドの待ち受け処理などをサボっています。
そのために、middleware.webpack()
の後に作成された hotClient
の server
を利用してメッセージを送信するようにしています。
const path = require("path");
const chokidar = require("chokidar");
const add = (app, middleware, options) => {
middleware.webpack().then(result => {
const server = result.hotClient.server;
const watchPath = path.resolve(__dirname, "public", "*");
const options = { ignoreInitial: true };
watcher = chokidar.watch(watchPath, options);
watcher.on("change", () => {
server.broadcast('{ "type": "window-reload", "data": {} }');
});
});
};
const argv = {};
const options = {
config,
add,
content: "public/",
open: true,
host: "0.0.0.0",
port: 8080
};
serve(argv, options);
これで、開発サーバを起動した後、public/index.html
などを更新すると自動的にリロードが走るようになります。
ファイル名とか見てないので、「今見ているページに関係ある場合だけ更新する」みたいなスマートなことはできないけど、だいたいにおいて期待することはこのレベルである気がする。
window-reload について
webpack-hot-client の以下あたりで定義されている。hot-client のクライアント側ライブラリは、メッセージ window-reload
が届くと window.location.reload()
することがわかる。
今回はリロードのみだからこれにそのまま乗ったけど、もうちょっと細かい挙動の制御がしたければ自前で実装した方がよさそう。