pnpm 12 正式发布后,前端社区讨论最多的一个问题是:Rust 重写到底快了多少。这个问题的背后其实不止是“快了几个毫秒”,而是 Node.js 包管理器在架构层面的一次明显转向。作为日常高频使用的工具,pnpm 的安装速度、磁盘占用、依赖解析逻辑和命令行为,直接影响开发体验和 CI 构建效率。本文从 pnpm 12 的实际变化出发,梳理 Rust 重写带来的性能提升、安装配置要点、常见问题的排查路径,以及从 npm 迁移到 pnpm 时最容易踩的坑。
如果你正在使用 npm 或 yarn,或者已经在团队里推广 pnpm,这篇文章会帮你理解 pnpm 12 到底改了什么、实测时该看哪些指标、遇到“pnpm 不是内部或外部命令”“pnpm 下载失败”“node 版本不满足要求”这类报错时该怎么处理。
1. 先理解 pnpm 为什么值得关注:不只是包管理器
1.1 pnpm 解决的核心问题
pnpm 是一个 Node.js 包管理器,和 npm、yarn 属于同一类工具。但它从一开始就不是为了“换一个命令名字”而存在,而是为了解决 npm 和早期 yarn 在依赖管理上的两个核心问题:重复安装和幽灵依赖。
在 npm 早期版本中,项目安装依赖时会按照依赖树的层级把每个包复制到node_modules里。如果多个项目依赖同一个版本的 React,磁盘上就会存在多份完全相同的 React 文件。更麻烦的是,npm 的扁平化结构会把传递依赖提升到顶层node_modules,导致项目代码可以直接引用那些没有在package.json中声明的包。这种现象叫幽灵依赖,它会让项目的依赖边界变得非常模糊。
pnpm 的解决方案是使用内容寻址存储和硬链接。所有依赖包都统一存放在一个全局存储目录中,项目中的node_modules只是通过硬链接或符号链接指向这些真实文件。每个项目的node_modules结构严格按照package.json的声明组织,没有被声明过的包无法被直接引用。这样既节省了磁盘空间,也保证了依赖关系的确定性。
1.2 为什么 Rust 会出现在 Node.js 工具链里
Node.js 生态里的工具链正在经历一轮重写潮。Rust 因为内存安全、无 GC、性能接近 C/C++,同时拥有 Cargo 这样完善的构建系统,成为 CLI 工具重写的热门选择。像 SWC、TurboPack、Biome 这些前端基础设施项目,都采用了 Rust。
pnpm 的核心逻辑并不只是“下载 tarball 解压到本地”,还包括依赖解析、版本选择、依赖图构建、硬链接处理、锁文件计算等。这些操作在 JavaScript 运行时里会受限于 V8 引擎的性能表现。把计算密集部分迁移到 Rust 后,可以显著减少大规模项目中的安装耗时和内存占用。pnpm 12 的发布重点就是把更多核心路径迁移到 Rust 实现,同时保持原有 JavaScript 插件生态的兼容性。
1.3 pnpm、npm、yarn 的定位差异
在实际项目中,选择包管理器不只看安装速度,还要看团队协作、CI 缓存、Monorepo 支持和锁文件兼容性。
| 维度 | npm | yarn classic | yarn berry | pnpm |
|---|---|---|---|---|
| 磁盘占用 | 较高,多项目重复安装 | 较高 | 较高(依赖全局缓存) | 低,硬链接共享存储 |
| 幽灵依赖 | 常见 | 常见 | 通过 PnP 解决 | 基本杜绝 |
| Monorepo 支持 | 需要额外工具 | 需要额外工具 | 内置 Workspace | 内置 Workspace |
| 锁文件 | package-lock.json | yarn.lock | yarn.lock | pnpm-lock.yaml |
| 安装速度 | 中等 | 中等 | 较快 | 较快,Rust 重写后更快 |
| 插件生态 | 丰富 | 较丰富 | 较丰富 | 较丰富,但部分工具需适配 |
pnpm 12 在保持这些优势的基础上,把性能优化推进到了更底层的位置。下一节可以看具体的架构变化。
2. pnpm 12 的核心变化:Rust 重写到底改了什么
2.1 Rust 重写覆盖的范围
pnpm 12 并不是把整个 pnpm 全部用 Rust 重写,而是采用渐进式重构。对性能影响最大的几个模块优先迁移到 Rust:
- 依赖解析器:负责读取
package.json、解析版本范围、决定安装哪个版本。 - 锁文件计算器:负责生成和校验
pnpm-lock.yaml,判断依赖树是否需要更新。 - 包导入器:负责把全局存储中的包通过硬链接或复制的方式导入到项目
node_modules。 - 文件校验器:负责校验已安装包的完整性,包括 checksum 验证和文件状态检查。
这些模块在过去是用 TypeScript 实现的。迁移到 Rust 后,主要收益集中在 CPU 密集场景,比如大项目首次安装、锁文件变更后的重算、以及 CI 中每次干净安装的依赖树构建。
2.2 安装流程对比:npm、pnpm JS 版本、pnpm Rust 版本
为了理解 Rust 重写带来的差异,可以把一次安装过程拆成几个阶段:
- 读取
package.json和锁文件。 - 解析依赖范围,确定需要安装的包版本。
- 下载缺失的 tarball 到全局存储。
- 把包文件链接或复制到项目
node_modules。 - 执行
postinstall、preinstall等生命周期脚本。
在 JavaScript 实现中,第 2 步和第 4 步会频繁创建对象、遍历依赖树、操作文件路径。这些操作在大型 Monorepo 中可能涉及数万个包,JavaScript 的对象开销和 GC 压力会非常明显。
Rust 重写后,这些计算密集路径使用更高效的数据结构和并发模型,减少中间对象的创建,同时可以利用多核 CPU 并行处理包的导入操作。用户能感受到的变化就是:
pnpm install的输出节奏更快。- 锁文件更新时等待时间更短。
- 在大仓库中内存占用更平稳。
2.3 为什么不能只看“快了多少”
很多人问 pnpm 12 快了多少,但这个问题没有统一答案。不同项目的包数量、网络速度、磁盘类型、锁文件状态、缓存命中率都会影响最终耗时。
比较合理的评估方式是在同一台机器上做横向对比:
- 清空全局缓存后执行一次干净安装。
- 在已有缓存的情况下执行一次冷安装。
- 只执行
pnpm install --frozen-lockfile,验证锁文件解析性能。 - 对比
pnpm install和pnpm install --offline的差异。
不能只看一篇博客里的秒数就得出结论。性能数据只有在相同条件下对比才有意义。
3. 环境准备:安装 pnpm 12 前必须确认三件事
3.1 Node.js 版本必须满足要求
pnpm 对 Node.js 版本有明确的engines声明。pnpm 12 要求至少 Node.js v22.13,具体以官方发布说明为准。如果在旧版本 Node.js 上安装,会出现类似这样的报错:
error: this version of pnpm requires at least node.js v22.13遇到这类提示,先检查当前 Node.js 版本:
node -v如果版本过低,建议使用 nvm、fnm 或 volta 切换 Node.js 版本。这里要注意:不要为了临时绕过版本检查去修改 pnpm 的engines配置,因为新版本可能使用了当前 Node.js 不具备的 API 或语法特性,强行运行会导致未知错误。
3.2 选择安装方式:npm 全局安装还是独立安装器
安装 pnpm 有多种方式,各有利弊。
| 安装方式 | 命令 | 适用场景 |
|---|---|---|
| npm 全局安装 | npm install -g pnpm | 最简单,前提是已经安装了 npm |
| Corepack | corepack enable pnpm | Node.js 自带,适合按项目切换版本 |
| 独立安装脚本 | curl -fsSL https://get.pnpm.io/install.sh | sh | 适合 CI 或不想依赖 npm 的环境 |
| Scoop | scoop install pnpm | Windows 用户 |
| Mise | mise use -g pnpm | 同时管理多个运行时和工具版本 |
个人推荐在开发环境中使用 Corepack 或独立安装器,因为它可以把 pnpm 版本锁定在项目级别,避免团队成员各自安装不同版本引入的行为差异。如果只是快速体验,npm install -g pnpm完全够用。
3.3 Windows 环境安装后的环境变量问题
Window 用户安装完 pnpm 后,最常见的问题是:
pnpm : 无法将“pnpm”项识别为 cmdlet、函数、脚本文件或可运行程序的名称或者:
'pnpm' 不是内部或外部命令,也不是可运行的程序或批处理文件这两种报错的原因基本一致:pnpm 的可执行文件目录没有加入到PATH环境变量中。
在 Windows 上通过 npm 全局安装时,需要查看 npm 全局 bin 目录:
npm prefix -g把输出的目录添加到系统环境变量的Path中,然后重新打开终端。如果安装时指定了自定义的 npm 全局目录,例如:
npm config set prefix "D:\nodejs\node_global" npm install -g pnpm那就要把D:\nodejs\node_global加入PATH。
注意:修改环境变量后要重开终端,已经在旧环境变量中启动的 Shell 不会自动刷新。
4. 安装与配置:踩过这些坑之后,pnpm 才能真正跑起来
4.1 pnpm 下载失败和安装卡顿怎么处理
pnpm 下载失败通常有三个原因:网络不稳定、默认源不可达、全局存储目录权限异常。
先用以下命令查看当前 pnpm 使用的 registry:
pnpm config get registry如果访问默认源很慢,可以切换到国内镜像:
pnpm config set registry https://registry.npmmirror.com这里要注意:pnpm 的下载过程分为两步。第一步是从 registry 获取元数据,第二步是从 registry 下载 tarball 包文件。设置 registry 后两步都会走同一个源。如果项目里配置了.npmrc,要确认配置是否真的生效:
pnpm config get registry如果项目根目录、用户主目录、全局目录存在多个.npmrc文件,pnpm 会按优先级合并配置,项目级配置优先级最高。排查时可以逐个查看:
pnpm config list另外,全局存储目录所在磁盘空间不足也会导致安装失败。pnpm 默认的全局存储目录可以通过以下命令查看:
pnpm store path如果空间不足,可以更换存储目录:
pnpm config set store-dir "D:\.pnpm-store"4.2 延长安装等待时间:网络超时参数
在弱网环境下,pnpm install可能会因为网络请求超时而失败。可以调整 pnpm 的网络超时时间,在.npmrc中配置:
fetch-timeout=600000 fetch-retries=5 fetch-retry-factor=2 fetch-retry-mintimeout=10000 fetch-retry-maxtimeout=60000参数含义如下:
| 参数 | 含义 | 默认值 |
|---|---|---|
fetch-timeout | 请求超时时间,单位毫秒 | 60000 |
fetch-retries | 失败重试次数 | 2 |
fetch-retry-factor | 重试间隔倍率 | 10 |
fetch-retry-mintimeout | 最小重试等待时间,单位毫秒 | 10000 |
fetch-retry-maxtimeout | 最大重试等待时间,单位毫秒 | 60000 |
调大这些值可以让 pnpm 在弱网环境下更耐心地等待响应。但要注意,fetch-timeout不是越大越好,过大会导致安装长时间挂起,无法及时感知网络异常。
4.3 运行 pnpm run build 构建出的包,怎么用 Nginx 启动
这个问题的本质是:pnpm 只负责安装依赖和触发构建脚本,它本身不提供 Web 服务能力。pnpm run build执行的是package.json中定义的build脚本,常见的框架如 Vite、Next.js、Vue CLI 等,构建产物会输出到dist、build或.next目录。
之后用 Nginx 托管构建产物,可以这样配置:
server { listen 80; server_name example.com; root /var/www/my-project/dist; index index.html; location / { try_files $uri $uri/ /index.html; } }需要确认三件事:
- 构建输出目录是否与
root一致。 - 是否使用了 history 路由模式。如果是,需要配置
try_files,否则刷新页面会 404。 - 静态资源路径是否是绝对路径。如果构建配置里设置了
base或publicPath,Nginx 的location也要相应调整。
一个典型的错误是:pnpm run build成功后,直接访问 Nginx 显示空白页,但接口请求正常。这时候先打开浏览器开发者工具看静态资源请求路径,再检查 Nginx 的root和try_files配置。
4.4 依赖的生命周期脚本被拦截怎么办
pnpm 对依赖的安装生命周期脚本有严格限制。默认情况下,依赖的preinstall、install、postinstall脚本不会自动执行,除非在package.json或.npmrc中明确允许。
如果安装依赖时看到这样的提示:
║ Ignored build scripts: esbuild. Run "pnpm approve-builds" to pick which dependencies should be allowed to run.这是因为 pnpm 默认不允许依赖执行构建脚本。esbuild、sharp、node-sass这类依赖需要在安装时执行脚本,所以必须手动批准。
解决方案是执行:
pnpm approve-builds命令会列出被忽略的依赖,交互式选择需要允许的依赖。也可以在package.json中配置:
{ "pnpm": { "onlyBuiltDependencies": [ "esbuild", "sharp" ] } }配置完成后重新运行:
pnpm install这里要解释一下背后的逻辑:pnpm 默认禁用依赖构建脚本,是为了安全考虑。因为install脚本会在你安装依赖时执行任意代码,如果依赖被恶意攻击或镜像源被污染,自动执行脚本会带来供应链安全风险。所以 pnpm 选择让用户显式批准,而不是默认全部执行。
5. 从 npm 迁移到 pnpm 的关键步骤
5.1 先移除旧的 node_modules 和锁文件
从 npm 迁移到 pnpm 时,不建议直接在同一目录下运行pnpm install。因为 npm 生成的node_modules是扁平结构,pnpm 安装时会基于已有的目录状态做增量处理,容易产生不可预期的冲突。
推荐做法:
rm -rf node_modules rm -rf package-lock.json pnpm install如果项目还使用了 yarn,则:
rm -rf node_modules rm -rf yarn.lock pnpm install执行pnpm install后,项目根目录会生成pnpm-lock.yaml。这个文件的作用和package-lock.json一样,都是锁定依赖版本,保证团队内安装结果一致。
5.2 检查项目中的工具链兼容性
迁移过程中,最容易出问题的不是 pnpm 本身,而是那些默认从项目根部node_modules查找二进制的工具。
例如:
- ESLint 需要通过
pnpm dlx eslint或本地安装方式运行。 - Jest、Vitest 需要确认在 pnpm 的符号链接结构下能找到二进制。
- 某些依赖在 npm 扁平结构中能“意外”访问到传递依赖,在 pnpm 的严格结构下会直接报模块找不到。
如果某个包在迁移后报错:
Cannot find module 'xxx'先在package.json中检查是否已声明依赖。如果没有声明,但代码里确实使用了,需要把该包加入dependencies或devDependencies。这样做虽然要修改代码,但其实是把项目从“依赖运气”变成“依赖正确声明”的过程。
5.3 使用 pnpm import 生成锁文件
如果项目已经拥有 package-lock.json,但希望直接生成对应的 pnpm 锁文件,可以使用:
pnpm import这个命令会读取现有锁文件的解析结果,生成pnpm-lock.yaml。但要注意,pnpm import只能保证锁文件格式转换,不能保证所有解析逻辑完全一致。如果项目中存在复杂的 git 依赖或私有 registry,转换后可能需要手动调整。
5.4 Monorepo 场景下的 workspace 配置
pnpm 内置了 workspace 支持。在根目录创建pnpm-workspace.yaml:
packages: - "packages/*" - "apps/*"这里目录结构会根据项目需要调整,例如:
my-monorepo/ ├── apps/ │ └── web/ ├── packages/ │ ├── ui/ │ └── utils/ ├── package.json ├── pnpm-workspace.yaml └── pnpm-lock.yaml在 workspace 内,一个包依赖另一个本地包时,不需要手动npm link,直接声明版本号即可,例如:
{ "dependencies": { "@my-monorepo/utils": "workspace:*" } }pnpm 会识别workspace:*协议并将包链接到本地。发布时如果使用workspace:*,pnpm 会提示需要把版本替换为实际版本,可以使用pnpm publish自动处理。
6. 实测与验证:怎么衡量 pnpm 12 的性能改进
6.1 建立一个可复现的基准测试方法
想确认 Rust 重写后快了多少,不能只靠“感觉”。建议按以下步骤建立基准:
- 准备一个足够大的项目,或者用多个中等项目模拟依赖规模。
- 分别使用 npm、pnpm 执行干净安装。
- 确保 npm 和 pnpm 都使用同一镜像源,避免网络差异影响结果。
- 记录以下指标:
- 安装总耗时。
- 磁盘占用。
node_modules中文件数量。- lock 文件生成耗时。
- 内存峰值。
- 重复多次,去掉极端值后取平均值。
命令示例:
# 清空缓存和依赖 npm cache clean --force rm -rf node_modules package-lock.json # npm 安装计时 /usr/bin/time -v npm install # 清空 pnpm 存储和依赖 rm -rf node_modules pnpm-lock.yaml pnpm store prune # pnpm 安装计时 /usr/bin/time -v pnpm install在 Windows 上可以使用 PowerShell 的Measure-Command:
Measure-Command { pnpm install }6.2 看安装速度时还需要注意这些变量
安装耗时容易受网络影响,所以更可靠的方式是测试磁盘相关性能。可以把 pnpm 的全局存储预热后,使用--offline参数执行离线安装:
pnpm install --offline这样可以从已缓存的包中完成安装,排除网络波动。对比 npm 的离线安装会更复杂,因为 npm 缓存的结构与 pnpm 不同。实际测试时,建议把网络下载和本地安装分别测试:
- 网络阶段:下载所有 tarball 的耗时。
- 本地阶段:从缓存到
node_modules生成完毕的耗时。
Rust 重写对本地阶段的提升更明显,因为这一阶段涉及大量文件操作和依赖图遍历。
6.3 验证依赖结构是否符合预期
安装完成后,可以使用以下命令检查node_modules的路径类型:
# 列出 node_modules 中的前若干条目 ls -la node_modules | head # 检查某个包的物理路径 pnpm list --depth 0如果项目中没有幽灵依赖,那么代码里无法直接引用未声明的包。可以故意测试一下:
node -e "require('some-unlisted-package')"如果提示模块找不到,说明 pnpm 的严格依赖隔离已经生效。这正是 pnpm 与 npm 的关键差异之一。
7. 常见问题排查:从报错信息倒推原因
7.1 “pnpm 不是内部或外部命令”
现象:
'pnpm' 不是内部或外部命令,也不是可运行的程序或批处理文件。排查顺序:
- 先确认 pnpm 是否真的安装成功:
npm ls -g pnpm- 确认 npm 全局目录是否在
PATH中:
npm prefix -g- 检查终端是否在修改环境变量后重新打开。
- 如果是 Corepack 启用失败,尝试:
corepack prepare pnpm@latest --activate7.2 pnpm install 卡住或超时
现象:
pnpm install长时间停在 “Resolving” 或 “Downloading” 阶段。- 报错
ETIMEDOUT或ECONNREFUSED。
排查顺序:
- 检查网络代理:
pnpm config get proxy pnpm config get https-proxy如果不需要代理但配置了代理,会导致请求失败。清除代理:
pnpm config delete proxy pnpm config delete https-proxy- 检查 registry:
pnpm config get registry- 检查 DNS 或 hosts 文件。
- 尝试切换镜像源或使用
--fetch-timeout调大超时。
7.3 Node.js 版本过低或过高
现象:
error: this version of pnpm requires at least node.js v22.13这种情况必须切换 Node.js 版本,而不是想办法绕过版本检测。
推荐使用 fnm:
fnm install 22.13 fnm use 22.13或者使用 nvm:
nvm install 22.13 nvm use 22.13版本切换后重新验证:
node -v pnpm -v7.4 镜像源里的包与官方源不一致
当配置了国内镜像后,偶尔会出现某些包版本不存在或 checksum 不一致的情况。这时可以先验证包在官方源是否存在,再决定是否需要切换 registry。
常见处理方式:
pnpm config set registry https://registry.npmjs.org/ pnpm install生产项目中不建议长时间使用不稳定的个人镜像源。可以使用企业内网搭建的 registry 代理,或使用云厂商提供的 npm 镜像。
7.5 pnpm 在 CI 中的缓存策略
pnpm 提供了--prefer-offline和--frozen-lockfile两个对 CI 很重要的参数。
pnpm install --frozen-lockfile --prefer-offline--frozen-lockfile:如果pnpm-lock.yaml与package.json不一致,直接失败,避免 CI 中偷偷更新依赖。--prefer-offline:优先使用本地缓存,减少网络请求。
GitHub Actions 中可以用:
- name: Setup pnpm uses: pnpm/action-setup@v4 with: version: 12 run_install: false - name: Install dependencies run: pnpm install --frozen-lockfile这里要注意:不同 CI 平台的缓存 key 需要包含锁文件的哈希值,否则缓存容易失效。
8. 常见错误用法与推荐做法
8.1 不提交锁文件
错误做法:
echo "pnpm-lock.yaml" >> .gitignore推荐做法:提交pnpm-lock.yaml。锁文件不仅记录版本号,还记录了依赖解析结果,是保证团队环境一致的核心文件。
8.2 混用 npm 和 pnpm 操作同一项目
错误做法:
npm install pnpm install npm run build这会破坏node_modules结构。推荐做法是选定一个包管理器后,整个项目生命周期内保持一致。如果需要切换,先删掉node_modules和旧锁文件。
8.3 使用 pnpm 时全局安装依赖
错误做法:
pnpm add -g lodash大多数情况下不需要全局安装。项目依赖应该写入package.json。只有在安装 CLI 工具时才考虑全局安装。而且全局安装的包也不会被项目代码直接引用。
8.4 依赖脚本全部放行
错误做法:
{ "pnpm": { "neverBuiltDependencies": [] } }或者干脆在.npmrc中:
enable-pre-post-scripts=true这种配置太宽泛。正确做法是只允许可信依赖的构建脚本。具体可以在package.json中列出白名单:
{ "pnpm": { "onlyBuiltDependencies": [ "esbuild", "prisma", "sharp" ] } }8.5 忽略 Node.js 版本跨平台问题
在 Windows 上安装 pnpm 后,如果团队其他成员使用 macOS,要注意.npmrc中的store-dir配置不要写死 Windows 路径,否则会导致其他平台无法使用。
推荐将store-dir配置放在用户级.npmrc,而不是项目级。这样每个开发者可以根据自己的环境设置存储目录。
9. 最佳实践清单:pnpm 12 项目落地建议
9.1 环境准备阶段
- 统一 Node.js 版本,至少满足 pnpm 12 的 engines 要求。
- 使用 Corepack 或独立安装器锁定 pnpm 版本。
- 在项目根目录添加
.npmrc,至少配置registry、store-dir和网络超时参数。 - 确认
PATH中包含 pnpm 的可执行文件目录。
9.2 项目初始化阶段
- 从空目录开始使用 pnpm 初始化,或先从 npm 迁移时清理旧依赖。
- 提交
pnpm-lock.yaml。 - 如果是 Monorepo,配置
pnpm-workspace.yaml。 - 设置
onlyBuiltDependencies白名单,提前处理 esbuild、sharp 等依赖。
9.3 CI/CD 阶段
- 使用
--frozen-lockfile防止依赖意外变更。 - 使用
--prefer-offline加速缓存命中。 - 缓存 pnpm 的全局存储目录。
- 安装完成后执行
pnpm list --depth 0或构建命令验证依赖可用。
9.4 开发阶段
- 新增依赖使用
pnpm add <pkg>,不要手动修改package.json后直接运行pnpm install。 - 删除依赖使用
pnpm remove <pkg>。 - 使用
pnpm exec执行本地安装的二进制,避免依赖全局环境。 - 定期执行
pnpm outdated检查依赖版本。
9.5 性能基线参考思路
如果要给团队一个“快了多少”的结论,可以按下面思路给出数据:
- 准备一个包含 1000 个依赖的中大型项目。
- 在相同机器、相同镜像源、相同 Node.js 版本下,分别执行 npm 和 pnpm 的干净安装。
- 记录总耗时和磁盘占用。
- 报告时注明测试条件,不要只报一个数字。
10. 扩展方向:从 pnpm 到前端工具链的 Rust 化
pnpm 12 的 Rust 重写只是前端工具链 Rust 化趋势的一部分。后续还可以关注这些方向:
- SWC:用于替代 Babel 的 JavaScript 转译器。
- Biome:集成了 lint、format、test 等能力的工具链。
- TurboPack:Webpack 的 Rust 版,用于 Vite 等框架的构建优化。
- Rolldown:基于 Rust 的 Rollup 替代品。
这些工具的共同点是:把高频、计算密集、文件操作多的路径从 JavaScript 移到 Rust。它们并不会完全替代 JavaScript 生态,而是作为底层加速器存在。pnpm 12 的价值就在于,它向 Node.js 包管理器这个最基础的环节证明了 Rust 重写的可行性。
如果你正在学习 Rust,或用 pnpm 管理大型 Monorepo,可以先从阅读 pnpm 的源码结构开始,了解它把哪些模块迁移到了 Rust、哪些模块仍然保留 JavaScript 实现。这样既能学习 Rust 在真实项目中的工程实践,也能更深入地理解 pnpm 12 的内部机制。
10.1 Rust 学习与 pnpm 源码阅读路径
如果要阅读 pnpm 源码,可以从以下目录结构入手:
pnpm/ ├── pkg-manager/ │ ├── core/ │ ├── resolve/ │ └── fetch/ ├── store/ │ └── controller/ ├── fs/ │ ├── hard-link-dir/ │ └── indexer/ └── workspace/Rust 重写部分主要聚焦在依赖解析、文件索引和锁文件计算这几个核心模块。读源码时不要一开始就关注命令行的交互逻辑,而要先关注:
- 依赖解析时如何处理版本范围。
- 全局存储中的包如何被引用。
- 锁文件如何比较依赖图是否有变化。
理解这几个核心逻辑后,再看 pnpm 的性能优化思路会清晰很多。