npm 内部机制

162 阅读3分钟

npm 安装机制

npm安装机制.png

构建依赖树时,当前项目无论是首层依赖还是子依赖的依赖,都应该遵循扁平化的规则,优先放置在node_modules目录下,在这个过程中,遇到相同的模块先判断当前已放置在node_modules下的模块的版本是否符合新版本的要求,符合则跳过,不符合则在依赖该模块的依赖目录的node_modules下放置该模块。

npm 缓存机制

我们可以执行以下命令查看缓存位置

npm config get cache

我们可以看到缓存目录下有这几个目录

  • content-v2
  • index-v5
  • tmp

content-v2中存放的是基本的二进制文件,更改后缀名为.tgz,解压之后即可得到我们的依赖库文件。

index-v5中存放的是content-v2内文件的索引。

npm(v5之后) 在安装依赖时会去检查缓存中是否存在该版本的库,首次安装不存缓存在则会从网络中下载并存储到缓存中,并解压到项目的node_modules目录下;接下来每次安装依赖时,根据package-lock.json中的integrity、version、name生成唯一的可key值,通过这个key值在index-v5中找到对应的缓存记录,如果找到了就根据找到的hash值找到缓存的包文件,解压到项目的node_modules目录下,省去了网络下载的时间。

npm 依赖管理

早期的 npm(v2) 设计很简单,安装依赖时直接把依赖放到项目的node_modules下面。如果某个项目依赖模块A,还间接依赖模块B。则模块B会被下载到模块A的node_modules下面,循环往复,最终形成一颗巨大的依赖树。

这样的node_modules下虽然结构明了,但对大型项目不友好,可能会有被重复安装的包,形成“依赖地狱”,浪费空间资源,之后 npm 采取了扁平化的结构。

当一个项目依赖模块A、模块B,同时模块A依赖模块Cv1.0,模块B依赖模块Cv2.0,那么我们最后的安装结构就是

未命名文件.png

至于Cv1.0出现在顶层和模块A和模块B的安装顺序相关,因此模块的安装顺序是可以影响我们项目的node_modules文件结构的。

最后介绍一个命令npm dedupe可以更新我们的node_modules结构,当出现如下结构(yarn 在安装依赖时就会自动执行dedupe命令)

未命名文件 (1).png

最佳实操建议

  • 优先使用npm v5.4.2以上的版本,保证 npm 的稳定性

  • 第一次搭建项目时使用npm install <package> 安装依赖,并提交package.json、package-lock.json文件,不提交node_modules目录。

  • 其他成员首次拉取项目后,需执行一次npm install安装依赖

  • 对于升级依赖包,可以

    • 通过npm update更新到新的小版本
    • 通过npm install <package>@<version>升级到指定版本
    • 也可以手动更新package.json中的依赖的版本号,执行npm install升级版本
    • 本地验证没有问题后,提交package.json、package-lock.json文件
  • 对于降级依赖包,可以

    • 通过npm install <package>@<version>降级到指定版本
    • 本地验证没有问题后,提交package.json、package-lock.json文件
  • 对于删除依赖包,可以

    • 通过npm uninstall <package>删除依赖,验证无误后,提交package.json、package-lock.json文件
    • 也可以手动更新package.json,删除依赖包,执行npm install,本地验证没有问题后,提交package.json、package-lock.json文件
  • 任何团队成员提交package.json、package-lock.json文件后,其他成员都应该拉取最新的代码,执行npm install更新依赖。

  • 任何时候都不要修改package-lock.json

  • 如果本地package-lock.json出现冲突,删除本地文件,从仓库上拉取代码,执行npm install