在之前的文章📄 果断放弃npm切换到pnpm–节约磁盘空间(256G硬盘救星) 中有提及 npm 扁平化带来的幽灵👻依赖 问题,但没有特别展开,这段时间实际业务中遇到了该问题,特整理如下:
♨️ 问题描述:项目使用 npm 安装依赖可以正常运行,而使用 pnpm 安装依赖运行报错!
以 node-emoji 为例:其是一款表情符号查找和解析工具,它依赖了
@sindresorhus/is
用于值类型检查。
{
"name": "node-emoji",
"version": "2.1.3",
"dependencies": {
"@sindresorhus/is": "^4.6.0",
...
}
}
🐜 使用 npm/pnpm 新增 node-emoji
依赖
$ npm install node-emoji --save
$ pnpm add node-emoji --save
示例:我 ❤️ 🇨🇳
const emoji = require('node-emoji')
console.log(emoji.emojify('我 :heart: :cn:'))
🐝 均可正常执行,我们修改代码如下:
const emoji = require('node-emoji')
+ const is = require('@sindresorhus/is')
console.log(emoji.emojify('我 :heart: :cn:'))
+ console.log(is('李刚')) // string
⚠️ npm 可正常执行!pnpm 报错:Error: Cannot find module '@sindresorhus/is'
左侧:npm;右侧:pnpm
通过安装的结构,便可以察觉问题:
- 使用 npm 安装,所有依赖都被提升到了 node_modules 下(npm@3之后的依赖扁平化,解决路径地狱);
- 使用 pnpm 安装,只有直接依赖(
package.json
dependences
中声明)安装在 node_modules 下,其他在 .pnpm(扁平化) 目录下。
👉 不再 node_modules 下,所以项目中无法直接引用!
pnpm 好处:
-
通过软链的形式,使得 require 可以正常引用;同时对非真正依赖的项目做隔离(避免引用依赖的混乱)
$ ls -li node_modules/node-emoji 30559101 lrwxr-xr-x 1 ligang staff 46 8 6 16:59 node_modules/node-emoji -> .pnpm/node-emoji@2.1.3/node_modules/node-emoji
-
.pnpm
的存在避免了循环引用和层级过深的问题(扁平化)node_modules └─ .pnpm | ├─ node_modules | | └─ @sindresorhus+is@4.6.0 -> ../../@sindresorhus+is@4.6.0/node_modules/@sindresorhus/is | ├─ @sindresorhus+is@4.6.0 | └─ node-emoji@2.1.3 | └─ node_modules | └─ @sindresorhus/is -> ../../../@sindresorhus+is@4.6.0/node_modules/@sindresorhus/is └─ node-emoji
-
硬链使得不同项目相同依赖只存在一个副本,减少磁盘空间
$ ll -li node_modules/.pnpm/@sindresorhus+is@4.6.0/node_modules/@sindresorhus/ 30564598 drwxr-xr-x 6 ligang staff 192B 8 6 17:52 is
inode值 文件类型权限 链接计数 文件拥有者 文件群组 大小 修改日期 名称 30564598 drwxr-xr-x 6 ligang staff 192B 8月6日 17:52 is
pnpm基于符号链接的 node_modules 结构
解决方案:不推荐
如果缺少依赖太多,可以使用提升选项。此选项官方不推荐。
pnpm install --shamefully-hoist