// https://www.jianshu.com/p/818833b2dd5anode
npm的版本号管理
一个版本号分为三个部分:
X,
Y,
Z.
X表示主版本号,
X为主版本号,
Y为次版本号,
Z为更新补丁号,
若是作稍微改动、
修复功能,
没有添加新功能,
更新Z,
若是添加新功能,
更新版本号Y,
若是有大的功能须要改动,
更新版本号X
~
会匹配最近的小版本依赖包,
好比~
1.2.3
会匹配全部1.2.
x版本,
可是不包括1.
3.0
^
会匹配最新的大版本依赖包,
好比 ^
1.2.3
会匹配全部1.
x.
x的包,
包括1.
3.0,
可是不包括2.
0.0
使用场景
运行同一个项目,
补丁的版本更新,
使用不一样项目的人npminstall,
二个不一样的版本运行的结果可能不同
这时候
package -
lock.
json
为了解决这个问题,(
npm
版本在5以上),
内容处理和安装依赖,
他代表了
版本号,
获取地址和哈希值,
是的每次安装都是相同的结果
//https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/22
// npm 模块安装机制:
发送npm
install的命令
查询node_modules目录是否有指定模块,
若是存在,
不须要从新安装
若是不存在
npm向registry查询压缩包的网址
下载压缩包,
存放在根目录下的.
npm的目录里
解压压缩包到当前项目node_modules目录下
// npm 实现的原理
当输入npm
install会经历以下几个阶段
1,
执行工程自身preinstall
2,
肯定首层依赖模块
首先须要作的是肯定工程中的首层依赖,
也就是
dependencies
和
devDependencies
属性中直接指定的模块(
假设此时没有添加
npm
install
参数)。
工程自己是整棵依赖树的根节点,
每一个首层依赖模块都是根节点下面的一棵子树,
npm
会开启多进程从每一个首层依赖模块开始逐步寻找更深层级的节点。
3,
获取模块
获取模块的信息
在下载一个模块以前,
首先要肯定其版本,
这是由于
package.
json
中每每是
semantic
version(
semver,
语义化版本)。
此时若是版本描述文件(
npm -
shrinkwrap.
json
或
package -
lock.
json)
中有该模块信息直接拿便可,
若是没有则从仓库获取。
如
packaeg.
json
中某个包的版本是 ^
1.1.
0,
npm
就会去仓库中获取符合 1.
x.
x
形式的最新版本。
获取模块的实体
上一步会获取到模块的压缩包地址(
resolved
字段),
npm
会用此地址检查本地缓存,
缓存中有就直接拿,
若是没有则从仓库下载。
查找模块的依赖
查找该模块依赖,
若是有依赖则回到第1步,
若是没有则中止。
4,
模块扁平化(
dedupe)
上一步获取到的是一棵完整的依赖树,
其中可能包含大量重复模块。
好比
A
模块依赖于
loadsh,
B
模块一样依赖于
lodash。
在
npm3
之前会严格按照依赖树的结构进行安装,
所以会形成模块冗余。
从
npm3
开始默认加入了一个
dedupe
的过程。
它会遍历全部节点,
逐个将模块放在根节点下面,
也就是
node -
modules
的第一层。
当发现有重复模块时,
则将其丢弃。
这里须要对重复模块进行一个定义,
它指的是模块名相同且
semver
兼容。
每一个
semver
都对应一段版本容许范围,
若是两个模块的版本容许范围存在交集,
那么就能够获得一个兼容版本,
而没必要版本号彻底一致,
这能够使更多冗余模块在
dedupe
过程当中被去
5,
安装模块
这一步将会更新工程中的
node_modules,
并执行模块中的生命周期函数(
按照
preinstall、
install、
postinstall
的顺序)。
6,
执行工程中自身生命周期
当前
npm
工程若是定义了钩子此时会被执行(
按照
install、
postinstall、
prepublish、
prepare
的顺序)。
最后一步是生成或更新版本描述文件,
npm
install
过程完成。