環境変数 `VITE_PORT` によるPlaywright並列実行のサポート
playwright.config.js と vite.config.js にハードコードされていたポート番号を VITE_PORT 環境変数で上書き可能にしました。これにより、複数のWorktreeで並列にPlaywrightテストを実行できるようになります。
背景
これまでの実装では、テスト用Viteサーバーのポートが 5173 に固定されていたため、複数のWorktreeを同時に使用する場合に深刻な競合が発生していました。具体的には、reuseExistingServer オプションの存在により、後から起動したPlaywrightが既に別のWorktreeで起動済みのViteサーバーをそのまま再利用してしまい、意図しないWorktreeのコードに対してテストが実行されるという問題がありました。
この問題はモノレポやGit Worktreeを活用した並列開発フローで顕在化します。ポート衝突であれば起動エラーとして発見できますが、reuseExistingServer による誤った再利用は気づかないままテストが通過・失敗するため、より厄介な問題です。
技術的な変更
VITE_PORT 環境変数を読み取り、未設定時は従来通り 5173 をデフォルト値として使用するよう、2ファイルを変更しています。
playwright.config.js では、ファイル先頭で vitePort 変数を定義し、baseURL と webServer.url の両方に適用しています。
変更前:
use: {
baseURL: "http://localhost:5173",
...
},
webServer: {
command: `npx vite --config ${import.meta.dirname}/vite.config.js`,
url: "http://localhost:5173",
reuseExistingServer: !isCI,
},
変更後:
const vitePort = process.env.VITE_PORT || "5173"
use: {
baseURL: `http://localhost:${vitePort}`,
...
},
webServer: {
command: `npx vite --config ${import.meta.dirname}/vite.config.js`,
url: `http://localhost:${vitePort}`,
reuseExistingServer: !isCI,
},
vite.config.js では、server.port を parseInt で数値に変換して設定しています。
変更前:
server: {
port: 5173,
strictPort: true,
},
変更後:
server: {
port: parseInt(process.env.VITE_PORT || "5173", 10),
strictPort: true,
},
playwright.config.js 側は文字列テンプレートとして扱うため文字列のまま保持し、Viteの設定ではポート番号として数値が必要なため parseInt で変換している点に注意が必要です。これにより、並列実行は VITE_PORT=5174 yarn test:browser のように起動するだけで実現できます。
設計判断
VITE_PORT という単一の環境変数 で playwright.config.js と vite.config.js の両方を制御する設計が採用されています。
PlaywrightのWebServerブロックはViteプロセスを子プロセスとして起動しますが、その子プロセス側(vite.config.js)も同じ環境変数を参照するため、両者の設定が自動的に同期されます。別々の変数を用意した場合、設定のズレがサイレントな障害を引き起こすリスクがあり、単一変数での制御はその問題を回避する合理的な判断です。
また、strictPort: true はこの変更前から設定されており、指定ポートが使用中の場合は別ポートにフォールバックせず即座にエラーを返します。これにより、意図しないポートでのサーバー起動を防ぎ、reuseExistingServer による誤接続のリスクをさらに低減しています。
まとめ
わずか数行の変更ながら、ハードコードされたポート番号という設定の硬直性が引き起こすWorktree並列運用の問題を根本から解消しています。VITE_PORT という単一の環境変数でPlaywrightとViteの両設定を一貫して制御する設計は、設定の同期ズレによる障害を防ぐシンプルかつ堅牢なアプローチです。