kangyana / daily-question

When your heart is set on something, you get closer to your goal with each passing day.
https://www.webpack.top
MIT License
3 stars 0 forks source link

【Q129】node_modules 的目录结构(拓扑结构) #129

Open kangyana opened 1 year ago

kangyana commented 1 year ago

1. 基础

require('package-hello') 时,假设 package-hello 是一个 npm 库,我们是如何找到该 package 的?

2. 很久以前: 嵌套结构

在 npmv2 时,node_modules 对于各个 package 的拓扑为嵌套结构。

假设:

依赖关系以 Markdown 列表表示:

- package-a
  - `lodash@4.17.4`
- package-b
  - `lodash@4.17.4`

此时 node_modules 目录结构如下:

graph
  app(node_modules) ---> A(package-a)
  app          ---> B(package-b)
  A            ---> C("lodash@4.17.4")
  B            ---> D("lodash@4.17.4")

此时最大的问题:

3. 现在阶段: 平铺结构

目前在 npm/yarn 中仍然为平铺结构,但 pnpm 使用了更省空间的方法,以后将会提到 在 npmv3 之后 node_modules 为平铺结构,拓扑结构如下:

graph
app(node_modules) ---> A(package-a)
app          ---> B(package-b)
app          ---> C("lodash@4.17.4")

情况1:以下依赖最终 node_modules 结果如何?

可参考该示例 依赖关系以 Markdown 列表表示:

- package-a
- `lodash@^4.17.4`
- package-b
- `lodash@^4.16.1`

答:与上拓扑结构一致,因为二者为 ^ 版本号,他们均会下载匹配该版本号范围的最新版本,比如 @4.17.4,因此二者依赖一致。

注意:此时如果有 lock,会有一点小问题,待稍后讨论

node_modules 目录结构如下图:

graph
  app(node_modules) ---> A(package-a)
  app          ---> B(package-b)
  app          ---> C("lodash@4.17.4")

情况2:以下依赖最终 node_modules 结果如何?

可参考该示例

- package-a
- `lodash@4.17.4`
- package-b
- `lodash@4.16.1`

答:package-b 先从自身 node_modules 下寻找 lodash,找到 lodash@4.16.1

node_modules 目录结构如下图:

graph
  app(node_modules) ---> A(package-a)
  app          ---> B(package-b)
  app          ---> C("lodash@4.17.4")
  B            ---> D("lodash@4.16.1")

情况3:以下依赖最终 node_modules 结果如何?

- package-a
  - `lodash@4.0.0`
- package-b
  - `lodash@4.0.0`
- package-c
  - `lodash@3.0.0`
- package-d
  - `lodash@3.0.0`

答:package-d 只能从自身的 node_modules 下寻找 lodash@3.0.0,而无法从 package-c 下寻找,此时 lodash@3.0.0 不可避免地会被安装两次。

node_modules 目录结构如下图:

graph
  app(node_modules) ---> A(package-a)
  app          ---> B(package-b)
  app          ---> C(package-c)
  app          ---> D(package-d)
  app          ---> X("lodash@4.0.0")
  C            ---> Y("lodash@3.0.0")
  D            ---> Z("lodash@3.0.0")

4. 重复的版本依赖有什么问题?

可参考 npm doppelgangers