2022年の1月31日、Remixの最新バージョン1.12.0が公開された。
この新しいアップデートにおいて、大きな目玉となっているのが新しい開発用サーバーである。
これは今までRemixが取っていたアプローチである、Remix App Server以外のサーバーに対する開発環境下での抽象化させすぎない戦略に対する新たな試みとして実装されている。
ただ、日本語の記事などではあまり大きく取り上げられていないため、今回その新しい開発用サーバーについて少し解説を行ってみる。
Remixの開発チームのコンテキストを理解していないと、リリースノートをかいつまんでは理解できない内容になっているため、解釈の相違がある場合があります。間違い等があればコメント欄で指摘していただけると修正致しますので、ご指摘等よろしくお願いいたします。
読み進める前に知っておいてほしいremix CLIのコマンド三選
今回導入された新しいアプローチが、そもそも採用されるに至った経緯には、今までのremix CLIが抱えていた問題点によるものだった。
そのため、読み進める前に、具体的に3つのコマンドについて改めて内容を確認してほしい。
remix watch
コマンド
アプリケーションファイルの変更を監視する。変更があればビルドを行い、buildディレクトリにindex.jsを生成する。
remix dev
コマンド
remix watch
コマンドの内容に加えて、Remix App Serverを起動する点が異なる。
これによりターミナルでURLが出力されるので、ブラウザからアプリにアクセスできるようになる。
...
[0] Rebuilding...
[1] 💿 Built in 208ms
[1] Remix App Server started at http://192.168.xx.x:3000
[0] Done in 111ms.
[1] GET / 200 - - 41.823 ms
remix-serve
パッケージ
remix-serve
パッケージは、Remixアプリを実行するために必要な設定が施されたexpressアプリケーションを作成する。
そして、この内容はremix CLIに統合されているので、remix watch
によって起動されたウォッチャーとremix-serve
によって実行されるexpressサーバーを同じプロセスで実行することができるようになっている。
これは、nodemon
やwrangler
を使って独自のサーバーを起動させたくない開発者のために用意されたものだ。
今までの問題点
remix CLIでは、remix dev
コマンドが組み込まれている。
これを使うことで、remix watch
を実行しつつ、Remix App Serverを立ち上げることができるようになっている。
Remix App Server以外のサーバーを実行したい場合はremix dev
コマンドを使うことができない。
ではどのように今まではしていたのかというと、remix watch
コマンドを実行してファイルを吐き出させて、自分の使用したいサーバーに合わせてwrangler
やnodemon
を実行してサーバーを起動させる方法を実践していた。
remix watch
コマンドによってファイルの変更が監視されているので、再ビルドされたときは<LiveReload>
がWebソケットを通じて、ブラウザにリロードするように伝えるようになっている。
上記の内容を読んでも分かる通り、今までのremix dev
コマンドは、内蔵されているRemix App Serverとの関係性から、Remix App Server以外のサーバーで開発を行う場合に制限が発生していた。
もちろん自前のRemix App ServerをRemixが所有しているのは大きなメリットなのだが、wrangler
やnodemon
といったツールを使用して開発用のサーバーを起動したい場合にはそうはいかない。
Remix App Server以外のサーバーを使いたい場合は、remix watch
と同時にwrangler dev
やnodemon server.js
を実行する必要があった。
しかし、これの問題点としてwrangler
やnodemon
を使って起動したサーバーがサーバー用のコードをリブートしたかどうかをRemixが知る術は存在しなかった。
そして、remix dev
でも問題点があり、今まではサーバー自体のリブートは行わず、Node.jsのrequire
のキャッシュを削除するのみにとどめていた。
これらの問題点が組み合わされることにより、開発環境では大きく分けて4つの問題が浮上していた。
1. 再ビルドによるPrismaの接続数枯渇問題
キャッシュがクリアされてしまうので、DB接続やメモリ内の参照はもちろん削除される。そのため、再ビルドされるたびにPrismaを使って新しい接続をおこなってしまうため、最終的に接続数が足りなくなるという問題が発生していた。
これを回避するためには、キャッシュのクリア前に接続していたという状態を維持させておくためにglobal
を使って__db
フラグを設定するなど、少々トリッキーな回避策を自前で用意する必要があった。
この問題への具体的な実装方法については、こちらのチュートリアルでも言及されている。
2. Webソケットのポート番号指定問題
<LiveReload>
に使用するWebソケットのポートをremix watch
と別のプロセスで起動しているサーバーに対して指定しようとする場合、ものすごく面倒で大変な作業が発生します。
というのも、上記の問題はRemixアプリを2つ同時に開発している場合における問題点である。
wrangler dev --port 3000
やnodemon server.js --port 3001
を実行して立ち上げられたサーバーは2つのプロセスで実行されたアプリであるものの、オプションを経由してポート番号を指定することができるのでそこまで面倒な操作は発生していない。
しかし、remix watch
を実行する場合は簡単にはいかない。
<LiveReload>
はremix watch
の機能の一部である。
そして<LiveReload>
はWebソケットを使用しているため、当然ポート番号を指定しないといけない。そしてサーバーバンドルであるSSRとクライアントバンドルであるブラウザの両方でそのポート番号を知っておく必要がある。
つまり、remix watch
とwrangler dev
の両方で正しいWebソケットのポート番号を取得しないといけないことを意味しており、今までのremix CLIでは簡単にオプション経由でポート番号をウォッチャーと呼ばれるremix watch
に渡すことは不可能だった。
なので、その都度環境変数を設定するなどして、ウォッチャー側にポート番号を渡す必要があったのである。
これはあまりに面倒であり、開発体験を損なう結果に繋がっていると度々問題点として上がっていた。
3. HMRの動作の一貫性問題
上記の理由から、HMRといった新しい開発機能を、Remix App Serverを含めたすべてのサーバーで一貫して動作するように実装することが困難を極めていた。
4. 再ビルドによるパフォーマンス問題
再ビルドされるたびに、buildディレクトリとpublic/buildディレクトリには、新しいファイルが生成される。
これらの生成されたファイルは開発用として使用しているサーバーがクラッシュするか正しく終了するかしない限り、ずっと残り続けることになる。そしてそのファイル数は数千ファイルにも及ぶため、パフォーマンス問題を引き起こし、デバッグ時に混乱を招くことにつながっていた。
開発用サーバーという新しいアプローチ
上記における問題の解決方法として、v1.12.0から新しい開発用サーバーが実装された。
この新しい開発用サーバーは、次のことを実行する。
- 開発モードでアプリをビルドする
- アプリのファイル変更を監視し、変更のたびに再ビルドを行う
- ブラウザでの再読み込みを行うときは、必ず
nodemon
などで起動したアプリサーバーが準備完了のシグナルを通知するのを待ってから行う - 以前のようなインメモリキャッシュの削除は行われない
- Prismaの接続を維持するための
global
を使ったハックは必要なくなる
具体的なメリットはなんなのかというと、2つのアプリ開発時に発生する両方のプロセスを所有する永続的なサーバーが存在することによって、ブラウザに何かを通知するタイミングを制御できるようになったことが一番のメリットとされている。
そして後述するが、複数のプロセスで起動したアプリの管理で大変だったWebソケットポート番号などをremix.config.jsのfuture
フラグで一元管理できるようになったこともまた大きなメリットのひとつだと言える。
現在開発用サーバーではできないこと
新しく実装された開発用のサーバーはRemix App Server、すなわちremix-serve
とは現時点では連動できない。
これは、Remix App ServerがNODE_ENV=production
としてハードコーディングされてしまっているためだとされている。
しかし、この新しい開発用のサーバーが安定的になった段階でRemix App Serverに対応することが予定されているので安心してよい。
新しい開発用サーバーを試す
この新しい開発用のサーバーは安定版ではないため、注意して使用する必要がある。
まずは、remix.config.jsで、future.unstable_dev
をtrue
に設定する。
module.exports = {
future: {
unstable_dev: true,
},
};
もし、開発用のサーバーのポート番号等を設定しつつ試したい場合はtrue
の代わりにオプションを表すオブジェクトを渡す。
module.exports = {
future: {
unstable_dev: {
// Port to use for the dev server (i.e. the <LiveReload> websocket)
// This can be overridden by a CLI flag: `remix dev --port 3011`
// By default, we will find an empty port and use that
port: 3010,
// Port for running your Remix app server
// This can be overridden by a CLI flag: `remix dev --app-server-port 3021`
// default: `3000`
appServerPort: 3020,
// Path to the Remix request handler in your app server
// Most app servers will route all requests to the Remix request
// handler and will not need this option. If your app server _does_
// route only certain request paths to the Remix request handler, then
// you'll need to set this.
// default: `""`
remixRequestHandlerPath: "/products",
// The number of milliseconds between "readiness" pings to your app server
// When a Remix rebuild finishes, the dev server will ping a special
// endpoint (`__REMIX_ASSETS_MANIFEST`) to check if your app server is
// serving up-to-date routes and assets. You can set this option to tune
// how frequently the dev server polls your app server.
// default: `50`
rebuildPollIntervalMs: 25,
},
},
};
この設定内容は将来的に変更される可能性があるので注意が必要
現段階では、実際に起動するときは2つのコマンドを実行する必要がある。
1つは、remix dev
による新しい開発用のサーバー。
そしてもう一つはnodemon
などによって起動されたアプリ用のサーバー。
# spin up the new dev server
remix dev
# Spin up your app server in parallel.
# This can be done in a separate terminal or with a tool like `concurrently`.
nodemon --watch build/ ./server.js
Remix v1.12.0のまとめ
Remix v1.12.0では、新たに開発用サーバーという試みが導入された。
これは、Remixフレームワークが成長していく過程で発生した<LiveReload>
などにおけるポートの問題などが開発体験を将来的に損なう可能性があったことから、この段階での機能追加に踏み切ったのだと考えられる。
もちろん安定版の機能ではないため、将来的に廃止されるか、もしくは設定方法等が大きく変更される可能性は存在する。
しかし、このような実験的な試みはRemixの開発チームが開発者のための開発体験を向上させながら進化をしていこうという前向きな思いの表れだと考えている。
もし、まだRemixを使っていない読者の方がいたら、ぜひRemixフレームワークを導入していただき、その開発体験の良さを一度味わってほしいと切に願う。
誤訳や解釈の相違がある場合があります。間違い等があればコメント欄で指摘していただけると修正致しますので、ご指摘等よろしくお願いいたします。