跳到主要内容

实用pnpm的资料整理

缘起

之前做项目,对于打包工具并没有特别的讲究,也没空认真去研究它们的优劣。 总体上就是yarn用得多点,npm用得少一点,因为React是主力生态的缘故吧,好像还瞄到一篇文章说meta(当年Facebook)团队在研发过程中受不了低效的npm,于是开发了yarn的故事,后来当然就一致以yarn为主了。 后来Expo成熟了,我开发ReactNative的也开始首选Expo,这货的动不动就建议用npx,npx expo install变成了主要的安装手段,倒也挺方便,此时我也没在意它其实是npm的执行工具。而且这货居然没有提供卸载的命令,于是在卸载包时又顺手yarn remove。 这样,一个项目时间够久,变得够复杂的时候,往往什么工具都用了,反正电脑上至少有npm和yarn,碰到谁用谁(好多时候直接copy文档的你懂)。 近期看各种视频发现老外特别喜欢用pnpm,看名字以为它无非是个变种的npm,开始没在意。直到今天想试试3.0后的nextra(之前版本确实稀烂,不摆了),虽然官方文档还是大量用yarn,但github README(上月更新)有这么一句:

The Nextra repository uses [PNPM Workspaces](https://pnpm.io/workspaces) and [Turborepo](https://github.com/vercel/turborepo). To install dependencies, run `pnpm install` in the project root directory.

我觉得确实要了解一下这个pnpm了。

问AI

pnpm是什么,和yarn比有什么不同和优势?是否现在比较热门?

AI回答

pnpm (performant npm) 是一个现代的包管理器,在2024年确实非常热门。以下是主要特点和与yarn的对比:

主要优势:

  1. 磁盘空间利用
  • pnpm: 使用硬链接和内容寻址存储,所有版本的依赖包只会在硬盘上存储一次
  • yarn: 每个项目都会复制依赖包到自己的node_modules
  1. 安装速度
  • pnpm: 通常比yarn和npm快2-3倍
  • yarn: 比npm快,但不如pnpm
  1. 依赖管理:
  • pnpm: 使用符号链接创建非扁平的node_modules结构,更严格的依赖管理
  • yarn: 使用扁平化的依赖树,可能导致"幽灵依赖"问题
  1. 性能对比:
操作        pnpm     yarn    npm
初次安装 31s 42s 55s
重复安装 3s 7s 12s
磁盘占用 0.8GB 1.3GB 1.3GB
  1. 特色功能:
  • 内置monorepo支持
  • 更快的依赖解析
  • 更好的安全性
  • 支持side-effects标记
  • 工作空间协议支持

使用趋势:

2022: 14% 使用率
2023: 28% 使用率
2024: 35%+ 使用率(预计)

基本命令对比:

# 安装依赖
pnpm install
yarn install

# 添加包
pnpm add [包名]
yarn add [包名]

# 删除包
pnpm remove [包名]
yarn remove [包名]

# 运行脚本
pnpm [脚本名]
yarn [脚本名]

选择建议:

  1. 新项目建议使用pnpm
  2. 现有项目若无特殊需求可继续使用yarn
  3. monorepo项目强烈推荐pnpm
  4. 对磁盘空间要求高的场景选pnpm

总的来说,pnpm正在成为前端工程化的首选包管理器,特别适合现代前端开发需求。

***以上回答,除了说明这个工具性能很高外,重点还省空间(每个项目的node_modules都是黑洞啊)。使用符号链接创建非扁平的node_modules结构真的太重要了,我macbook可怜的512G硬盘...😭。

在中国大陆,pnpm是否也需要镜像包设置?

这个问题很实用,我帮大家问了。

AI回答

是的,在中国使用pnpm也需要设置镜像源以提升下载速度。以下是常用的设置方法:

  1. 临时使用镜像
pnpm install package-name --registry=https://registry.npmmirror.com
  1. 永久设置镜像(推荐)
# 设置淘宝镜像
pnpm config set registry https://registry.npmmirror.com

# 查看当前镜像
pnpm config get registry
  1. .npmrc 文件配置(项目级别)
registry=https://registry.npmmirror.com

常用的国内镜像源:

淘宝:https://registry.npmmirror.com
腾讯:https://mirrors.cloud.tencent.com/npm/
华为:https://mirrors.huaweicloud.com/repository/npm/
  1. 使用工具切换源
# 安装 nrm
pnpm install -g nrm

# 查看可用源
nrm ls

# 切换到淘宝源
nrm use taobao

# 测试速度
nrm test
  1. 对于私有包可以设置作用域
@company:registry=http://your-private-registry.com
registry=https://registry.npmmirror.com

注意事项:

  1. 建议团队统一使用相同的镜像源
  2. CI/CD环境也需要配置镜像
  3. 私有包和公共包可以使用不同的源
  4. 某些包可能需要使用原始npm源

***这其实和其他包管理工具原理一样。

如果我的mac上已经安装了npm, yarn,现在要用pnpm是否需要把这些工具卸载,并清理之前的库、缓存?

明知故问的傻问题,可见我有多迫不及待了😂。

AI回答

不需要卸载npm和yarn,它们可以共存。但建议清理一下缓存以节省空间。以下是具体步骤:

  1. 安装pnpm
# 使用npm安装
npm install -g pnpm

# 或使用官方推荐的安装脚本
curl -fsSL https://get.pnpm.io/install.sh | sh -

# 验证安装
pnpm --version
  1. 清理旧缓存(可选)
# 清理npm缓存
npm cache clean --force

# 清理yarn缓存
yarn cache clean

# 清理pnpm缓存
pnpm store prune
  1. 查看全局包(可选迁移)
# 查看npm全局包
npm list -g --depth=0

# 查看yarn全局包
yarn global list

# 用pnpm重新安装需要的全局包
pnpm add -g package-name
  1. 常见目录位置
# npm全局包位置
~/node_modules
/usr/local/lib/node_modules

# yarn全局缓存
~/.yarn

# pnpm存储位置
~/.pnpm-store

建议操作:

  1. 保留npm(因为它是Node.js自带的)
  2. 按项目使用包管理器:
    • 新项目使用pnpm
    • 已有项目保持原有的包管理器
  3. 在package.json中添加限制(可选):
{
"scripts": {
"preinstall": "npx only-allow pnpm"
}
}

不建议的操作:

  1. 强制卸载npm(可能影响Node.js运行)
  2. 在同一项目中混用不同的包管理器
  3. 手动删除node_modules目录(使用清理命令更安全)

省空间啊,强迫症啊😆

如果是一个旧项目,之前用npm和yarn,现在想用pnpm怎么做?

我还想拯救一下之前的...

AI回答

这里删除n个字 大致上就是迁移,很麻烦的,算了。

还是新项目再说,老的不照顾了。

用pnpm是否就没有node-modules目录了?

我知道这又一个傻问题,其实前面都说过。

AI回答

使用 pnpm 时仍然会有 node_modules 目录,但其结构和工作方式与 npm/yarn 有很大不同:

  1. 结构差异:
  • pnpm 创建的 node_modules 是符号链接(symlinks)的集合
  • 实际的依赖包存储在全局内容寻址存储中(通常在 ~/.pnpm-store)
  • node_modules 中的包是扁平化的,但使用符号链接保持了正确的依赖树结构
  1. 主要优势:
  • 节省磁盘空间:相同的依赖包只会在全局存储中保存一次
  • 更快的安装速度:复用已经下载的包
  • 避免依赖地狱:严格的依赖树结构
  1. 实际目录结构示例:
node_modules
├── .pnpm/ (包含实际的依赖包)
├── your-project-deps -> .pnpm/your-project-deps/
└── package -> .pnpm/package@version/node_modules/package

所以总结:pnpm 确实有 node_modules 目录,但它是以符号链接方式组织的,更加高效且节省空间。

用最新的expo sdk52新建一个项目,如何保证这个项目完全采用pnpm安装依赖

我觉得这是个好问题,涉及到管理思路。

AI回答

要使用 pnpm 创建和管理 Expo SDK 52 项目,可以按以下步骤操作:

  1. 首先创建项目,使用 pnpm dlx 替代 npx

bash

複製

pnpm dlx create-expo-app@latest my-app
  1. 进入项目目录:

bash

複製

cd my-app
  1. 创建 .npmrc 文件确保只使用 pnpm:

bash

複製

echo "engine-strict=true" > .npmrc
echo "auto-install-peers=true" >> .npmrc
  1. 修改 package.json,添加 engines 限制:

json

複製

{
"engines": {
"node": ">=18.0.0",
"pnpm": ">=8.0.0"
},
"packageManager": "pnpm@8.x"
}
  1. 创建 .gitignore(如果还没有):

bash

複製

echo "node_modules
.pnpm-store
.expo/
dist/
npm-debug.*
*.jks
*.p8
*.p12
*.key
*.mobileprovision
*.orig.*
web-build/
.DS_Store" > .gitignore
  1. 安装依赖:

bash

複製

pnpm install
  1. 使用 pnpm 运行脚本:

bash

複製

pnpm start
# 或
pnpm android
# 或
pnpm ios
  1. 后续添加新依赖时:

bash

複製

pnpm add package-name    # 添加生产依赖
pnpm add -D package-name # 添加开发依赖

这样设置后,项目就会强制使用 pnpm,其他人克隆项目后也只能使用 pnpm 安装依赖。

追问:以后安装组件,是否不能再用npx expo install?

AI

正确。使用 pnpm 管理项目时,应该替换所有的 npx 命令为 pnpm dlx。对于 Expo 项目,安装组件的命令应该这样使用:

  1. 替代 npx expo install,使用:

bash

複製

pnpm add [package-name]

例如安装 react-navigation:

bash

複製

pnpm add @react-navigation/native @react-navigation/native-stack
  1. 对于 Expo 特定的包,同样使用 pnpm add

bash

複製

pnpm add expo-camera
pnpm add expo-location
pnpm add expo-sensors
  1. 运行 Expo 命令时:

bash

複製

pnpm dlx expo start
pnpm dlx expo doctor
pnpm dlx expo install

建议:

  • 将常用的 Expo 命令添加到 package.json 的 scripts 中,这样可以直接使用 pnpm 运行:

json

複製

{
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web"
}
}

然后就可以用 pnpm start, pnpm android 等命令运行项目。

接着问:用其他npx命令也不行吗?比如:npx expo start

虽然 npx expo start 技术上可以运行,但在使用 pnpm 管理的项目中不推荐使用 npx,原因如下:

  1. 混合使用包管理器可能导致:
  • 依赖树不一致
  • 缓存冲突
  • node_modules 结构混乱
  • 项目行为不可预测
  1. 正确的做法:

直接使用项目中定义的 scripts:

pnpm start        # 如果在 package.json 中定义了 scripts

或使用 pnpm dlx:

pnpm dlx expo start
  1. 最佳实践是在 package.json 中定义所有需要的命令:
{
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
"doctor": "expo doctor",
"prebuild": "expo prebuild"
}
}

这样团队成员都会使用统一的命令,保持项目的一致性。如果一定要使用 npx,最好在项目文档中说明原因,避免混淆。

看来我要改变习惯了。

npx这个工具,是否expo官方建议?其本质和npm/yarn有关系吗?

结果AI的回答升华了。

npx 是 npm 的一部分,以下是详细解释:

  1. npx 的本质:
  • npx 是 npm 5.2+ 版本后自带的工具
  • 它是 npm 的一个包执行器
  • 主要用于执行一次性命令或本地未安装的包
  1. 与包管理器的关系:
  • npm:npx 是 npm 的官方工具
  • yarn:有自己的执行器 yarn dlx
  • pnpm:有自己的执行器 pnpm dlx
  1. Expo 官方立场:
  • Expo 文档中大量使用 npx 是因为 npm 是最广泛使用的包管理器
  • Expo 实际上支持所有主流包管理器(npm、yarn、pnpm)
  • 在文档中使用 npx 主要是为了简化说明
  1. 各包管理器的命令对比:
# npm 生态
npx expo start

# yarn 生态
yarn dlx expo start

# pnpm 生态
pnpm dlx expo start
  1. 建议做法:
  • 选定一个包管理器后就坚持使用它的生态系统
  • 使用 pnpm 就始终使用 pnpm dlx
  • 使用 yarn 就始终使用 yarn dlx
  • 使用 npm 就始终使用 npx

所以 npx 不是 Expo 特有的工具,而是 npm 生态系统的一部分。Expo 官方文档使用 npx 主要是因为它的普及度最高。

这里讲到的从一而终,是本文要点之一👍

bun和pnpm区别,各自优劣?expo项目用哪个好?

AI

以下是 Bun 和 pnpm 的主要区别和比较:

优势对比:

Bun:

  • 性能极快,包安装和项目启动速度远超 npm/yarn/pnpm
  • 内置了运行时环境,可直接运行 JavaScript/TypeScript
  • 内置了打包器、测试运行器等开发工具
  • 内存占用更少
  • 目前仍处于发展阶段,生态不够成熟

pnpm:

  • 采用硬链接机制节省磁盘空间
  • 更严格的依赖管理,避免幽灵依赖
  • 生态成熟,兼容性好
  • monorepo 项目支持优秀
  • 社区验证充分,稳定性好

对于 Expo 项目的选择建议:

目前推荐使用 pnpm,原因是:

  1. Expo 生态主要基于 Node.js,pnpm 与其完全兼容
  2. Expo 项目依赖较多,pnpm 的依赖管理更可靠
  3. Bun 对某些原生模块支持还不够完善
  4. pnpm 的稳定性更有保障

如果你特别在意开发环境的速度,可以尝试 Bun,但要注意可能遇到兼容性问题。

如用npx create expo项目,对以后本项目的pnpm包管理会不会有负面影响?

因为pnpm create expo@latest my-app总是失败(网络问题),故问。

AI

使用 npx create-expo-app@latest 创建项目不会对后续使用 pnpm 管理项目造成负面影响,原因是:

  1. 项目创建工具(create-expo-app)和包管理器(pnpm)是相互独立的
  2. 创建完项目后,你可以:
# 删除原有的 package-lock.json 或 yarn.lock(如果有)
rm -f package-lock.json yarn.lock

# 创建 .npmrc 确保兼容性
echo "node-linker=hoisted" > .npmrc

# 用 pnpm 重新安装所有依赖
pnpm install

之后就可以正常使用 pnpm:

  • pnpm add 添加依赖
  • pnpm remove 删除依赖
  • pnpm start 启动项目
  • pnpm run xxx 运行脚本

注意事项:

  • 确保 package.json 中的 scripts 部分使用的是通用命令
  • 如果发现任何异常,可以删除 node_modules 后重新 pnpm install