CRA=create-react-app が WSL で start できない理由と回避方法のメモ
問題
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 でも巧く解決されて多くのユーザーが意図に反したエラーに悩まされない実装になると嬉しいです。