幽灵依赖是指项目代码能够访问但未在 package.json 中显式声明的依赖。其成因在于 npm 和 Yarn Classic 采用的扁平化提升策略:为了减少目录嵌套深度,包管理器会将大量传递依赖提升到 node_modules 根目录,使得项目代码可以"顺便"引用这些本不应直接访问的包。这种机制在开发阶段看似便利,实则埋下了不确定性隐患——当传递依赖在新版本中移除或变更 API 时,依赖它的代码会突然失效。
pnpm 通过非扁平化的符号链接结构从根本上切断幽灵依赖的访问路径。项目的 node_modules 根目录只包含直接依赖的符号链接,传递依赖被隔离在 .pnpm 目录深处,Node.js 的模块解析算法无法直接触及。即使开发者尝试 require 一个未声明的包,也会因模块不存在而立即报错。
从 npm 或 Yarn 迁移到 pnpm 时,若项目中存在幽灵依赖,首次 pnpm install 后运行代码会触发 Cannot find module 错误。此时的处理方式是将该包显式添加到 package.json 中(pnpm add ),或确认该引用确实不必要后移除相关代码。对于少数依赖扁平化结构的遗留工具(如某些旧版 Webpack 配置或 React Native 项目),可通过 .npmrc 中的 shamefully-hoist=true 或 public-hoist-pattern[] 配置临时恢复扁平结构,但这会重新引入幽灵依赖风险,仅建议作为迁移过渡方案使用。