
最近后台收到好几个朋友私信说电脑磁盘突然被塞满了一查发现 C 盘飘红打开工具一看好家伙光 pnpm 相关的目录就占了几十 GB。还有人遇到“pnpm 不是内部或外部命令”的报错装完用不了问是不是环境变量没配好。其实这些问题背后大多是同一件事pnpm 的存储位置没有被统一管理。我自己的机器以前也是这个状态项目开得越多磁盘空间越紧张。后来花了一晚上把 pnpm 的 store 整体迁移、配置统一、顺带把全局 bin 目录也挪到了独立硬盘上之后空间焦虑基本就消失了。这篇就把整个过程以及这背后的原理、各种坑一次讲清楚。1. pnpm 为什么会“吃”掉这么多磁盘空间1.1 先搞懂 store、硬链接和软链接很多人一直没搞明白 pnpm 和 npm、yarn 到底差在哪。npm 和 yarn 传统安装模式是把每个包原样下载一份到当前项目的 node_modules 里10 个项目用了同一个依赖磁盘上就有 10 份拷贝。pnpm 的设计思路完全不同它引入了一个全局的内容寻址存储也就是 pnpm store依赖包第一次下载后只会存一份之后所有项目都通过硬链接或者符号链接指向这台“仓库”里的同一份文件。这里最核心的概念是硬链接。你可以把硬链接理解成同一个文件在磁盘上的多个“门牌号”不管从哪个门牌号进去改的都是同一块数据区域。创建硬链接几乎不占额外空间只是多了一个目录项。pnpm 在项目的 node_modules 里面放的就是这样一个一个硬链接真正占磁盘的是全局 store 里那一份原始文件。这意味着如果两个项目依赖同一个 lodash磁盘上的 lodash 只有一份而不是两份。符号链接则是另外一回事它保存的是文件路径pnpm 在组织复杂依赖关系时也会用到。不过我们日常排查磁盘占用先抓住“硬链接共享文件、store 存真货”这个概念就够了。1.2 磁盘空间都去哪了三个典型场景道理都懂为什么实际使用中 store 还是越来越大把硬盘撑爆根据我自己的经验常见原因有三个。第一pnpm 的 store 是一个内容寻址仓库每个依赖包都会有完整的版本记录而且默认不会自动清理旧版本。你升级一次依赖、跑一次 pnpm install下载的每个版本都会留存在 store 里。时间一长几十个项目的所有历史版本叠在一起总量自然膨胀。我见过一个同事的 store 干了 40 多 GB里面躺着大量早就没人在用的老版本。第二新起项目时很多人直接pnpm install这样依赖会重新下载并写入默认 store 位置。如果是 Windows默认路径通常是 C 盘的AppData\Local\pnpm下面如果是 Linux一般是~/.local/share/pnpm/store。C 盘本来系统、软件、缓存就占了大量空间再把所有项目的依赖中转站放这里爆盘几乎只是时间问题。第三用户对硬链接存在一个常见的误操作。有人觉得“既然 node_modules 里是硬链接那我直接把整个项目文件夹复制到新硬盘上应该也不占什么空间吧”结果复制完成后发现磁盘占用翻倍了。原因很简单硬链接是文件系统层面的关系一旦复制到另一个文件系统或者分区硬链接关系就无法保留系统只能老老实实复制真实文件内容store 那份、node_modules 那份各算各的空间反而变得更占地方。把这些机制搞清楚之后你就会明白解决 pnpm 磁盘焦虑的根本思路不是删掉 node_modules 那么简单而是要管理好那个全局 store 的位置和体积。2. 动手前先摸清你机器上的 pnpm 存储分布2.1 怎么查看当前 store 在哪不要凭感觉猜直接用命令看。在任意终端执行pnpm store path正常情况下会输出当前 store 的绝对路径。不同操作系统、不同 pnpm 版本的默认路径不完全一样但 pnpm 自己会给出准确答案这是后续所有操作的第一参考。还有一种情况如果你配置过环境变量PNPM_STORE_DIR或者项目里写了.npmrc输出结果可能和你预想的不一致。所以一定要以这条命令的实际输出为准。顺便推荐几个辅助查看磁盘占用的命令Linux/macOS 上可以看 store 目录有多大du -sh $(pnpm store path)Windows 上可以用 PowerShell 统计$storePath pnpm store path | Select-Object -Last 1 Get-ChildItem $storePath -Recurse | Measure-Object -Property Length -Sum注意 Windows 上pnpm store path可能会输出多行说明文字所以要取最后一行真正的路径上面命令里这几行处理就是这个目的。2.2 判断 node_modules 里到底是不是硬链接知道 store 在哪之后还有一个常见疑问当前项目的 node_modules 到底是不是真的用了硬链接有时候配置被全局.npmrc干扰实际用的可能还是复制模式导致磁盘占用飙升。Windows 上可以用fsutil查看某个文件的硬链接数量fsutil hardlink list .\node_modules\lodash\lodash.js如果命令行环境不允许也可以用 PowerShell 加 Windows API 查看。macOS 和 Linux 上更简单直接看文件链接数ls -l node_modules/.pnpm/node_modules/lodash/lodash.js链接数如果大于 1说明 store 里和 node_modules 里确实共享同一份数据。如果等于 1那大概率是复制模式或者硬链接创建失败磁盘占用会远高于预期。判断完现状接下来才考虑怎么改、怎么迁移。这里我多说一句很多人第一步就踩坑直接rm -rf node_modules然后重装。不是说不行但如果你真正的痛点是 C 盘空间不够删 node_modules 只是暂时解决问题下次 install 又会把 store 塞回 C 盘。一定要从 store 位置入手。3. 统一存储位置全局配置与迁移方案3.1 修改全局 store-dir 的两种方式pnpm 提供了store-dir配置项修改方式有很多最推荐的是写到用户级配置文件里。执行下面的命令pnpm config set store-dir D:\pnpm-store这个命令会把配置写入用户的.npmrc文件位置一般在用户目录下面。Windows 上也可以直接编辑C:\Users\你的用户名\.npmrc手动加一行store-dirD:\pnpm-store如果你更习惯用环境变量也可以设置PNPM_STORE_DIR效果接近但要注意环境变量和配置文件的优先级关系避免两边写了不同的路径产生混乱。我的习惯是能用配置文件解决的就不要引入环境变量因为环境变量的传播范围对你的所有终端都生效很容易误伤其他工具链。验证配置是否生效重新打开一个终端然后执行pnpm store path如果输出的是你新设置的路径说明全局配置已经生效了。这里要特别提醒只改配置不会把旧 store 里的文件自动搬过去。下次 install 时 pnpm 会重新开始一个新的内容寻址存储老 store 里的几十 GB 文件依然占着老位置。所以完整操作不能少了迁移这一步。3.2 新建内容寻址存储的“冷启动”与“热迁移”迁移 pnpm store 有两种情况一种是还没形成大量缓存的新机器直接改配置冷启动就行另一种是已经积累了海量缓存的机器必须做热迁移。所谓热迁移就是把现有 store 目录整体搬到新位置同时改好配置让 pnpm 的硬链接关系不中断。因为硬链接是文件系统层面的特性如果你只是新配置一个空目录所有项目的 node_modules 还需要重新安装下载量非常可观。迁移前先把开发服务器和可能占用 Node 进程的终端关掉Windows 上尤其注意store 目录里有文件被占用时移动会失败或者复制出来的文件不完整。然后执行以下操作。Windows 下推荐用 robocopy 移动目录比move命令稳定处理超长路径也更好robocopy C:\Users\你的用户名\AppData\Local\pnpm\store D:\pnpm-store /E /MOVE注意 robocopy 的/MOVE会在复制完成后删除源目录里的文件如果不想删源文件可以去掉/MOVE改成下面两步手动确认复制完毕再删。macOS 和 Linux 上用 mv 就行mv ~/.local/share/pnpm/store /data/pnpm-store迁移完成后再执行一次pnpm config set store-dir把路径指向新位置然后随便进一个项目跑pnpm install确认没有报错依赖安装正常。这里说个我的习惯迁移后第一次 install 不要加--frozen-lockfile让它重新校验一下 store 里的内容完整性顺便更新 lock 文件里的引用信息后面装起来会更顺。有些朋友会直接图省事删掉旧 store 重来比如旧 store 里的包都是老版本项目 lock 文件锁的也都是这些版本删掉之后一旦某些老版本下载失败整个项目就没法安装了。除非你完全不心疼重新下载的时间否则我不建议这种操作。4. 多盘符、多项目、多人共用 store 的实战配置4.1 单机多盘符方案把“大仓库”放在大容量盘上实际开发中我见过很多前端项目同时维护五六个仓库每个仓库 node_modules 加起来都不小。如果所有 store 都压在系统盘 C 盘哪怕你配置得再统一C 盘照样会越用越满。更好的方案是把 store 整个迁移到容量充足的数据盘比如 D 盘或者挂载的独立 SSD 上。这样做的好处非常明显。新项目安装依赖时pnpm 直接从本地 store 做硬链接几乎是秒级完成不消耗网络流量。多个项目之间共享的依赖也不会重复占空间。我的机器上 store 现在放在一块单独的 SSD 上占用 20 多 GB但所有项目的 node_modules 加起来看起来也很大实际上真实磁盘只增加了 store 这一份体积。有人会问node_modules 里全是硬链接那我把整个项目目录拷贝到移动硬盘时是不是就会失效对没错。这也是我一直强调“存储位置统一”的原因之一。硬链接依赖同一分区、同一文件系统项目换个盘硬链接就断了。如果你的项目需要在多台机器、多个磁盘之间流转可以考虑在项目根目录放一个.npmrc里面写清楚store-dir的预期位置配合脚本自动检测当前机器上有没有对应路径减少误操作。4.2 项目级 .npmrc 与团队统一团队协作场景里最怕的是每个人 pnpm 配置都不一样有人把 store 放 C 盘有人可能在项目里偷偷改过 .npmrc导致团队里总有人的磁盘先爆。我的做法是在团队文档里约定一套统一的环境变量和配置文件模板关键的几项包括store-dirD:\pnpm-store registryhttps://mirrors.cloud.tencent.com/npm/registry 换成境内镜像源之后首次下载依赖的速度会明显提升大型依赖多的项目这点尤其明显。再配合前面说的统一 store-dir团队成员之间还能共享下载缓存。当然这条路的前提是大家都不乱改全局配置。如果是 monorepo 项目pnpm 还支持通过pnpm-workspace.yaml统一管理多个子包的依赖关系这种场景下更要保证 store 位置一致不然每个子包去访问不同 store不光磁盘浪费安装速度也会变慢。4.3 CI/服务器上的 store 缓存策略除了本地开发机器CI 服务器上跑构建任务时store 策略也很关键。如果你每次构建都用全新环境那 pnpm 每次都会把所有依赖重新下载一遍构建速度慢不说CI 机器的磁盘也会被多次构建的缓存堆满。比较成熟的做法是CI 里把 pnpm store 目录单独挂载为持久化缓存目录例如在 .gitlab-ci.yml 或者 GitHub Actions 的缓存配置里把pnpm store path指向的目录加入 cache 列表。这样每次构建时直接复用 store 里的内容新版本依赖只需要增量下载。npm、yarn 的缓存策略也可以类似设置但 pnpm 的统一 store 天生更适合做这种缓存复用因为它的内容寻址特性保证了不会有多余重复。这里再提一个容易被忽略的小细节CI 上跑pnpm install时如果 package.json 里的packageManager字段指定了 pnpm 版本最好和本地开发保持一致否则可能出现 lock 文件格式不兼容的报错。统一版本管理后store 缓存命中率也会更高。5. 常见报错与排查心得5.1 “pnpm 不是内部或外部命令”怎么处理这个热词经常出现在搜索榜上而且反复出现。大多数情况下不是你安装失败而是 pnpm 的可执行文件目录没有加入系统 PATH 环境变量。pnpm 官方推荐的安装方式是通过 npm 全局安装也可以使用 Corepack、Scoop、Homebrew甚至直接下载独立可执行文件。无论哪种方式最终都会在某个目录下生成 pnpm 命令你要确保这个目录在 PATH 中。Windows 上如果你用 npm 全局安装 pnpm目录通常是C:\Users\你的用户名\AppData\Roaming\npm如果这个路径不在 PATH 里打开命令提示符输入 pnpm 就会报“不是内部或外部命令也不是可运行的程序”。在 PowerShell 里还会出现那句经典的“无法将 pnpm 项识别为 cmdlet、函数、脚本文件或可运行程序的名称”。解决办法就是手动把上面的目录添加到系统环境变量 Path 中然后重开终端验证。如果你希望连 pnpm 本身也放到数据盘体验更好可以设置PNPM_HOME环境变量指向一个非系统盘目录比如D:\pnpm-home然后把该目录加入 PATH。这样做的好处有两个一是 pnpm 程序本体和 store 都迁出 C 盘系统盘空间更宽裕二是以后用pnpm add -g安装的全局工具都会集中到这个目录不会散落在系统盘各处。5.2 下载失败、源问题和 Node 版本报错搜索热词里也出现了“腾讯 pnpm 的源”可见很多人确定下载依赖太慢希望通过切换镜像源解决。修改 registry 的方式前面已经提过在用户级.npmrc里加一行就行registryhttps://mirrors.cloud.tencent.com/npm/如果之前下载失败留下了不完整的缓存改完源之后还是反复报错可以执行pnpm store prune它会清理 store 中不再被任何项目引用的孤立包数据。注意这条命令不会删除正在被项目引用的包所以执行起来是安全的。如果项目安装还是失败再尝试删除项目里的node_modules和锁文件重新安装但先备份锁文件避免解析结果发生变化。另一个高频报错是error: this version of pnpm requires at least node.js v22.13 the current ver...这种报错说明你本机的 Node.js 版本太老安装的 pnpm 版本已经要求更高的 Node 运行时。解决办法有两条路升级 Node.js或者降级安装和当前 Node 匹配的 pnpm 版本。个人建议尽量去升级 Node不仅为了 pnpm其他工具链对新版本 Node 的兼容性也在逐渐提升留在老版本上迟早还会遇到问题。降级 pnpm 属于临时救急时间长了会积累更多版本错位的坑。run pnpm approve-builds to pick which dependencies should be allowed to ru...这类提示在较新版本的 pnpm 上很常见原因是安全策略收紧默认不执行依赖包的安装脚本需要你手动批准哪些依赖允许执行。不是报错按提示运行后面的命令并选择允许的依赖就行。还有一个同类警告形如the pnpm field in package.json is no longer read by pnpm这说明项目还在用旧版配置格式把 pnpm 的配置写在了 package.json 里。新版 pnpm 已经把配置移到了pnpm-workspace.yaml你只需把原来 package.json 里的pnpm.overrides等字段转移过去警告就会消失。5.3 store 清理与“删除 pnpm”的完整姿势搜索热词里有“删除pnpm”一般两种诉求一种是彻底卸载 pnpm比如不再使用这个工具了另一种只是想删掉缓存缓解磁盘压力。如果是后者我不建议直接删整个 store因为先删掉 store 再跑项目所有依赖都要重新下载一遍体验极差。先跑一下pnpm store prunepnpm store prune它会删除所有没有被项目引用的孤儿包。如果你的磁盘实在不够还可以检查一下项目里有没有多余的node_modules副本不对的就说实话。比如有些项目用了 pnpm 却没有配置统一 store可能在多个盘上留下了多个 store 副本都需要逐个清理。真要卸载 pnpm需要区分安装方式。如果是npm i -g pnpm安装的用npm uninstall -g pnpm卸载如果是 Corepack可以用corepack disable之类的命令。Windows 上还要记得清理PNPM_HOME指向的目录以及它在 PATH 中留下的残留路径否则终端重启后可能还会找到旧的 pnpm 命令造成“删了但还能用”的诡异现象。还有个隐藏点Windows 上 pnpm 可能通过符号链接在项目里创建了一些目录这些链接文件本身不会占用太多空间但如果你用文件管理器直接复制项目目录可能把符号链接当成真实文件复制产生意料之外的大量数据。我处理这类问题时通常优先用命令行工具复制项目再单独重建硬链接关系而不是把整个目录拖来拖去。5.4 几个相对冷门但实用的 check 项Linux 离线安装 pnpm准备好 pnpm 的 standalone 压缩包解压后放到/usr/local/bin或用户bin目录再执行pnpm setup完成环境变量初始化不依赖 npm。离线机器上安装时还要提前把 store 目录整个打包带过去否则依赖还是装不了。注意 pnpm 和 npm 的原生差异npm 的缓存目录和 pnpm 的 store 目录不是一回事互不影响。有些人会用npm cache clean --force来释放空间对 pnpm store 完全无效别白费力气。pnpm 版本更新后store 目录结构如果有调整旧版本创建的 store 可能无法被新版本直接复用。此时旧 store 在新版本下的pnpm install过程中可能需要整体重建。遇到过的话重新安装依赖即可不要手动去改 store 目录里的 json 文件结构。6. 迁移之后的日常维护与我的小技巧store 统一放到数据盘之后日常维护仍然不能完全“零成本”。我给自己定了一个就近检查周期每过一两个月会跑一次pnpm store prune同时用du或者 Windows 的资源监视器看一眼 store 的体积变化。这一步能及早发现异常增长比如某个大版本依赖被反复安装或者某个仓库反复切换分支导致 store 里堆积了大量中间版本。另一个比较实用的小技巧是把 store 目录加入杀毒软件的白名单。Windows Defender 实时扫描如果每访问一个硬链接文件就检查一遍磁盘会让 pnpm install 明显变慢把D:\pnpm-store这类路径加入排除项后安装速度会有肉眼可见的提升。这个操作仅针对 store 目录不要盲目排除整个磁盘否则安全上得不偿失。如果你是团队里负责搭建设备环境的人建议把这套流程沉淀成脚本文档一台新电脑过来先改 store-dir、再迁移旧数据、最后配置 PATH十分钟之内搞定环境。现实里很多“装完 pnpm 用不了”“磁盘又满了”的问题都是少了这个流程里的某一步。我自己现在所有项目都跑在这一套统一的 pnpm 存储方案下C 盘再也没因为 node_modules 和依赖缓存飘红过。每次看到那些还在为磁盘空间苦恼的人我都会建议他们先看一眼 store 在哪、有多大。很多时候问题就是这样一句话就能点破的。