侧边栏壁纸
博主头像
一笑痕

仙人之下我无敌,
仙人之上一换一。

  • 累计撰写 62 篇文章
  • 累计收到 7 条评论

npm --prefix 跑脚本和装依赖,都落在 prefix 那一层

2026-9-18 / 0 评论 / 3 阅读

npm --prefix 跑脚本和装依赖,都落在 prefix 那一层

monorepo 里想不动窝操作某个子包,npm --prefix packages/app run build 是最常见的写法。有人担心脚本拿到的工作目录不对,有人担心依赖装错地方。下面几个问题都是围绕这件事的,答案全部来自本机实测(node v26.8.1 / npm 11.19.0),脚本在 tools/verify-pkgmgr-cwd.sh

--prefix 会不会把脚本的工作目录也换掉?

会。在 repo 根上执行 npm --prefix packages/app run wherewhere 脚本只有一行 console.log(process.cwd()),输出是:

===== npm --prefix:脚本看到的目录,以及退出码 =====

> app@1.0.0 where
> node -e 'console.log("cwd=", process.cwd())'

cwd= /private/tmp/pkgmgr-cwd/repo/packages/app
npm run exit=0

脚本拿到的 cwd 就是 prefix 指的那一层,不是执行命令时所在的 repo 根。也就是说,脚本里写相对路径读文件,读的是子包目录下的文件。这一点对依赖 npm 生命周期脚本的工具同样成立。

装依赖呢,node_modules 会出现在哪一层?

npm --prefix packages/app install left-pad 之后找了一遍:

===== npm --prefix 装依赖:node_modules 出现在哪一层 =====
repo 根这一层:
  没有
packages/app 这一层:
packages/app/node_modules

===== 对照:cd 进去再装,落点一致 =====
packages/app/node_modules

落点在 prefix 指的包那一层,跟 cd 进去再装完全一致。没有装到 repo 根去,也没有因为上层有 package.json 就往上漂。

那依赖提升(hoisting)还生效吗?

npm 对普通目录树的提升逻辑照走:装的时候它照样会看上层有没有可以共享的依赖。这一点没实测深挖,只确认了落点:node_modules 建在子包那层。monorepo 用 workspace 协议的话另说,workspace 有自己的一套提升规则,--prefix 是绕开 workspace 直接按目录操作的,两者别混用。

有什么场景不该这么用?

CI 里想在根上一条命令依次构建多个子包,--prefix 拼循环确实省事,但每个子包的脚本假设未必一样,脚本假设的环境变量、.npmrc 都跟着 cwd 走。子包多了之后,一条根命令里的隐含假设会越积越多。包少、脚本统一的时候用着舒服;包一多,老老实实进目录跑,或者交给专门的 monorepo 工具,出问题好定位。

另外注意 --prefix 的值写 . 的时候行为和不写一样,这种写法在脚本里容易让人误以为有特殊处理,其实没有,别为了好看加它。

    🤞 分享