详解npm的模块安装机制

详解npm的模块安装机制

依赖树表面的逻辑结构与依赖树真实的物理结构

依赖树表面的逻辑结构与依赖树真实的物理结构并不一定相同!

这里要先提到两个命令:tree -d(linux)和npm ls(npm)

在一个npm项目下:

tree -d命令以树状图的方式列出一个项目下所有依赖的物理结构

npm ls命令以树状图的方式列出一个项目下所有依赖的逻辑结构

以官方文档为例子:

项目example1有两个依赖模块:mod-a模块和mod-c模块;

mod-a模块有一个依赖模块[email protected]模块

mod-c模块有一个依赖模块[email protected]模块

tree -d 和npm ls运行结果如下:(注意npm版本为npm3而非npm2)

先看看下面那个红框的结果,这应该是“最符合我们理解”的依赖树,首先项目下形成了一级依赖——mod-a模块和mod-b模块,然后以这两个模块为父模块再追加二级依赖模块[email protected]和[email protected]

但是!这却并不是物理上真实形成的依赖树的模样,物理上真实形成的依赖树是上面的那个红色框。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 ):https://docs.npmjs.com/how-npm-works/packages

【温馨提醒】:任何一篇脍炙人口的博客,都比不上一本厚重的书籍和枯燥的文档

【完】

时间: 2024-10-14 14:19:29

详解npm的模块安装机制的相关文章

npm 模块安装机制简介

转自:http://www.ruanyifeng.com/blog/2016/01/npm-install.html npm 是 Node 的模块管理器,功能极其强大.它是 Node 获得成功的重要原因之一. 正因为有了npm,我们只要一行命令,就能安装别人写好的模块 . $ npm install 本文介绍 npm 模块安装机制的细节,以及如何解决安装速度慢的问题. 一.从 npm install 说起 npm install 命令用来安装模块到node_modules目录. $ npm in

[转] npm 模块安装机制简介

npm 是 Node 的模块管理器,功能极其强大.它是 Node 获得成功的重要原因之一. 正因为有了npm,我们只要一行命令,就能安装别人写好的模块 . $ npm install 本文介绍 npm 模块安装机制的细节,以及如何解决安装速度慢的问题. 一.从 npm install 说起 npm install 命令用来安装模块到node_modules目录. $ npm install <packageName> 安装之前,npm install会先检查,node_modules目录之中是

实例详解Spring的事务传播机制(二)

上面我们讨论了NEVER和MANDATORY的作用,下面我们接着讨论其他情况. 3. SUPPORTS 如果有事务则加入该事务,如果没有存在的事务则以非事务的方式运行. 我们先让insertSubTable方法在无事务的情况下运行.配置文件为: <tx:attributes>       <!--     <tx:method name="insertSuperTable" propagation="REQUIRED"/>      -

《AngularJS》5个实例详解Directive(指令)机制(转)

转自大漠穷秋:http://damoqiongqiu.iteye.com/blog/1917971 感谢作者分享! <AngularJS>5个实例详解Directive(指令)机制 大漠穷秋 本文整理并扩展了<AngularJS>这本书第六章里面的内容,此书近期即将由电子工业出版社出版,敬请期待口令:Angular 1.一点小说明 指令的作用:实现语义化标签 我们常用的HTML标签是这样的: <div> <span>一点点内容</span> &l

npm模块安装机制

npm 是 Node 的模块管理器,功能极其强大.它是 Node 获得成功的重要原因之一.正因为有了npm,我们只要一行命令:npm install,就能安装别人写好的模块 . 一.从 npm install 说起 npm install 命令用来安装模块到node_modules目录. $ npm install <packageName> 安装之前,npm install会先检查,node_modules目录之中是否已经存在指定模块.如果存在,就不再重新安装了,即使远程仓库已经有了一个新版

【许晓笛】详解 EOS 的新共识机制 BFT-DPoS

EOS 最新的白皮书中已经将共识机制从 DPoS 升级为了 BFT-DPoS(Byzantine Fault Tolerance - Deligated Proof of Stake,带有拜占庭容错的委托股权证明),本篇文章将详解新共识机制的原理. 传统 DPoS EOS 项目刚刚发布的时候的共识机制是 DPoS(Deligated Proof of Stake,委托股权证明),类似于 Bitshares 和 Steem,这种共识机制采用随机的见证人出块顺序,出块速度为 3 秒,交易不可逆需要4

详解python的垃圾回收机制

python的垃圾回收机制 一.引子 我们定义变量会申请内存空间来存放变量的值,而内存的容量是有限的,当一个变量值没有用了(简称垃圾)就应该将其占用的内存空间给回收掉,而变量名是访问到变量值的唯一方式,所以当一个变量值没有关联任何变量名时,我们就无法再访问到该变量值了,该变量值就是一个垃圾会被python解释的垃圾回收机制自动回收 二.什么是垃圾回收机制 垃圾回收机制(简称GC)是python解释器自带的一种机制,专门用来回收不可用的变量值所占用的内存空间 三.为什么要用垃圾回收机制 程序运行过

Linux下安装MyEclipse和Tomcat服务器详解,以及我安装过程中所出现的问题以及解决办法,并实现一个web小程序

1.首先,先要去MyEclipse和Tomcat的官网去下载Linux版的压缩文件,而MyEclipse的中文官网是需要登录并有可能要付钱,大家可以去网上下载,还有就是Tomcat的linux版,这个直接上官网就可以下载了,下载后我还是通通把它们放在我E盘下的as目录底下,如果大家还没配置好jdk,即Java环境的话,可看我这篇文章:http://blog.csdn.net/u012561176/article/details/45119047 这里我就直接进行操作了! 我E盘下的as文件夹

《AngularJS》5个实例详解Directive(指令)机制

本文整理并扩展了<AngularJS>这本书第六章里面的内容,此书近期即将由电子工业出版社出版,敬请期待口令:Angular 1.一点小说明 指令的作用:实现语义化标签 我们常用的HTML标签是这样的: <div> <span>一点点内容</span> </div> 而使用AngularJS的directive(指令)机制,我们可以实现这样的东西: <tabpanel> <panel>子面板1</panel>