問題
WSLでCRAしてyarn startするとcmd.exeを実行できずにウェブブラウザーの起動どころかサーバーも起動せず死んでしまいます。
再現方法:
- WSLで
npx create-react-app hogeしてcd hoge; yarn startします
Starting the development server...
events.js:291
throw er; // Unhandled 'error' event
^
Error: spawn cmd.exe ENOENT
at Process.ChildProcess._handle.onexit (internal/child_process.js:268:19)
at onErrorNT (internal/child_process.js:468:16)
at processTicksAndRejections (internal/process/task_queues.js:80:21)
Emitted 'error' event on ChildProcess instance at:
at Process.ChildProcess._handle.onexit (internal/child_process.js:274:12)
at onErrorNT (internal/child_process.js:468:16)
at processTicksAndRejections (internal/process/task_queues.js:80:21) {
errno: -2,
code: 'ENOENT',
syscall: 'spawn cmd.exe',
path: 'cmd.exe',
spawnargs: [ '/s', '/c', 'start', '""', '/b', 'http://localhost:3000' ]
}
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
そもそもWSLで実行しているのにcmd.exeなどとわけのわからない事を言われたので「またyarnか何かの実行バイナリーがWSL内ではなくWindowsの何かが何故か優先されているふぁっきゅーかな」と思いましたが、同じくらいふぁっきゅーなCRA側の問題でした。
回避策; 本質的な解決策は執筆時点でもまだCRAにマージされていません
1. BROWSER=none 戦術
いまのところ、わたしのおすすめはこちらの回避策です。
yarn startをBROWSER=none yarn startにします- または
package.jsonで"start": "BROWSER=none react-scripts start"してyarn startします
note:
package.jsonを変更する場合に、開発環境の可搬性に PowerShell, cmd など対応したい場合はcross-env付きで仕込みます。- またはプロジェクトで採用するビルドエコシステムの方針によって
run-script-osが有用な場合もあるかもしれません。
- またはプロジェクトで採用するビルドエコシステムの方針によって
"scripts": { "start": "run-script-os", "start:default": "cross-env BROWSER=none react-scripts start", "start:win32": "react-scripts start",
2. PATH=$PATH:/mnt/c/Windows/System32 戦術
yarn startをPATH=$PATH:/mnt/c/Windows/System32 yarn startにします- または
package.jsonで"start": "PATH=$PATH:/mnt/c/Windows/System32 react-scripts start"してyarn startします - または WSL の実行環境の
PATHをexport PATH=$PATH:/mnt/c/Windows/System32します - または
/etc/wsl.confの[Interop]セクションでappendWindowsPath = TrueまたはFalseを定義しない設定へ変更します - または
cmd.exeを実行可能な他のお膳立てをしてあげます
原因
- CRAがブラウザーを起動するために"
cmd.exeを使える状態を前提"にのみ実装されている is-wslで WSL を検出して気を利かせてcmd.exeを起動しようとしているっぽい †参考1
参考
- https://github.com/facebook/create-react-app/issues/7251; Error: spawn cmd.exe ENOENT using WSL since 9.0.0 #7251
関連おまけ
思うところメモ
BROWSER=none 回避策は PATH 回避策より一般的には良いです。WSLのユーザーのおそらくほとんどはWSLを"WindowsとGNU/Linuxが悪魔合体した何か"ではなく、Windowsから便利に利用しやすいGNU/Linux環境として利用し、WSLがWindows上で実行されながらもWindows特有の環境要因にはできるだけ依存せずGNU/Linux環境としての純粋性や可搬性を維持したWindowsとは異なる環境かつWindowsとのつながりもユーザーが求めれば構築しやすい、そんな何かであることを望んでいるのではないかな、と思います。参考の Issue #7251 でもそういう考え方の開発者さんは少なくも無さそうな雰囲気があります。
もちろん、is-wslからcmd.exeによるWindowsネイティブのブラウザー呼び出しを試みようとする、その気の利いた工夫は良い事です。しかし、現状の実装は想定が甘く、WSLを悪魔合体的な環境で利用されている状況だけを前提に fallback も無い実装になっている事が悲しみを生んでしまった原因になっていると思います。開発環境の可搬性も保守性には有用な視点の1つにもなりますし、 default でも巧く解決されて多くのユーザーが意図に反したエラーに悩まされない実装になると嬉しいです。