monorepo
pnpm 在管理 monorepo 方面具有独特的优势,主要归功于其高效的依赖管理和出色的性能。
一、 pnpm 的优势
高效的依赖安装:
内容寻址存储 (Content-Addressable Store): pnpm 会在全局存储依赖项的硬链接 (hard links),这意味着如果多个项目使用相同版本的依赖,它们只会占用磁盘上的一份空间。这大大节省了磁盘空间。
非扁平化的
node_modules: pnpm 创建的node_modules结构是符号链接 (symlinks) 的嵌套结构。这解决了幽灵依赖 (Phantom Dependencies) 和提升问题 (Dependency Hoisting) ^1。幽灵依赖 (Phantom Dependencies): 子依赖不会被提升到项目根目录,因此你无法意外地使用未显式声明的依赖。
性能卓越:
由于依赖项的去重和硬链接机制,安装速度通常比 npm 或 yarn 更快。
严格性:
node_modules结构更严格,确保项目只能访问其直接声明的依赖,提高了代码库的可维护性和可靠性。
二、 Monorepo 的关键配置
要将一个代码库配置为 pnpm monorepo,最核心的文件是 pnpm-workspace.yaml。
pnpm-workspace.yaml:这个文件定义了工作空间 (Workspace) 的根目录和所有子包 (Packages) 的位置。
packages:
# 匹配 'packages' 目录下的所有子目录
- "packages/*"
# 匹配 'apps' 目录下的所有子目录
- "apps/*"
# 也可以排除特定目录
# - '!packages/legacy-app'作用: 告诉 pnpm 哪些目录是工作空间中的独立包。
位置: 必须放在 monorepo 的根目录。
包之间的依赖(内部引用):在 monorepo 中,不同包之间可以相互依赖。
声明方式: 在依赖包的
package.json文件中,像引用外部依赖一样,使用包名进行引用,但版本号通常使用特殊的工作空间协议workspace:。版本号协议:
"my-ui-library": "workspace:^1.0.0": 使用^遵循 SemVer 规则。"my-utils": "workspace:*": 使用*匹配当前最新版本。"my-app": "workspace:^"(最常用): pnpm 会自动解析到该包的当前版本。
三、 Monorepo 常用命令
pnpm 提供了强大的命令来管理工作空间中的所有包。
pnpm install
在根目录执行,安装所有子包的依赖。
pnpm install
pnpm add
添加依赖到指定的包。
pnpm add lodash --filter <pkg-name>
pnpm remove
从指定的包中移除依赖。
pnpm remove lodash --filter <pkg-name>
pnpm run
运行一个脚本命令。
pnpm run build --filter <pkg-name>
pnpm run <script> -r
递归地在所有子包中运行相同的脚本。
pnpm run test -r
pnpm link
在工作空间内手动创建符号链接(通常不需要,install 会自动处理)。
pnpm publish -r
递归地发布所有有更新的包。
pnpm publish -r
四、 筛选器 (--filter)
--filter)--filter 是 pnpm monorepo 中最核心且最强大的特性之一。它允许您将命令的作用范围限制在一个或多个特定的包上。
--filter <pkg-name>
针对指定的包。
--filter my-app
--filter <scope>/*
针对某个范围内的所有包。
--filter @scope/*
--filter ...<pkg-name>
包括指定包及其所有依赖项。
--filter ...my-app
--filter <pkg-name>...
包括指定包及其所有被依赖项(依赖于该包的项目)。
--filter my-ui-lib...
--filter ./<path>
针对指定路径下的包。
--filter ./packages/admin
--filter '{<glob>}'
使用 glob 模式筛选。
--filter '{apps/*}'
例如,要只构建 my-app 及其所有依赖的内部库: pnpm run build --filter ...my-app
五、 运行拓扑排序(构建流程)
当使用 -r 或 --filter 运行脚本时,pnpm 会自动进行拓扑排序 (topological sorting)。
作用: pnpm 会根据包之间的依赖关系,确定一个安全的执行顺序。例如,如果
app依赖于ui-lib,pnpm 会确保先构建ui-lib,然后才构建app。关键: 这使得构建流程非常可靠,不需要额外的工具来管理构建顺序。
六、 限制(shamefully-hoist)
shamefully-hoist)为了与某些依赖于扁平化 node_modules 结构的工具(如某些旧版 Webpack 加载器或 Jest)兼容,pnpm 提供了选项来放松其严格的依赖结构。
shamefully-hoist = true: 在.npmrc文件中设置此选项,可以强制 pnpm 像 npm/yarn 那样,将所有依赖项提升到根node_modules中。⚠️ 建议: 尽量避免使用此选项,因为它会失去 pnpm 严格依赖管理带来的优势,重新引入幽灵依赖的风险。
常用命令实例
安装
移除
更新
运行脚本
最后更新于