1. npm安装机制
1. 发出npm install命令
2. 查询node_modules目录,是否存在已经指定的模块
- 存在,不再重新安装
- 不存在
- npm向registry查询模块压缩包的网址
- 下载压缩包,存放在根目录下的.npm目录
- 解压压缩包到当前项目的node_modules目录
2. npm实现原理
输入npm install后,会经历以下几个阶段:
- 执行自身工厂的preinstall
如果当前的npm工程定义了preinstall钩子的话,在安装开始时会先执行这个钩子。(当然还有install、postinstall,install的npm install命令必须执行的阶段)
- 确定首层依赖模块
首层依赖,指的是dependencies和devDependencies中配置的模块。
一个工程本身是整棵依赖树的根节点,每个首层依赖模块都是根节点下的一棵子树,npm在执行时会开启多进程,从每个首层依赖模块开始逐步寻找更深层级的节点。
- 获取模块
获取模块是一个递归的过程实现,主要分以下几步:
- 获取模块信息。在下载一个模块之前,首先要确定版本,这是因为在package.json中的往往都是semver版本(语义化版本,semantic version),此时,如果在版本描述文件(shrinkwrap.json或package-lock.json)中有该模块就直接去拿,如果没有 则从仓库中获取。
- 获取模块实体。上一步获取到的只是模块压缩包的地址(package-lock.json中的resolve字段值),npm会用这个地址去校验本地的缓存,如果缓存中有则直接拿,没有就会从仓库中下载。
- 检查该模块的相关依赖。如果有,回到第1步继续执行,没有,就此停止。
- 模块扁平化
这一步是将上一步所获得的完整的依赖树,将彼此之间的重复模块放在根节点目录下(即node_modules的第一层目录下),方便在被重复引用的模块使用时调用,而不是在每一个模块中都进行引入。
- 安装模块
这一步是将会更新工程中的node_modules,并执行模块中的声明周期函数。(更新顺序是按照preinstall、install和postinstall的顺序进行更新。)
- 执行工程自身的生命周期
当前npm工程如果自定义了钩子,此时会被执行。(执行顺序按照:install、postinstall、prepublis、prepare的顺序执行)
Tips:npm依赖安装的最后一步是更新版本描述文件。致辞,npm install过程完成。
3. registry
关于npm是怎么知道每个模块的最新版本的呢?答案是npm模块仓库提供的查询服务:registry。
- 在它的查询服务网址https://registry.npmjs.com后面加上模块名,就可以得到该模块的所有版本信息。如https://registry.npmjs.com/element-ui,可以得到element-ui的所有相关信息(淘宝镜像相应的可以使用https://registry.npm.taobao.org/element-ui获得)。
- 返回的
dist.tarball属性,就是该版本的压缩包的网址
。拿到这个网址下载的压缩包然后在本地解压,就可以得到模块的源码。- TIPS:npm install和npm update都是通过这种方式安装模块的。
4. 模块安装过程
Node模块的安装过程:
- 发出npm install命令
- npm向registry查询模块压缩包的网址
- 下载压缩包,存放在~/.npm目录
- 解压压缩包到当前项目的node_modules目录