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/lilytest-lib-a@1.1.0/node_modules/lilytest-lib-a。使用 dir 可以看到:

安装 a 和 b:

和之前相比,只多了 node_modules/lilytest-lib-b,链接到 .pnpm/lilytest-lib-b@1.1.0/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.

相关推荐
qq_3323942013 小时前
pnpm的坑
前端·vue·pnpm
前端扎啤3 天前
高效前端开发:解密pnpm的存储与链接
前端·前端框架·npm·pnpm·依赖
小玲子小玲子15 天前
pnpm run build报错throw new Error(‘Callback was already called.‘);
javascript·pnpm
天下布武81 个月前
使用 PNPM 从 0 搭建 monorepo,测试并发布
pnpm·monorepo·storybook·lit·webcomponents
开发小途1 个月前
pnpm包管理器总结
npm·pnpm·yarn
夏微微~~1 个月前
vue2转vue3初步下载pnpm遇到的问题 pnpm : 无法加载文件 D:\nodejs\pnpm.ps1
pnpm·vue3
loriloy2 个月前
node pnpm修改默认包的存储路径
pnpm
小玲子小玲子2 个月前
pnpm install报错 Value of “this“ must be of type URLSearchParams
pnpm·node
空白诗2 个月前
npm、yarn与pnpm详解
前端·npm·node.js·pnpm·yarn
捶捶自己2 个月前
pnpm安装指南
npm·pnpm