问题记录一下
今天遇到一个很奇怪的问题。
一个 vue-cli 4 + vue 2 的项目,运行 npm run dev
竟然报错。
命令行环境是 Windows 11 21H2 + Windows Terminal + PowerShell 7.3.0
项目 package.json
的 scripts 配置了 dev
是 vue-cli-service serve
项目根目录下正巧有一个 node.js
为文件名的文件,然后每次执行 npm run dev
都变成了执行这个文件,里面用了 ES6 语法,不是 CommonJS 规范的,导致报错。
原因猜测:
npm run dev
实际上是在一个局部环境内执行 package.json
里配置的 vue-cli-service serve
,所有命令都会去 ./node_modules/.bin
下寻找,这是安装依赖时,npm自动生成好了的可执行文件的软链接,一般都会生成3个,一个无后缀名的二进制文件,一个 .cmd
文件,和一个 .ps1
文件。
Windows环境下,基本上都是找 .cmd
文件来执行,这个文件内容如下
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\@vue\cli-service\bin\vue-cli-service.js" %*
可以看到最终是执行 node 绝对路径\node_modules\@vue\cli-service\bin\vue-cli-service.js
这样一个命令(参考 https://www.cnblogs.com/HYZhou2018/p/12195670.html),
那么我怀疑问题出在这个 node
上,可能是 Windows 11 和 CMD 的 bug,导致这里没有去找全局的 node
命令,而是直接当成是当前目录下的 node.js
脚本执行了,而正巧项目就有这么个文件。
那么就检查 这个 .cmd
文件里那个 ELSE
分支的内容,PATHEXT
是Windows环境变量,在PowerShell中使用 $env:PATHEXT
查看,没啥问题,
再考虑包管理工具,换用 cnpm run dev
、yarn dev
,结果也一样报错。
那么干脆直接执行 .\node_modules\.bin\vue-cli-service.cmd serve
,也是一样的,问题应该就在这个 .cmd
脚本这里,
作为对比确认,执行 .\node_modules\.bin\vue-cli-service.ps1 serve
,一切顺利,没有问题。
执行 .\node_modules\.bin\vue-cli-service serve
是一样的,因为是在PowerShell里运行,不写后缀的默认会去找 .ps1
文件。
怎么解决?
首先肯定是考虑把根目录的 node.js
文件换掉。
换掉后一切顺利,不过,停止项目时,发现需要按两次 Ctrl + C
了,因为执行 .\node_modules\.bin\vue-cli-service.cmd
这个CMD文件,需要开子进程用系统的 cmd.exe
了,CMD环境里结束进程就会多一步提示 Terminate batch job (Y/N)?
。
所以又再考虑不要CMD环境,尝试把 scripts 的 dev
改成 pwsh -c vue-cli-service serve
,这样通过PowerShell来执行 vue-cli-service serve
命令( -c
就是 -Command
),这样就不会走 .\node_modules\.bin\vue-cli-service.cmd
文件来执行了(在 .cmd
文件中加入 @ECHO 666
以验证),而是会走 .\node_modules\.bin\vue-cli-service.ps1
文件,不会再触发 node.js
文件的问题了,node.js
文件也不用换掉,但是,最后停止项目的时候,还是多了一步提示 Terminate batch job (Y/N)?
,需要按两次 Ctrl + C
,不知道是为什么,可能是 pwsh -c
多启动了一层PowerShell环境吧。
最后,要么接受需要按两次 Ctrl + C
,要么直接敲 .\node_modules\.bin\vue-cli-service serve
来启动项目算了