当前位置: 首页 > Web前端 > HTML

简单探索npm相关机制

时间:2023-03-27 23:48:02 HTML

这篇文章你能得到什么?npm的安装机制,即执行install命令时做了什么?npm的缓存策略这里简单介绍一下,不深入。npm的依赖管理,也就是我们每次安装的依赖在node_modules中是怎么管理的?锁文件有什么用?我们真的需要吗?如果以上三点你已经很清楚了,那你就不用浪费太多时间了,简单复习一下就可以了。不清楚的可以坐下来看8分钟。npm依赖安装机制首先,我们了解下npm依赖安装的设计理念:npm在安装依赖时,会先安装到当前项目的目录下,以保持各个项目依赖的独立性。优点:可以减轻开发者的精神负担,方便维护每个项目下的不同依赖。缺点:项目A和项目B都依赖一个包,此时会出现依赖的重复安装,造成电脑内存资源的浪费。当然也可以全局安装webpack、creat-react-app等依赖。这样做的目的是为了方便设置环境变量路径,方便我们在任何地方调用相应的命令。了解了这些之后,我们来探究一下npm依赖安装的核心机制。通过上图,我们可以看到整个npm安装依赖的脉络。下面我们一一分析。当我们执行npminstall命令时,会先搜索对应的配置文件,告诉npm使用什么规则来下载文件。.配置文件有多个,但是有一个优先级:项目级.npmrc>用户级.npmrc>全局.npmrc>npm内置.npmrc文件我们可以通过npmconfigls-l查看当前配置OK配置完成后config,会看到当前项目下有没有package-lock.json文件。如果有package-lock.json文件,则比较pacakge.json和lock文件:如果依赖版本规范兼容,则根据lock文件中的信息下载资源;如果依赖的版本规范不兼容,不同的版本会有不同的处理(详见上图)其实大部分情况下两个版本规范是兼容的,所以大部分都是根据锁文件安装依赖。除非你手动更改依赖版本号,否则可能会出现不兼容的情况。总结一下:规范兼容,根据**锁**下载依赖。Incompatible根据**package.json**下载依赖,最后更新锁文件。这里的问题是如何判断两个依赖版本是否兼容?这里需要了解一个知识点,什么是semver?如果官方文档中没有package-lock.json文件,那么依赖树就会根据package.json文件构建。构建依赖树时,遵循扁平化原则,即先将依赖放在node_modules的根目录下。后面安装其他依赖的时候会判断依赖是否已经存在。如果存在,则会比较两个依赖的版本规范是否兼容。如果兼容,则跳过依赖的安装(忽略依赖,因为已经存在),如果不兼容,则将本版本的依赖单独放在其parent的node_modules中,然后在获取时优先缓存依赖资源,可以加快依赖的下载速度。npm取决于缓存策略。我们可以通过以下命令获取缓存地址,在对应的__caches文件夹下可以查看到相关文件。npmconfiggetcache我们每次安装时如何读取缓存?我们在安装的时候,npm会先把资源下载到缓存中,然后解压项目对应的node_modules。之后每次安装资源时,都会根据package-lock.json文件中的版本、完整性、名称信息生成一个key值。这个键值可以匹配index-v5中缓存的资源信息。如果命中缓存,就会找到对应的tar包解压到项目中的node_modules中。这里其实可以探究一下这个key值是怎么产生的?留个念头:如果没有锁文件,是不是就不会从缓存中取资源了?但是每次都是通过网络下载的?npm依赖管理机制首先,我们看一下npm依赖管理v2版本是如何工作的。当一个项目中有两个依赖A和B时,这两个依赖会依次安装到node_modules中。而这两个依赖有一个共同的依赖C,那么在v2中,C会被安装到A和B文件夹的node_modules中。这样就会产生一个问题,就是依赖地狱。依赖地狱会造成内存资源浪费,重复安装依赖会导致安装进度缓慢。为了解决这样的问题,npm从v3开始就采用了扁平化的结构(实际上目前npm的很多机制都是基于yarn的设计)。扁平化结构下,npm是如何管理依赖的?让我们一步步说清楚。首先,依赖A有一个依赖C版本号为v1,所以在安装依赖的时候是这样的:然后在安装依赖B的时候,他也依赖了v1版本C,那么他就会从node_modules的根目录下寻找依赖,此时的依赖结构如下:如果依赖了B,它依赖的C版本是v2,那么结构会发生变化,B会在自己目录的node_modules中安装对应的v2版本的C:根据上面的情况,继续往下看如果这个时候我们需要把依赖A升级到v2,这个版本的A不再依赖v1版本的C,而是依赖v2版本的C。那么npm会做什么此时?删除A是因为v1版本的C没有包依赖,所以v2版本的A也会被删除,因为此时根目录下没有v2的C,会在根目录下安装v2版本的C.这里可能有一个问题,为什么依赖C的v2版本,而依赖B在自己的目录下单独安装C的v2?因为后面安装了B依赖,安装B的时候根目录下已经存在v1版本的C包,所以v2版本安装在自己的目录下。从这里可以看出,npm中依赖的安装顺序会对依赖结构产生很大的影响,可能会影响到node_modules的文件大小。那么有没有办法让它完全变平呢?当然是可以的,npm提供了一个命令可以帮助我们处理这些重复的文件,也可以理解为帮助我们在npmdedupe执行变得更加优雅之后将结构扁平化:这里值得一提的是yarn在在安装依赖的时候,会自动执行dedupe命令,帮助我们自动平级。下面给大家一个真实案例。我初始化了一个新项目。这个项目只安装了一个依赖find-css-import(这个包是我自己写的,所以比较熟悉)。本包只有一个依赖strip-commentsv2.0。当我们第一次安装这个依赖时,这两个文件会同时出现在项目中的node_modules文件夹中。这种现象也符合我们上面分析的结果。然后我们手动更改目录结构,将strip-comments文件夹放入find-css-import的node_modules中,然后执行dedupe来模拟压扁的过程。手动修改后的目录结构是这样的:然后我们去执行dedupe,可以看到已经成功的把文件结构扁平化了~总结一下,这篇文章其实是一篇笔记,对于前两篇看到的知识天做一个总结。其实,虽然我们日常经常使用包管理工具,但很多细节都被忽略了,希望能通过这篇文章有所收获。参考LucasHC先生(侯策)-前端基础设施与架构30讲山月先生-什么是semver文章来源和公众号:前端程序喵,欢迎大家关注