Windowsバッチでnpm後のコマンドが実行されない原因とcallの使い方
- 開発環境
- 問題解決
- Windows
Windowsのバッチファイル(.bat)でnpm installの次にnpm run startを書いても、後続コマンドが実行されないことがあります。Windows版npmの実体はnpm.cmdであり、別のバッチ/CMDファイルを呼び出し元へ戻すにはcallが必要です。
@echo off
call npm.cmd install
call npm.cmd run startコマンドプロンプトへ直接入力するときはcallがなくても構いません。必要になるのは、.batまたは.cmdファイルの中から別の.bat/.cmdファイルを実行し、その後も処理を続ける場合です。
npmの後続コマンドが実行されない原因
次のバッチファイルでは、npm installの後に書いた処理が実行されない場合があります。
@echo off
npm install
echo npm installが終了しました
npm run startWindowsでwhere npmを実行すると、環境によってはnpmの実体としてnpm.cmdが見つかります。
where npm.cmdと.batはバッチプログラムです。Microsoft公式のcallコマンド資料では、別のバッチプログラムを親のバッチプログラムを停止せずに呼び出すコマンドとしてcallが説明されています。
呼び出し元のバッチファイルからnpm.cmdをcallなしで実行すると、npm.cmdへ制御が移り、終了後に呼び出し元の次の行へ戻りません。後続処理を実行するにはcallを付けます。
| 実行場所・書き方 | 後続処理 |
|---|---|
コマンドプロンプトでnpm install | 通常どおり入力を続けられる |
バッチ内でnpm install | 呼び出し元へ戻らない場合がある |
バッチ内でcall npm.cmd install | 終了後に次の行へ進む |
call npm.cmdの基本的な書き方
バッチファイル内では、拡張子を含めたnpm.cmdを明示すると、何を呼び出しているか分かりやすくなります。
@echo off
call npm.cmd install
call npm.cmd run build
call npm.cmd run startnpm run startがサーバーなどの常駐プロセスを起動する場合、そのプロセスが終了するまで次の行には進みません。これはcallの不具合ではありません。サーバーを別ウィンドウや別プロセスで起動する必要がある場合は、起動方法を分けます。
初回だけ動かないように見える理由
次のようにnode_modulesの有無でインストールを分岐すると、実行回数によって挙動が変わって見えます。
@echo off
if not exist "node_modules\" npm install
npm run start初回はnode_modulesがないためnpm installが実行されます。callがないと、npm.cmdの終了後に呼び出し元へ戻らず、npm run startへ進みません。
2回目はnode_modulesが存在するため、npm installの行が実行されません。その結果、次のnpm run startへ進みます。この場合は「2回目以降が動かない」のではなく、「初回だけnpm installで処理が終わる」という状態です。
次のように両方へcallを付けます。
@echo off
if not exist "node_modules\" call npm.cmd install
call npm.cmd run startpackage-lock.jsonを使って同じ依存関係を再現する環境では、用途に応じてnpm installではなくnpm ciも検討してください。ただし、起動のたびに依存関係をインストールすると時間がかかり、ネットワーク障害の影響も受けます。本番運用では、配布・更新工程とアプリ起動を分ける方が安定します。
npmの失敗時に処理を止める
callは呼び出し元へ処理を戻しますが、npmが失敗しても自動的にバッチ全体を停止するわけではありません。errorlevelを確認します。
@echo off
if not exist "node_modules\" (
call npm.cmd install
if errorlevel 1 (
echo npm installに失敗しました。
exit /b 1
)
)
call npm.cmd run start
if errorlevel 1 (
echo アプリの起動に失敗しました。
exit /b 1
)if errorlevel 1は、終了コードが1以上の場合に処理します。成功時だけ次へ進めたい場合は、各npmコマンドの直後で確認してください。
npxや別のバッチファイルを呼び出す場合
Windows版のnpxも通常はnpx.cmdです。後続処理がある場合は同じようにcallを付けます。
call npx.cmd astro build
if errorlevel 1 exit /b 1
call npm.cmd run preview自作の.batや.cmdファイルを呼び出す場合も同様です。
call "%~dp0prepare.bat"
if errorlevel 1 exit /b 1
call "%~dp0start-app.cmd"一方、.exeファイルはバッチプログラムではないため、通常はcallを付ける必要がありません。
startとcmd -kを組み合わせる場合
startは別のコマンドプロンプトウィンドウを開くときに使用できます。cmd.exe /kは指定したコマンドの実行後もウィンドウを残し、cmd.exe /cは実行後に終了します。
start "App" "%ComSpec%" /k call "%~dp0_start-app.bat"startの最初の引用符付き引数は、実行ファイルではなくウィンドウタイトルとして扱われます。そのため、上の例では"App"をタイトルとして明示し、その後に"%ComSpec%"を指定しています。
| 指定 | 動作 |
|---|---|
cmd.exe /k | コマンド実行後もウィンドウを残す |
cmd.exe /c | コマンド実行後にウィンドウを終了する |
start "App" ... | Appを新しいウィンドウのタイトルにする |
複雑な処理を別のbatファイルへ分ける
複数のコマンドをcmd /k "..."の中へ直接書くこと自体は禁止されていません。&もWindowsコマンドの正式な区切り文字です。ただし、パスの引用符、環境変数、&、丸括弧が重なると、どのcmd.exeがどの文字を解釈するか分かりにくくなります。
次のような長いインライン記述は、保守と原因調査が難しくなります。
start "App" cmd.exe /k "cd /d "%PROJ%" & call npm.cmd install & call npm.cmd run start"起動側と処理側を分けると、引用符の入れ子を減らせます。
起動用のadmin.bat:
@echo off
start "App" "%ComSpec%" /k call "%~dp0_start-app.bat"実際の処理を行う_start-app.bat:
@echo off
cd /d "%~dp0"
if not exist "node_modules\" (
call npm.cmd install
if errorlevel 1 exit /b 1
)
call npm.cmd run startログを残したい場合やウィンドウを自動で閉じたい場合は、/kと/cを運用に合わせて選択します。
バッチファイルの場所を基準にする
%~dp0は、実行中のバッチファイルが置かれているドライブとフォルダーパスへ展開されます。末尾にはバックスラッシュが含まれます。
cd /d "%~dp0"cd /dを使うと、現在地だけでなくドライブも切り替えられます。エクスプローラー、スタートアップ、タスクスケジューラなど、異なる作業フォルダーからバッチを起動する場合に役立ちます。
親フォルダーへ移動する場合は、次のように記述できます。
cd /d "%~dp0.."
動作確認のポイント
作成したバッチファイルは、次の条件で確認します。
node_modulesがない初回実行でも後続処理へ進むnode_modulesがある2回目以降も起動する- npmが失敗した場合にエラーを表示して終了する
- スペースを含むフォルダーパスでも動作する
- 別の作業フォルダーから起動しても正しいプロジェクトへ移動する
/kを使用した場合はウィンドウが残る/cを使用した場合は処理後にウィンドウが閉じる
実行中のコマンドを確認したい場合は、一時的に@echo offを外すか、必要な変数と現在地を表示します。
echo Current directory: %CD%
where npm
参考資料
- callコマンド(Microsoft Learn)
- cmdコマンド(Microsoft Learn)
- startコマンド(Microsoft Learn)
- whereコマンド(Microsoft Learn)
まとめ
Windowsのバッチファイルでnpm後の処理を続けるには、call npm.cmd ...と記述します。npx.cmdや自作の.bat/.cmdを呼び出す場合も同じです。
startとcmd /kへ複雑な処理を直接書くことはできますが、引用符や特殊文字の解釈が分かりにくくなります。処理を別のバッチファイルへ分け、%~dp0で作業フォルダーを固定すると、起動場所に左右されにくい構成になります。