问题
只有在终端直接执行node node_modules/webpack/bin/webpack.js serve --mode development --config build/webpack.dev.conf.js可以正常编译启动项目 但是把package文件配置 "dev": "node node_modules/webpack/bin/webpack.js serve --mode development --config build/webpack.dev.conf.js", 或者 "dev": "npx webpack serve --mode development --config build/webpack.dev.conf.js", 或者 "dev": "webpack serve --mode development --config build/webpack.dev.conf.js", 执行npm run dev都是一样的效果 显示一下版本号然后闪退
过程分析
解释一下 npm run背后做了什么
这就为你详细拆解一下 npm run 背后的"黑盒"机制,以及为什么在你的电脑上,PowerShell 和 npm 之间会产生"交接棒"的冲突。
🎭 第一层:你看到的只是表象(PowerShell 的外壳)
当你在 Windows 的 PowerShell 里输入 npm run dev 时,PowerShell 其实并不知道 npm 是个什么程序。它只是在自己的"环境变量(PATH)"里,找到了一个叫 npm.cmd 的批处理文件,然后把它交给了 Windows 系统去执行。
⚙️ 第二层:npm 的"偷梁换柱"(启动真正的 Node.js 引擎)
这个 npm.cmd 文件,本质上是一个"传话筒"。它内部写了一堆 Windows 批处理代码,核心作用只有一句话:
"启动 node.exe(Node.js 解释器),让它去运行 npm 的核心逻辑文件 npm-cli.js。"
所以,从你按下回车的那一刻起,PowerShell 其实就已经"退居二线"了。真正接管你命令的,是 Node.js 引擎。
📖 第三层:npm 读取"任务清单"(package.json)
Node.js 引擎启动后,npm-cli.js 会立刻去你项目的根目录下,找到 package.json 这个文件。它打开文件里的 scripts 字段,查字典一样寻找你输入的 dev 对应的那串命令(比如你写的 node node_modules/webpack/bin/webpack.js ...)。
🚀 第四层:最关键的"交接棒"(创建子 Shell 进程)
找到那串命令后,npm 并不会自己直接去执行 Webpack。它会做一件非常重要的事:
它会在当前系统里,重新召唤出一个新的"子进程(Child Process)",并且这个子进程默认是一个系统的 Shell 环境(在 Windows 上就是传统的 cmd.exe)。
然后,npm 会把那串命令扔进这个新开的 cmd.exe 黑框框里让它去跑。
💥 为什么你的电脑会在这里"闪退"?
问题就出在第四层的"召唤 Shell" 这个过程上。
环境的"水土不服":你平时是在 PowerShell 里操作的,但 npm run 底层却强制要拉起一个传统的 cmd.exe 来跑命令。这两个东西虽然都是黑框框,但它们的"语言习惯"(环境变量、路径解析规则、特殊字符的处理方式)是完全不同的。
交接时的"摔了一跤":当 npm 试图把控制权从 Node.js 引擎转移给新开的 cmd.exe,并让它去执行你那串很长的 node ... 命令时,你的电脑环境在这个"交接棒"的瞬间出现了严重的冲突。可能是路径里有什么特殊符号 cmd 不认识,也可能是 PowerShell 的某些全局环境变量干扰了 cmd 的启动。
结果:这个新拉起来的 cmd.exe 还没开始真正干活,就因为环境冲突直接崩溃退出了。因为它是后台静默拉起的子进程,所以你只看到终端闪了一下(显示了 Windows 版本号,这是 cmd 启动时的默认特征),然后什么都没了。
✅ 为什么加上 cmd /c 就修好了?
当你把脚本写成 "dev": "cmd /c node ..." 时,你相当于在第三层和第四层之间做了一个"物理外挂":
你不再依赖 npm 内部那个容易出错的"自动召唤 cmd"的机制。你直接把"启动 cmd"这个动作,写死在了命令的最前面。
这就好比:原本 npm 负责帮你叫一辆出租车(cmd)来送你,但它在叫车时总是出 Bug;现在你直接自己拦了一辆出租车(cmd /c),然后告诉 npm:"你不用叫车了,直接把我扔上这辆我已经拦好的车就行。"
这样一来,npm 只需要负责把命令传给这个已经稳定启动的 cmd 进程,完美绕过了中间那个容易崩溃的"自动交接"环节。
解决方式
"dev": "cmd /c "node node_modules/webpack/bin/webpack.js serve --mode development --config build/webpack.dev.conf.js & pause"",