npmv2、npmv3、pnpm,模块管理方案对比

1,524 阅读1分钟

最原始的问题是:A 依赖 B v1.0,C 依赖 B v2.0,那这时候 B 就会有冲突。

npm v2

npm v2 采用了嵌套的方式来解决冲突,如下图。它带来的新问题就是:B 存了多份浪费空间

npm v3

npm v3 采用了扁平化的风格 (flat mode),尽可能将相同的模块提取到根目录,如下图。

flat mode 也不是完美的,还存在两个问题:

  1. 还是会有冗余空间,把 B v1.0 提到根目录,B v2.0 还是要嵌套存储,反之亦然
  2. 影子依赖 (Phantom dependency) 问题

影子依赖问题

关于影子依赖问题,我们看下面一段代码:package.json 里面并没有声明 glob 依赖,但代码中却可以正常使用。实际上 glob 是 rimraf 的依赖,glob 是被 flat mode 的机制提升到根目录的。

my-library/package.json

{
  "name": "my-library",
  "version": "1.0.0",
  "main": "lib/index.js",
  "dependencies": {
    "minimatch": "^3.0.4"
  },
  "devDependencies": {
    "rimraf": "^2.6.2"
  }
}

my-library/lib/index.js

var minimatch = require("minimatch")
var expand = require("brace-expansion");  // ???
var glob = require("glob")  // ???

除了会导致难以维护以外,还可能会导致其它问题。例如本地开发的时候会去安装 devDependencies,但在发布的时候不会安装 devDependencies,这样的话发布的时候就不存在 glob 导致无法正常工作。

pnpm:完美的解决方案

pnmp 目录结构上采用嵌套的方式避免了影子依赖问题,采用软链接的方式解决了模块复用的问题。