# npm script 面试总览:执行环境、编排与依赖确定性
⚡ 30 秒速记
npm run xxx= 读package.json的scripts.xxx→ 把node_modules/.bin加到PATH前面 → 交给系统shell执行(Linux/Mac是sh,Windows是cmd.exe)- 钩子:
prebuild/postbuild会在build前后自动跑 - 串行用
&&(前一步失败就停),并行用npm-run-all/concurrently这类工具,别指望&跨平台 - 给底层命令传参用
--:npm run lint -- --fix;跨平台设环境变量用cross-env - 版本范围管「允许装哪些」,
lockfile管「这次实际装了哪个」;CI用npm ci
npm script 本质上就是给命令起别名:npm run build 找到 scripts.build 那段文本,把 node_modules/.bin 加进 PATH,再交给系统 shell 去跑。 所以脚本里能直接写 eslint 而不用写全路径。也正因为交给的是系统 shell,Windows 的 cmd 和 Mac 的 sh 语法不一样,NODE_ENV=production 这种写法在 Windows 上就挂了,要用 cross-env。多个命令串起来用 &&,有一个失败整体就失败。流程一复杂,我会把逻辑挪到一个 scripts/build.mjs 里,package.json 只留入口。
{
"scripts": {
"lint": "eslint .",
"test": "vitest run",
"verify": "npm run lint && npm test",
"build": "cross-env NODE_ENV=production node scripts/build.mjs"
}
}
执行 npm run build 时,npm 先找到脚本文本,再构造包含 node_modules/.bin 的 PATH 并交给当前平台的 shell。因此脚本里能直接写 eslint,无需硬编码 ./node_modules/.bin/eslint;但同一段 shell 在 Windows 与 POSIX 环境的变量语法、引号和命令可用性可能不同,这正是跨平台工具存在的原因。
串行任务用 && 可以保证前一步失败后停止,不能用 ; 假装等价。并行任务不只是“同时启动”:还要聚合退出码、把终止信号发给所有子进程,并避免一个任务失败后另一个继续占端口。规模变大后,把分支、重试和文件处理放进可测试的 Node.js 脚本,package.json 只保留稳定入口。
版本范围和 lockfile 回答的是两个不同问题:^1.2.3 描述未来重新解析时允许选哪些版本,lockfile 固定这次安装使用的精确版本及依赖图。CI 应使用 npm ci,当清单与 lockfile 不一致时直接失败,而不是悄悄重写锁文件。上面的交互演示会真实解析两组 semver 范围,展示 ^1.2.3 与 ^0.2.3 的边界差异。