Rumah > hujung hadapan web > tutorial js > npm的模块安装机制详细介绍

npm的模块安装机制详细介绍

零下一度
Lepaskan: 2017-06-26 10:54:07
asal
1261 orang telah melayarinya
 
依赖树表面的逻辑结构与依赖树真实的物理结构
依赖树表面的逻辑结构与依赖树真实的物理结构并不一定相同!
这里要先提到两个命令:tree -d(linux)和npm ls(npm)
在一个npm项目下:
tree -d命令以树状图的方式列出一个项目下所有依赖的物理结构
npm ls命令以树状图的方式列出一个项目下所有依赖的逻辑结构
 
以官方文档为例子:
项目example1有两个依赖模块:mod-a模块和mod-c模块;
mod-a模块有一个依赖模块mod-b@1.0.0模块
mod-c模块有一个依赖模块mod-b@2.0.0模块
tree -d 和npm ls运行结果如下:(注意npm版本为npm3而非npm2)
 
 
先看看下面那个红框的结果,这应该是“最符合我们理解”的依赖树,首先项目下形成了一级依赖——mod-a模块和mod-b模块,然后以这两个模块为父模块再追加二级依赖模块mod-b@1.0.0和mod-b@2.0.0
 
但是!这却并不是物理上真实形成的依赖树的模样,物理上真实形成的依赖树是上面的那个红色框。mod-a,mod-c和mod-b竟然同为同一级的依赖。
 
你可能会问,为什么会形成这样的依赖树呢?下面我就来解释一番
 
【注意】:下面的图示全部为依赖树的物理结构,而不是逻辑结构
 
关于npm模块安装机制的一点猜想
安装模块时,可能的方式有两种:平级式的安装或嵌套式的安装(此处仅仅是猜想和假设)

 

能不能完全采取平级的安装方式呢?——不能
 
我们取和上面相似的一个例子:项目APP下有两个依赖模块A和B;A又有一个依赖模块Cv1.0;而B也有一个依赖模块Cv2.0。显然,它们并不能同时存在于同一个node_modules下,当安装的时候,由于npm的作用机制,只能有一个版本的依赖模块被安装,其中一个将覆盖另外一个。

 

但如果我们仅仅只安装一个版本的C依赖模块,将可能会导致A模块和B模块不兼容
 
 
基于以上原因,npm2选择了嵌套的安装方式——
 
npm2下的模块安装机制
npm2安装多级的依赖模块采用嵌套的安装方式: 
 
 
 
优点和弊端
优点:解决了版本单一时存在的存在的不兼容问题,实现多版本兼容
弊端:可能造成相同模块大量冗余的问题,如下:
 
以上面例子为例,下面这种情况也是合理存在的:
凭感觉也知道,这绝不是什么好现象,那我们如何能在实现依赖间多版本兼容的前提下,减少这种模块冗余呢?于是npm3做了一下改进
 
npm3下的模块安装机制:
npm3和npm2的不同主要体现在二级模块的安装上:
npm3会"尽量"把逻辑上某个层级的模块在物理结构上"全部"放在项目的第一层级里,具体我概括为以下三种情况:
 
1.在安装某个二级模块时,若发现第层级还没有相同名称的模块,便把这第二层级的模块放在第一层级
2.在安装某个二级模块时,若发现第层级有相同名称,相同版本的模块,便直接复用那个模块
3.在安装某个二级模块时,若发现第层级有相同名称,但版本不同的模块,便只能嵌套在自身的父模块下方
 
这一开始可能有些难理解,所以让我们看图说话吧!
 
先说1:在安装某个二级模块时,若发现第一层级还没有相同名称的模块,便把这第二层级的模块放在第一层级
我们先简化一下上面的例子:现在项目APP下只有一个一级依赖模块A,它下面有一个二级依赖模块C,但npm install的时候,项目下安装依赖的

 

npm3中的二级模块(C v1.0),在项目的一级目录(node_modules)下没有相同名称的模块时,会被安装到一级目录下,从而跟它的父模块A同级。这就是本文一开始中依赖树的逻辑结构和物理结构不同的起因
 
也就是说:
在npm2中,依赖树的逻辑结构和它的物理结构相同
在npm3中,依赖树的逻辑结构和它的物理结构可能不同
 
再说2:在安装某个二级模块时,若发现第一层级有相同名称,相同版本的模块,便直接复用那个模块
 
在1的基础上,我们把1的例子还原回之前的复杂一些的场景::项目APP下有两个依赖模块A和B;A又有一个依赖模块Cv1.0;而B也有一个依赖模块C v1.0(两个C模块版本相同)

 

对npm2,两个C包是相同的,造成模块冗余
在npm3中,因为A模块下的C模块被安装到了第一级,这使得B模块能够复用处在同一级下;且名称,版本,均相同的C模块
npm3就是用这种方式,部分地解决了npm2的痛点(部分)
 
【从1,2到3的过渡】我在这一小节的开始说:“npm3会"尽量"把逻辑上某个层级的模块"全部"放在项目的第一层级里”,我想你看完1,2后应该多少有些理解了“尽量”的含义了,但我说了“尽量”,同时也就意味着npm3存在着不能把二级依赖放在第一层级的情况。对此,请看3:
 
最后说3:在安装某个二级模块时,若发现第一层级有相同名称,但版本不同的模块,便只能嵌套在自身的父模块下方
 
在2中,A,B所依赖的两个C模块是相同的,但如果两个C模块的版本不同呢?,项目npm install情况如下:

 

在npm3中,因为B和A所要求的依赖模块不同,(B下要求是v1.0的C,A下要求是v2.0的C )所以B不能像2中那样复用A下的C v1.0模块
(看到这里我想应该能解答你对文章开头那个例子的疑惑了吧,这个例子和那个例子是几乎完全一样的哦)
 
看到这里,你对npm2和npm3下的模块工作机制,以及npm3针对npm2的优化有个大体的了解了吧,但请思考一个问题:npm3是否已经把npm2的模块冗余的缺陷优化到极致了呢? ———答案是没有,请往下看:
 
实际上:npm3中仍然可能出现模块冗余的情况,因为一级目录下已经有v1.0的C模块了,所以所有的v2.0只能作为二级依赖模块被安装,这样你就会看到如下的情况

 

 
并且在上图所示的这种特殊情况里,npm3和npm2表现得似乎并没什么区别
 
【过渡】那么这有没有什么解决的方式呢?当然是有的,当A模块下的C v1.0模块被更新至C v2.0的前提下,我们可以通过npm dedupe把所有C v2.0的二级依赖模块“重定向”到一级目录下的那个C v1.0
 
利用npm dedupe去除冗余模块:
npm dedupe做了什么?它能够把凡是能够去除的冗余的二级依赖模块,“重定向”到名称/版本相同的一级模块

 

参考资料 npm官方文档第二节(how npm works ): 
【温馨提醒】:任何一篇脍炙人口的博客,都比不上一本厚重的书籍和枯燥的文档
 
【完】
每天记10个小单词吧,重在积累哦!
memory:内存  Dependency:依赖  constraints:约束 deploy: 部署 parameter:参数 scope:作用域
ecosystems:生态系统 prefix:前缀 Prior:优先/之前  revoke:撤销
 
 

Atas ialah kandungan terperinci npm的模块安装机制详细介绍. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan