依赖树表面的逻辑结构与依赖树真实的物理结构
依赖树表面的逻辑结构与依赖树真实的物理结构并不一定相同!
这里要先提到两个命令: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 ):https://docs.npmjs.com/how-npm-works/packages
【温馨提醒】:任何一篇脍炙人口的博客,都比不上一本厚重的书籍和枯燥的文档
【完】
每天记10个小单词吧,重在积累哦!
memory:内存 Dependency:依赖 constraints:约束 deploy: 部署 parameter:参数 scope:作用域
ecosystems:生态系统 prefix:前缀 Prior:优先/之前 revoke:撤销
- 详解npm的模块安装机制
详解npm的模块安装机制 依赖树表面的逻辑结构与依赖树真实的物理结构 依赖树表面的逻辑结构与依赖树真实的物理结构并不一定相同! 这里要先提到两个命令:tree -d(linux)和npm ls(npm ...
- 【npm】详解npm的模块安装机制
依赖树表面的逻辑结构与依赖树真实的物理结构 依赖树表面的逻辑结构与依赖树真实的物理结构并不一定相同! 这里要先提到两个命令:tree -d(linux)和npm ls(npm) 在一个npm项目下 ...
- 介绍下 npm 模块安装机制,为什么输入 npm install 就可以自动安装对应的模块?
1. npm 模块安装机制: 发出npm install命令 查询node_modules目录之中是否已经存在指定模块 若存在,不再重新安装 若不存在 npm 向 registry 查询模块压缩包的网 ...
- [转] npm 模块安装机制简介
npm 是 Node 的模块管理器,功能极其强大.它是 Node 获得成功的重要原因之一. 正因为有了npm,我们只要一行命令,就能安装别人写好的模块 . $ npm install 本文介绍 npm ...
- npm 模块安装机制简介
npm 是 Node 的模块管理器,功能极其强大.它是 Node 获得成功的重要原因之一. 正因为有了npm,我们只要一行命令,就能安装别人写好的模块 . $ npm install 本文介绍 npm ...
- npm模块安装机制简介
npm是node的模块管理器,功能及其强大,它是node获得成功的重要原因之一. 正因为有了nom,我们只要一行命令,就能安装别人写好的模块. $ npm install 本文介绍npm模块安装机制的 ...
- 转载 《AngularJS》5个实例详解Directive(指令)机制
<AngularJS>5个实例详解Directive(指令)机制 大漠穷秋 本文整理并扩展了<AngularJS>这本书第六章里面的内容,此书近期即将由电子工业出版社出版,敬请 ...
- Hadoop 发行版本 Hortonworks 安装详解(二) 安装Ambari
一.通过yum安装ambari-server 由于上一步我们搭建了本地源,实际上yum是通过本地源安装的ambari-server,虽然也可以直接通过官方源在线安装,不过体积巨大比较费时. 这里我选择 ...
- Redis详解(六)——哨兵机制
Redis详解(六)--哨兵机制 一.概述 Redis Sentinel是一个分布式系统,为Redis提供高可用性解决方案.可以在一个架构中运行多个 Sentinel 进程(progress), 这些 ...
随机推荐
- 海康/大华 IpCamera RTSP地址和格式
海康:rtsp://[username]:[password]@[ip]:[port]/[codec]/[channel]/[subtype]/av_stream说明:username: 用户名.例如 ...
- NuGet(Nuget Packages)
Nuget是一个.NET平台下的开源的项目,它是Visual Studio的扩展.在使用Visual Studio开发基于.NET Framework的应用时,Nuget能把在项目中添加.移除和更新引 ...
- STM32、Cortex-A、Cortex-R、Cortex-M、SecurCore
STM32是就是基于Cortex-M3这个核生产的CPU. arm7是arm公司推出的以V4指令集设计出来的arm核--其代表的芯片有s3c44b0 arm9是arm公司推出的以V5指令集设计出来的a ...
- php curl 访问 https站点
$uri = "https://your_website"; $ch = curl_init (); $data=I('post.'); curl_setopt ( $ch, CU ...
- select效果联动
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <hea ...
- CodeSmith生成实体的分页读取规则
首先.我得向咱们博客园提个意见,能不能我写的东西就给预保存下呢?刚才我写半天,只因为这个不给力的IE浏览器死了,导致我白写了,如果这要是那个大神直接在这上面写的非常有技术含量的贴着会因此而丢失实在是有 ...
- [ext4]空间管理 - 与分配相关的关键数据结构
在块分配机制中,涉及到几个主要的数据结构. 通过ext4_allocation_request描述块请求,然后基于块查找结果即上层需求来决定是否执行块分配操作. 在分配过程中,为了更好执行分配, ...
- Composer 常用命令总结(三)
init(初始化) 该命令用于创建 composer.json 文件,并进行基础信息配置: $ composer init 可以配置Package name.Description.Author.Mi ...
- ubuntu下搭建nginx+mysql+php-fpm站点
概述 Nginx ("engine x") 是一个高性能的 HTTP 和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 代理服务器. nginx的优势在于能以低内存高 ...
- TP5学习基础一:增删改查小demo
①TP5--增删改查简单的demo 我先吐槽一下:因为工作需要研究tp5,去官网看了一下哎呦,资源挺多挺全啊!然后下载唯一免费的官方教程,我曹pdf打开533页.讲的很细但是开发能等看完才做吗?看到精 ...