[FE] npm dependency resolution

1. 包(package)和模块(module)

A package is a file or directory that is described by a package.json.
A module is any file or directory that can be loaded by Node.js' require().

一般而言,npm package都可以使用require来引入,但不尽然,
例如,某些cli package,它们只包含了命令行接口,并不能被require导入,因此不是module。

2. 模块管理

2.1 npm v2

npm v2,采用了如下的模块组织方式,
将模块的依赖,放到该模块的子文件夹node_modules中,
最终形成一个树形结构。

假设有三个模块,A,B,C,
A v1.0依赖了B v1.0,C v1.0依赖了B v2.0,如图所示,


又假设,我们的应用同时依赖了A v1.0和C v1.0,


很显然,我们必须保留模块B的两个不同版本,
npm v2将B v1.0和B v2.0,分别放到模块A v1.0和C v1.0,各自的子文件夹中,


然而,虽然从文件的组织方式上来看,我们可以按照上图来处理,
但是,某些module loader却不能同时向内存中载入不同版本的模块。

幸运的是,node的module loader没有这种限制。

2.2 npm v3

npm v3采用了不同的模块组织方式,
在文件系统中,npm v3将一些二级依赖直接放到了一级依赖的位置,
因此,文件系统的树形结构,与模块的依赖关系,并不是同构的,
并且,文件系统的树形结构,与模块的安装顺序有关。

假设我们有两个模块,A,B,其中A v1.0依赖了B v1.0,


那么依赖了模块A的应用,将按下图方式组织文件,
将B v1.0(二级依赖),直接放到了和A v1.0(一级依赖)并列的位置,


如果我们现在引入了新的模块C v1.0,它依赖了B v2.0,


由于在一级依赖的位置上,已经有了B的某个版本,
npm v3将会把B v2.0,放到C v1.0的子文件夹中,


可以看到,先安装A和先安装C是不同的,
先安装A,会将B v1.0放到一级依赖的位置,
而先安装C,会将B v2.0放到一级依赖的位置。

2.3 去重复

接着上面的例子,假设我们又引入了新的模块D,其中D v1.0依赖了B v2.0,


由于在一级依赖的位置上,已经有了B的某个版本,
和模块C的情况类似,npm v3将会把B v2.0,放到D v1.0的子文件夹中,


此外,如果E v1.0依赖了B v1.0,


则最终文件结构如下,


现在事情发生变化了,A升级了版本,它所依赖的B版本也发生了变化,A v2.0依赖了B v2.0,


不难想象,文件结构会变成这样,和新增一个A v2.0模块相似,


然而,假设E也升级了,E v2.0也依赖B v2.0了,会怎样,


npm v3会删除一级依赖处的B v1.0,因为没有模块依赖它了,
它还会安装B v2.0到一级依赖处,因为一级依赖位置没有B模块的任何版本了,

可是,这样下来,B v2.0发生了很多重复依赖,
我们可以执行以下命令,消去重复,

npm dedupe

结果,文件结构如下,


3. 文件结构的不确定性

我们看到,由npm v3模块管理策略所得到的文件结构,是与安装顺序相关的
先安装的模块,其二级依赖会被放置到一级依赖处,
后安装的模块,其二级依赖会被放置到它的子文件夹中,
因此,不同的开发者,由于历史原因,更新模块的顺序不同,会导致工程的文件结构不同。

但这对开发工作是没有影响的。
文件系统只能体现模块组织的物理结构,其依赖关系的逻辑结构是相同的。

如果想要每个开发者的文件系统相同,
可以删除node_modules重新全量npm install
这样就能保证,使用package.json中指定的,相同的安装顺序安装模块,
得到的文件系统也将是相同的。


参考

Packages and Modules
npm v2 Dependency Resolution
npm v3 Dependency Resolution
npm3 Duplication and Deduplication
npm3 Non-determinism

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容

  • 弗洛伊德算法适用于为图中每一个顶点求最短路径,思路如下 检查图中任何一个 到 任何另一个点能否通过第一个点降低最短...
    RichardW阅读 947评论 0 1
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • 题目1: 如何全局安装一个 node 应用? Node模块采用npm install命令安装。 每个模块可以“全局...
    萧雪圣阅读 1,769评论 0 1
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,382评论 25 707
  • 是的,今日下午看了《理发师情人》 淡淡的思绪萦绕 与世隔绝的小小理发店 塞纳河畔金色的黄昏 无限的沉溺 这披着轻纱...
    flyteen阅读 503评论 0 0