Node.js 的 preserve-symlinks
Node.js 在 6.5.0 版本中支持了 preserveSymlink 选项。通过 preserveSymlink 选项,开发人员可以在 处理文件链接的时候,具有更多的选择。在默认情况下,node.js 默认情况下会解析链接文件,并尝试访问链接所指的 目标文件或目录,这可能会导致 Node.js 提示模块无法解析的错误。
例如在 demo 目录中 b.js 是一个软链,index.js 文件中 require 了
b.js 文件,b.js 文件中通过相对路径的方式 require 了 c.js 文件。
通过 node index.js
运行代码,会出现 Error: Cannot find module './c.js'
的错误提示。
demo 目录结构
├── a.js
├── b.js -> ../../../b.js
├── c.js
└── index.js
// b.js 文件内容,b.js 的目标文件位于 ../../../b.js
// 通过相对路径引入 c.js
// 在不使用 preserve-symlinks 选项时,require('./c.js') 相当于 require('../../../c.js')
// 使用 preserve-symlinks 选项时,require('./c.js') 仍然相对于 './' 目录查找
const c = require('./c.js')
console.log(c)
exports.module = c
运行错误
❯ node index.js
internal/modules/cjs/loader.js:905
throw err;
^
Error: Cannot find module './c.js'
通过 node --preserve-symlinks index.js
可以让代码正常运行。
❯ node --preserve-symlinks index.js
{ module: 'This is C' }
{ module: { module: 'This is C' } }
在第一次运行代码时,node.js 会解析 b.js 软链接所指向的目标文件的路径,而不是 b.js 这个软链接所在的目录。 所以会出现找不到 c.js 的情况,因为 c.js 和 b.js 软链接是同一个目录。
第二次运行代码是,node.js 会按照 b.js 软链接的目录来查找 c.js 文件,因为 b.js 软链接和 c.js 文件在同一个目录下,所以通过require('./c.js')
是可以定位到的。
了解了 Node.js 如何对文件链接进行处理后,在来看 pnpm ,pnpm 的实现采用了文件链接,借助文件链接来达到节约磁盘空间的目的。 通过 pnpm 安装后的 node_modules 结构如下:
node_modules
├── foo -> ./.pnpm/foo@1.0.0/node_modules/foo
└── .pnpm
├── bar@1.0.0
│ └── node_modules
│ └── bar -> <store>/bar
└── foo@1.0.0
└── node_modules
├── foo -> <store>/foo
└── bar -> ../../bar@1.0.0/node_modules/bar
在这个示例中,foo 依赖的 bar 实际指安装了一次,通过链接的方式进行复用。<store>
是存储链接的目录,可以通过 .npmrc
文件中的 virtual-store-dir
修改。
由于 pnpm 的实现采用了链接,所以它提供了 node-linker
和 symlink
对安装时所采用的链接形式进行控制,除了 pnpm 外,TypeScript 和 rollup 等提供了 preserveSymlinks 选项。
如果对代码仓库进行 pnpm 的支持,遇到 Error: Cannot find module
类的错误,可以尝试修改 TypeScript 或 rollup 的相关配置。