pnpm 安装后 node_modules 是什么结构?为什么 webpack 不识别 pnpm 安装的包?

本篇研究:使用 pnpm 安装依赖时,node_modules 下是什么结构


回顾

npm@3 之前:依赖树

缺点:

  • frequently packages were creating too deep dependency trees, which caused long directory paths issue on Windows
  • packages were copy pasted several times when they were required in different dependencies

npm@3 和 yarn:扁平化

缺点:

  • modules can access packages they don't depend on
  • the algorithm of flattening a dependency tree is pretty complex

测试 pnpm 效果

yalc

为了方便看效果,我打算自己建几个 npm 包测试。

我并不想真的发布 npm 包,所以使用 yalc 模拟。折腾了一番,成功用yalc 发布、安装 lib 后,发现自己的行为很愚蠢。。。因为使用这个 lib 时,要用 yalc add xxx 来安装,安装的逻辑是 yalc 的逻辑,不是 pnpm 的。所以这种方法不能测试出 pnpm 安装包的效果!STUPID!!!

还是老实发布 lib 吧

publish library

注册

去 npm 官网注册账号

登录

在 cmd 中登录 npm login。登录失败,报403。

google 后修改 npm registry:npm config set registry http://registry.npmjs.org/。再次登录仍然失败,报426。

google 后说是 node 版本过老,但是我升到最新版也没用。折腾一番发现是 registry 不能用 http,要用 https。修改 npm config set registry https://registry.npmjs.org/。再次登录,成功。

发布 lib

新建文件夹 lib-c,初始化 npm init -y

新建 index.js:

js 复制代码
const str_c = "c";
module.exports = { str_c };

发布时 lib 的名称是由 package.json 中的 name 字段规定的。加个前缀防止重名:

js 复制代码
  "name": "lilytest-lib-c",	

发布 npm publish

按照这个方法创建三个包 a b c并发布,依赖关系为:a依赖b,b依赖c,c无依赖

test-project

新建文件夹 test-project,npm init -y

安装 a pnpm i lilytest-lib-a

node_modules/lilytest-lib-a 为例说明。它是一个链接,真实路径为 .pnpm/[email protected]/node_modules/lilytest-lib-a。使用 dir 可以看到:

安装 a 和 b:

和之前相比,只多了 node_modules/lilytest-lib-b,链接到 .pnpm/[email protected]/node_modules/lilytest-lib-b

总结

结合官网说明,总结一下 pnpm 的安装流程:

第一步:在 .pnpm 下安装真实依赖

在 .pnpm 下安装所有 package,无论直接、间接、间间接、间间间接、间间间...接的。放在.pnpm/<name>@<version>/node_modules/<name>中。这些是 node_modules 下唯一的"真实"文件

解释一下:为什么最后还要多套一层 node_modules?

  • allow packages to import themselves. foo should be able to require('foo/package.json') or import * as package from "foo/package.json".
  • avoid circular symlinks. Dependencies of packages are placed in the same folder in which the dependent packages are. For Node.js it doesn't make a difference whether dependencies are inside the package's node_modules or in any other node_modules in the parent directories.
第二步:在 .pnpm 下链接依赖

比如,将 .pnpm/a/node_modules 下的 b 链接到 .pnpm/b/node_modules/b:

将 .pnpm/b/node_modules 下的 c 链接到 .pnpm/c/node_modules/c:

第三步:在 node_modules 下链接直接依赖

将 node_modules 下的 a 和 b 链接到 .pnpm 下对应位置

参考阅读:


old-school webpack

本篇文章的起因就是 webpack 不认 pnpm 的路径,终于说回这个问题了。

webpack Problems with pnpm and the way loaders are resolved

We have issues in lots of applications because webpack can't resolve packages in the node_modules created by pnpm. I think it is because webpack doesn't resolve dependencies the way Node does. Node resolves requires from the real path of a module. That is why the symlink approach pnpm uses works with all Node apps. However, it seems to confuse webpack and some other tools like browserify and eslint.

相关推荐
灿灿1213814 天前
npm、pnpm、yarn 各自优劣深度剖析
前端·javascript·npm·pnpm·yarn
wml0000017 天前
pnpm项目内网迁移
pnpm·离线
big tail20 天前
项目依赖版本修改
npm·pnpm·react·yarn·依赖·package.json
青苔猿猿24 天前
node版本.node版本、npm版本和pnpm版本对应
前端·npm·node.js·pnpm
Lysun0011 个月前
(pnpm)引入 其他依赖失败,例如‘@element-plus/icons-vue‘失败
前端·javascript·npm·pnpm
ejinxian1 个月前
npm,yarn,pnpm,cnpm,nvm,npx包管理器常用命令
前端·npm·pnpm·yarn·nvm·npx
YuShiYue1 个月前
pnpm monoreop 打包时 node_modules 内部包 typescript 不能推导出类型报错
javascript·vue.js·typescript·pnpm
小七de尾巴2 个月前
利用pnpm patch给第三方库打补丁
vue·pnpm·patch·补丁
爱宇阳2 个月前
pnpm 依赖升级终极指南:从语义化版本控制到 Monorepo 全局更新的企业级实践
pnpm·版本控制·monorepo·依赖升级
AJ_Styles3 个月前
pnpm 报错 Error: Cannot find matching keyid 解决
pnpm·node·corepack