同一ファイルを動的ローダ経由で複数回読み込むとトップレベル副作用が二重実行されうる。ロード結果を呼び出し側間で共有して回避する
Node.js
CLI
モジュールシステム
知識
判断
CLI ツールなどで、入力ファイル(設定・シナリオ等)を tsx の tsImport や同種の動的モジュールローダで読み込む実装で、別々のコマンドハンドラ(判定用の事前チェックと実行本体など)がそれぞれ独自にロードを呼ぶと、同一ファイルに対してモジュールが二度読み込まれる。
問題の型
動的ローダ(tsx の tsImport など、require/import キャッシュを共有しない方式)は呼び出すたびに新しいモジュール namespace を作ることがある。この場合、モジュールのトップレベルで実行されるコード(定数初期化だけでなく、割られた初期化処理・外部接続の確立・グローバル状態の登録等)が呼び出し回数分都度実行されてしまう。判定用の先読みと実行用の本読みを別々の呼び出しで行うと、判定時の export と実行時の export が異なるインスタンスとして扱われ、副作用の二重実行に気づかないまま進む。
判断基準・対策
- 分岐判定(例: ファイルの種別による事前バリデーション)と実行本体が別関数に分かれていても、入力ファイルの読み込みは 1 回だけ行い、別関数間でその結果(ロードした値・判別結果)を引数で渡して共有する。呼び出し側の別関数がそれぞれ独自にロードし直す実装は避ける。
- この問題は JSON などのプレーンデータフォーマットでは表面化しない(再パースするだけで副作用はない)。TS/JS モジュールのようにトップレベルコードを含む形式で、動的ローダを介して読み込むファイル形式が共存する入力経路で特に起きやすい。
検証方法
対象ファイルのトップレベルにカウンターインクリメントやログ出力を仔込み、判定用呼び出しと実行用呼び出しを両方含むパス(例: 上位コマンドが下位コマンドを呼ぶ構成)を実行して、カウンターが 1 ではなく 2 以上になっていないかを確認する。