从 Yarn 或 npm 迁移到 pnpm 的详细步骤及问题解决方案

1,422 阅读5分钟

pnpm 是一个现代的包管理器,它旨在提供更快的安装速度和更小的磁盘占用。与 npmyarn 相比,pnpm 通过其独特的符号链接结构(node_modules 中的非扁平化结构)和内容寻址存储来优化依赖管理。如果你正在使用 npmyarn,并考虑迁移到 pnpm,以下是详细的步骤以及解决潜在问题的方案。

1. 安装 pnpm

首先,你需要全局安装 pnpm。推荐使用以下几种方式之一:

  • 使用 npm 或 yarn (如果已安装):

    npm install -g pnpm
    # 或者
    yarn global add pnpm
    
  • 使用独立脚本 (推荐):

    • 对于 POSIX 系统 (Linux, macOS):
      curl -fsSL https://get.pnpm.io/install.sh | sh -
      
    • 对于 Windows (PowerShell):
      iwr https://get.pnpm.io/install.ps1 -useb | iex
      

    安装后可能需要重启终端或配置 PATH。

  • 使用 Corepack (Node.js >= 16.9 自带):

    corepack enable
    corepack prepare pnpm@latest --activate # 或者指定版本
    

    此后,在有 package.jsonpackageManager 字段指定了 pnpm 的项目中,pnpm 命令会自动生效。

2. 准备项目进行迁移

在开始迁移之前,建议:

  1. 备份你的项目,特别是 package.json 和锁文件(package-lock.jsonyarn.lock)。
  2. 清理旧的依赖和锁文件:为了确保干净的迁移,可以删除 node_modules 文件夹和旧的锁文件。
    rm -rf node_modules
    rm -f package-lock.json yarn.lock
    

3. 初始化 pnpm (如果需要)

如果你的项目还没有 package.json 文件,可以在项目根目录下运行以下命令来初始化 pnpm 并创建 package.json

pnpm init

如果项目中已经有 package.json 文件,此步骤可以跳过。pnpm 会使用现有的 package.json

4. 迁移依赖和锁文件

pnpm 提供了 import 命令,可以直接从 npmyarn 的锁文件生成 pnpm-lock.yaml。这是推荐的迁移方式,因为它会尝试保持与原锁文件尽可能一致的依赖版本。

在你的项目根目录下运行:

pnpm import

此命令会自动检测项目根目录下的 package-lock.json (来自 npm) 或 yarn.lock (来自 Yarn),并基于它们生成 pnpm-lock.yaml 文件。

5. 安装依赖

执行 pnpm import 后,你已经拥有了 pnpm-lock.yaml。现在,运行以下命令来实际安装所有依赖项:

pnpm install

pnpm 会根据 pnpm-lock.yamlpackage.json 来安装依赖到 node_modules 目录。

6. 验证和测试

迁移完成后,务必:

  1. 检查 pnpm-lock.yaml 是否已生成。
  2. 运行项目的测试套件,确保所有功能正常。
  3. 本地启动项目,进行手动测试。

7. 解决版本锁定和迁移问题

迁移过程中,由于 pnpm 的依赖解析策略(特别是对 peer dependencies 的处理)可能与 npmyarn 不同,可能会遇到一些问题。

  1. 依赖版本不一致或缺失

    • pnpm import 旨在最大限度地保留原有版本,但有时细微差异可能导致问题。
    • 检查 pnpm 的输出,特别是关于 peerDependencies 的警告。pnpmpeerDependencies 的处理更为严格,可能需要你在 package.json 中显式安装一些之前被隐式满足的对等依赖。
    • 使用 pnpm listpnpm why <package-name> 来查看依赖树,确定版本冲突的来源。
    • 如果某个特定包的版本确实需要调整,可以在 package.json 中手动指定版本范围,然后运行 pnpm install
  2. 使用 pnpm.overrides 解决版本冲突: 如果需要强制指定某个间接依赖的版本,可以在 package.json 中使用 pnpm.overrides 字段(类似于 yarnresolutions):

    // package.json
    {
      "pnpm": {
        "overrides": {
          "some-dependency": "^1.2.3", // 强制 some-dependency 使用 1.2.3 或更高兼容版本
          "another-package>sub-dependency": "2.0.0" // 强制 another-package 下的 sub-dependency 使用 2.0.0
        }
      }
    }
    

    修改后运行 pnpm install

  3. 清理并重新安装: 有时,彻底清理并重新安装可以解决一些缓存或状态问题:

    rm -rf node_modules pnpm-lock.yaml
    pnpm import  # 如果你还保留着旧的 lock 文件并且想重新导入
    pnpm install
    

    或者,如果 pnpm-lock.yaml 已经基于 pnpm import 生成且你认为它是正确的,只是安装出了问题:

    rm -rf node_modules
    pnpm install
    

8. 常见问题的解决方案

问题:迁移后脚本运行失败

解决方案

  • 检查 package.json 中的 scripts 部分。将所有 npm runyarn 命令替换为 pnpm
    • 例如:"dev": "npm run start" 应改为 "dev": "pnpm run start" (或更简洁的 "dev": "pnpm start")。
    • yarn test 应改为 pnpm test
  • pnpm 默认不会像 yarn (v1) 那样自动运行 prepost 钩子脚本,除非明确配置。如果你的脚本依赖这些,可能需要调整。

问题:某些依赖无法找到或安装失败

解决方案

  • 检查错误信息:仔细阅读 pnpm install 输出的错误信息,通常会指示问题所在。
  • Peer Dependencies:如上所述,pnpmpeerDependencies 更严格。你可能需要手动安装项目中其他包声明的 peerDependenciespnpm add <peer-dependency-package>
  • 特定编译工具:某些包可能需要 Python、C++ 编译器等构建工具。确保你的开发环境已配置好。
  • 网络问题:尝试切换 npm registry 或检查网络连接。pnpm 默认使用官方 npm registry。你可以通过 .npmrc 文件配置:
    registry=https://registry.npmmirror.com/
    
  • 运行 pnpm doctor:此命令可以检查项目配置中的一些常见问题。

问题:全局安装的包与 pnpm 使用习惯

解决方案

  • 如果你之前使用 npm install -g <package>yarn global add <package> 安装全局工具,现在应使用 pnpm add -g <package>
  • pnpm 管理的全局包通常位于 ~/.pnpm-store/v3/ 相关目录,并符号链接到 pnpm 的全局可执行文件路径下。确保 pnpm 的全局路径已添加到你的系统 PATH。安装 pnpm 时通常会自动处理。

结论

迁移到 pnpm 可以为你的项目带来显著的性能提升和磁盘空间节省。通过 pnpm import 命令,迁移过程通常很平滑。关键在于迁移后仔细测试,并理解 pnpm 在依赖解析(特别是 peerDependencies)上可能存在的细微差异。如果在迁移过程中遇到任何问题,查阅 pnpm 的官方文档或在社区寻求帮助总是一个好主意。