作为前端工程师你真的知道 npm install 原理么.docx

上传人:b****7 文档编号:9849065 上传时间:2023-02-07 格式:DOCX 页数:15 大小:433.64KB
下载 相关 举报
作为前端工程师你真的知道 npm install 原理么.docx_第1页
第1页 / 共15页
作为前端工程师你真的知道 npm install 原理么.docx_第2页
第2页 / 共15页
作为前端工程师你真的知道 npm install 原理么.docx_第3页
第3页 / 共15页
作为前端工程师你真的知道 npm install 原理么.docx_第4页
第4页 / 共15页
作为前端工程师你真的知道 npm install 原理么.docx_第5页
第5页 / 共15页
点击查看更多>>
下载资源
资源描述

作为前端工程师你真的知道 npm install 原理么.docx

《作为前端工程师你真的知道 npm install 原理么.docx》由会员分享,可在线阅读,更多相关《作为前端工程师你真的知道 npm install 原理么.docx(15页珍藏版)》请在冰豆网上搜索。

作为前端工程师你真的知道 npm install 原理么.docx

作为前端工程师你真的知道npminstall原理么

作为前端工程师你真的知道npminstall原理么?

做前端工程师得你,一定经常会使用到npminstall,那你真的了解npminstall执行之后的流程细节么?

嵌套结构

我们都知道,执行npminstall后,依赖包被安装到了node_modules,下面我们来具体了解下,npm将依赖包安装到node_modules的具体机制是什么。

在npm的早期版本,npm处理依赖的方式简单粗暴,以递归的形式,严格按照package.json结构以及子依前端要学好必须每天坚持学习。

为了方便大家的交流学习,也是创建了一个群每天都有分享学习方法和专业老师直播前端课程,这个扣裙首先是132中间是667最后是127前端学习零基础想要学习的同学欢迎加入,如果只是凑热闹就不要来了!

!

!

赖包的package.json结构将依赖安装到他们各自的node_modules中。

直到有子依赖包不在依赖其他模块。

举个例子,我们的模块my-app现在依赖了两个模块:

buffer、ignore:

ignore是一个纯JS模块,不依赖任何其他模块,而buffer又依赖了下面两个模块:

base64-js、ieee754。

那么,执行npminstall后,得到的node_modules中模块目录结构就是下面这样的。

这样的方式优点很明显,node_modules的结构和package.json结构一一对应,层级结构明显,并且保证了每次安装目录结构都是相同的。

但是,试想一下,如果你依赖的模块非常之多,你的node_modules将非常庞大,嵌套层级非常之深:

在不同层级的依赖中,可能引用了同一个模块,导致大量冗余。

在Windows系统中,文件路径最大长度为260个字符,嵌套层级过深可能导致不可预知的问题。

扁平结构

为了解决以上问题,NPM在3.x版本做了一次较大更新。

其将早期的嵌套结构改为扁平结构:

安装模块时,不管其是直接依赖还是子依赖的依赖,优先将其安装在node_modules根目录。

还是上面的依赖结构,我们在执行npminstall后将得到下面的目录结构:

此时我们若在模块中又依赖了base64-js@1.0.1版本:

当安装到相同模块时,判断已安装的模块版本是否符合新模块的版本范围,如果符合则跳过,不符合则在当前模块的node_modules下安装该模块。

此时,我们在执行npminstall后将得到下面的目录结构:

对应的,如果我们在项目代码中引用了一个模块,模块查找流程如下:

在当前模块路径下搜索

在当前模块node_modules路径下搜素

在上级模块的node_modules路径下搜索

直到搜索到全局路径中的node_modules

假设我们又依赖了一个包buffer2@^5.4.3,而它依赖了包base64-js@1.0.3,则此时的安装结构是下面这样的:

所以npm3.x版本并未完全解决老版本的模块冗余问题,甚至还会带来新的问题。

试想一下,你的APP假设没有依赖base64-js@1.0.1版本,而你同时依赖了依赖不同base64-js版本的buffer和buffer2。

由于在执行npminstall的时候,按照package.json里依赖的顺序依次解析,则buffer和buffer2在package.json的放置顺序则决定了node_modules的依赖结构:

先依赖buffer2:

先依赖buffer:

另外,为了让开发者在安全的前提下使用最新的依赖包,我们在package.json通常只会锁定大版本,这意味着在某些依赖包小版本更新后,同样可能造成依赖结构的改动,依赖结构的不确定性可能会给程序带来不可预知的问题。

Lock文件

为了解决npminstall的不确定性问题,在npm5.x版本新增了package-lock.json文件,而安装方式还沿用了npm3.x的扁平化的方式。

package-lock.json的作用是锁定依赖结构,即只要你目录下有package-lock.json文件,那么你每次执行npminstall后生成的node_modules目录结构一定是完全相同的。

例如,我们有如下的依赖结构:

在执行npminstall后生成的package-lock.json如下:

我们来具体看看上面的结构:

最外面的两个属性name、version同package.json中的name和version,用于描述当前包名称和版本。

dependencies是一个对象,对象和node_modules中的包结构一一对应,对象的key为包名称,值为包的一些描述信息:

version:

包版本——这个包当前安装在node_modules中的版本

resolved:

包具体的安装来源

integrity:

包hash值,基于SubresourceIntegrity来验证已安装的软件包是否被改动过、是否已失效

requires:

对应子依赖的依赖,与子依赖的package.json中dependencies的依赖项相同。

dependencies:

结构和外层的dependencies结构相同,存储安装在子依赖node_modules中的依赖包。

这里注意,并不是所有的子依赖都有dependencies属性,只有子依赖的依赖和当前已安装在根目录的node_modules中的依赖冲突之后,才会有这个属性。

例如,回顾下上面的依赖关系:

我们在my-app中依赖的base64-js@1.0.1版本与buffer中依赖的base64-js@^1.0.2发生冲突,所以base64-js@1.0.1需要安装在buffer包的node_modules中,对应了package-lock.json中buffer的dependencies属性。

这也对应了npm对依赖的扁平化处理方式。

所以,根据上面的分析,package-lock.json文件和node_modules目录结构是一一对应的,即项目目录下存在package-lock.json可以让每次安装生成的依赖目录结构保持相同。

另外,项目中使用了package-lock.json可以显著加速依赖安装时间。

我们使用npmi--timing=true--loglevel=verbose命令可以看到npminstall的完整过程,下面我们来对比下使用lock文件和不使用lock文件的差别。

在对比前先清理下npm缓存。

不使用lock文件:

使用lock文件:

可见,package-lock.json中已经缓存了每个包的具体版本和下载链接,不需要再去远程仓库进行查询,然后直接进入文件完整性校验环节,减少了大量网络请求。

使用建议:

开发系统应用时,建议把package-lock.json文件提交到代码版本仓库,从而保证所有团队开发者以及CI环节可以在执行npminstall时安装的依赖版本都是一致的。

在开发一个npm包时,你的npm包是需要被其他仓库依赖的,由于上面我们讲到的扁平安装机制,如果你锁定了依赖包版本,你的依赖包就不能和其他依赖包共享同一semver范围内的依赖包,这样会造成不必要的冗余。

所以我们不应该把package-lock.json文件发布出去(npm默认也不会把package-lock.json文件发布出去)。

缓存

在执行npminstall或npmupdate命令下载依赖后,除了将依赖包安装在node_modules目录下外,还会在本地的缓存目录缓存一份。

通过npmconfiggetcache命令可以查询到:

在Linux或Mac默认是用户主目录下的.npm/_cacache目录。

在这个目录下又存在两个目录:

content-v2、index-v5,content-v2目录用于存储tar包的缓存,而index-v5目录用于存储tar包的hash。

npm在执行安装时,可以根据package-lock.json中存储的integrity、version、name生成一个唯一的key对应到index-v5目录下的缓存记录,从而找到tar包的hash,然后根据hash再去找缓存的tar包直接使用。

我们可以找一个包在缓存目录下搜索测试一下,在index-v5搜索一下包路径:

然后我们将json格式化:

上面的_shasum属性6926d1b194fbc737b8eed513756de2fcda7ea408即为tar包的hash,hash的前几位6926即为缓存的前两层目录,我们进去这个目录果然找到的压缩后的依赖包:

以上的缓存策略是从npmv5版本开始的,在npmv5版本之前,每个缓存的模块在~/.npm文件夹中以模块名的形式直接存储,储存结构是{cache}/{name}/{version}。

npm提供了几个命令来管理缓存数据:

npmcacheadd:

官方解释说这个命令主要是npm内部使用,但是也可以用来手动给一个指定的package添加缓存。

npmcacheclean:

删除缓存目录下的所有数据,为了保证缓存数据的完整性,需要加上--force参数。

npmcacheverify:

验证缓存数据的有效性和完整性,清理垃圾数据。

基于缓存数据,npm提供了离线安装模式,分别有以下几种:

--prefer-offline:

优先使用缓存数据,如果没有匹配的缓存数据,则从远程仓库下载。

--prefer-online:

优先使用网络数据,如果网络数据请求失败,再去请求缓存数据,这种模式可以及时获取最新的模块。

--offline:

不请求网络,直接使用缓存数据,一旦缓存数据不存在,则安装失败。

文件完整性

上面我们多次提到了文件完整性,那么什么是文件完整性校验呢?

在下载依赖包之前,我们一般就能拿到npm对该依赖包计算的hash值,例如我们执行npminfo命令,紧跟tarball(下载链接)的就是shasum(hash):

用户下载依赖包到本地后,需要确定在下载过程中没有出现错误,所以在下载完成之后需要在本地在计算一次文件的hash值,如果两个hash值是相同的,则确保下载的依赖是完整的,如果不同,则进行重新下载。

整体流程

好了,我们再来整体总结下上面的流程:

检查.npmrc文件:

优先级为:

项目级的.npmrc文件>用户级的.npmrc文件>全局级的.npmrc文件>npm内置的.npmrc文件

检查项目中有无lock文件。

无lock文件:

从npm远程仓库获取包信息

根据package.json构建依赖树,构建过程:

构建依赖树时,不管其是直接依赖还是子依赖的依赖,优先将其放置在node_modules根目录。

当遇到相同模块时,判断已放置在依赖树的模块版本是否符合新模块的版本范围,如果符合则跳过,不符合则在当前模块的node_modules下放置该模块。

注意这一步只是确定逻辑上的依赖树,并非真正的安装,后面会根据这个依赖结构去下载或拿到缓存中的依赖包

在缓存中依次查找依赖树中的每个包

不存在缓存:

从npm远程仓库下载包

校验包的完整性

校验不通过:

重新下载

校验通过:

将下载的包复制到npm缓存目录

将下载的包按照依赖结构解压到node_modules

存在缓存:

将缓存按照依赖结构解压到node_modules

将包解压到node_modules

生成lock文件

有lock文件:

检查package.json中的依赖版本是否和package-lock.json中的依赖有冲突。

如果没有冲突,直接跳过获取包信息、构建依赖树过程,开始在缓存中查找包信息,后续过程相同

上面的过程简要描述了npminstall的大概过程,这个过程还包含了一些其他的操作,例如执行你定义的一些生命周期函数,你可以执行npminstallpackage--timing=true--loglevel=verbose来查看某个包具体的安装流程和细节。

yarn

yarn是在2016年发布的,那时npm还处于V3时期,那时候还没有package-lock.json文件,就像上面我们提到的:

不稳定性、安装速度慢等缺点经常会受到广大开发者吐槽。

此时,yarn诞生:

上面是官网提到的yarn的优点,在那个时候还是非常吸引人的。

当然,后来npm也意识到了自己的问题,进行了很多次优化,在后面的优化(lock文件、缓存、默认-s...)中,我们多多少少能看到yarn的影子,可见yarn的设计还是非常优秀的。

yarn也是采用的是npmv3的扁平结构来管理依赖,安装依赖后默认会生成一个yarn.lock文件,还是上面的依赖关系,我们看看yarn.lock的结构:

可见其和package-lock.json文件还是比较类似的,还有一些区别就是:

package-lock.json使用的是json格式,yarn.lock使用的是一种自定义格式

yarn.lock中子依赖的版本号不是固定的,意味着单独又一个yarn.lock确定不了node_modules目录结构,还需要和package.json文件进行配合。

而package-lock.json只需要一个文件即可确定。

yarn的缓策略看起来和npmv5之前的很像,每个缓存的模块被存放在独立的文件夹,文件夹名称包含了模块名称、版本号等信息。

使用命令yarncachedir可以查看缓存数据的目录。

yarn默认使用prefer-online模式,即优先使用网络数据,如果网络数据请求失败,再去请求缓存数据。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 文学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1