Node.js での devServer の構築では初手 unjs/get-port-please の導入が便利
業務で複数の devServer を同時に立ち上げたいケースがあり、チーム内で「React.jsプロジェクト(APP_A)を起動してからNext.jsプロジェクト(APP_B)を起動するとNextが気を利かせてくれるが、Nextを起動してからReactだとポートが専有されていてエラーになっていて地味に不便」という声が上がっていた。
かねてから課題ではあったものの、それぞれ実装を進めることから、同時に立ち上げる機会がそこまで多くなくこれまで放置されていた。しかしそうは言っても不便ではあった中、get-port-please の存在を思い出したので試しに導入してみることにした。
結果として、好感触でなかなか良いライブラリだったので本記事で紹介したいと思う。
unjs/get-port-please について
https://github.com/unjs/get-port-please
unjs の名前空間で分かる通り、 Nuxt.js の開発者たちがメンテナンスしているライブラリ群の一つ。その名の通り、available なポートを見つけ出し、その値を number で返すだけのシンプルなライブラリとなっている。
ここには consola なども属しており、とにかく筋が良いライブラリが多い。 このライブラリも例にもれず、「基本的には注文したポートを、埋まっているときは適当なポートで Listen したい」という実に我儘な要望を叶えてくれる。
なお、ここでの「筋が良い」は実装方針やライブラリのアーキテクチャというよりは、解決すべき問題を適切に解決している課題解決能力としての筋の良さとなる
例えば今どきのアプリケーションでは定番になっている、 3000 番で基本的には Listen したいが、埋まっている場合は別のポートでも良いという場合はこのように書く。
import { getPort } from 'get-port-please';
const port = await getPort({
port: 3000,
});
console.log(port); // 3000 or 適当なポートが取得される
また、ランダムな port で Listen したいケースでは、以下のように書く。
import { getPort } from 'get-port-please';
const port = await getRandomPort();
console.log(port); // 適当なポートが取得される
このように考えられる一般的なケースにおいては、ほぼ何も考えることなく実装が可能となっている。現実的なケースを考えるのであれば、以下に少し書き足すのが現実的に見える。
import { getPort, isSafePort } from 'get-port-please';
const PORT = isSafePort(~~(process.env.APP_A_PORT)) ? ~~(process.env.APP_A_PORT) : 3000;
const port = await getPort({
port: PORT,
});
console.log(port);
とはいえこの程度で実現できる。
利用可能チェックのしくみ
非常にシンプルであり、この記事を執筆時点では素朴にポートを専有しようとして、成功したポートを返すだけとなっている。この実際の処理は、 _checkPort にて行われている。
また、システムの既定のポートであったり、 ssh などメジャーな用途で使われるポートは実際のチェック処理の前に弾かれている。これは unsafe-ports.js にて定義されており、 isSafePort 関数並びに isUnsafePort を介してユーザーも利用することができる。
そのため特別な処理をしているわけでもなく、ある程度安心して利用できるはず。
余談
その他使っていて気になったこと。
ポートの取得順序
- 引数
port
で指定したポート - 引数の
ports
で指定したポート - 同じく unjs が管理している fs-memo で読み取れるファイルに書いてあるポート
- ランダムのポート
となっている様子。また、 range の範囲ではシーケンシャルに取得が進むようで、 3000 が埋まっている場合は 3001 のチェックが走る。
終わりに
期待値通り、やりたいことを最小の手数で賢く実現してくれるため非常に感触が良い。
今回はあとから導入することになったが、手元で簡単な Node.js サーバーを建てるときは、今後ははじめから導入しておきたい。