前端工程化(2)npm的内部机制和核心原理
前言
当我们拉取一个前端工程化项目,都会通过npm/Yarn/pnpm 管理工具来安装项目的依赖,运行项目,打包项目,基本上是前端开发三部曲。不知在前端开发过程中你是否考虑过下面几个问题:
1、安装依赖的时候(npm install),具体执行了什么操作?
2、怎么建设NPM私有库
3、在项目中安装依赖模块npm install报错和处理办法
带着以上几个问题的思考,我们一起来探索前端安装依赖相关的知识点~
一、从内部机制和核心原理了解npm
1.1、 npm 的安装机制和背后思想
1、npm install 执行之后,首先,检查并获取 npm 配置
2、检查项目中是否有 package-lock.json 文件
- 若有: 检查 package-lock.json 和 package.json 中声明的依赖是否一致:一致就直接使用package-lock.json 中的信息,从缓存或网络资源中加载依赖;不一致,则依据npm的版本进行处理
- 若无:则根据 package.json 递归构建依赖树,按照构建好的依赖树下载完整的依赖资源,在下载时就会检查是否存在相关资源缓存:存在缓存,就会将缓存内容解压到node_modules 中;不存在缓存,就从npm远程仓库下载包,并会检验包的完整性,随后添加到缓存,解压到node_modules 中生成package-lock.json。
3、最后生成 package-lock.json
1.2、 package-lock.json的作用
上面说到了npm install 的时候会检查项目中是否有 package-lock.json 文件,Lock文件的出现是为了解决 npm install 的不确定性问题 ,在 npm 5.x 版本新增了 package-lock.json 文件。
它的作用锁定安装时的包的版本号及包的依赖的版本号, 以保证其他所有人人在使用 npm install 时下载的依赖包都是一致的。
我们可以打开一个package-lock.json(例如下图)
看看其文件结构,我们可以看到最外面的两个属性 name 、version 同 package.json 中的 name 和 version ,用于描述当前包名称和版本。
dependencies 是一个对象,对象和 node_modules 中的包结构一一对应,对象的 key 为包名称,值为包的一些描述信息:
- version: 包版本这个包当前安装在 node_modules 中的版本
- resolved: 包具体的安装来源,通常是npm,也有是私有源
- integrity: 包 hash 值,来判断安装的依赖包是否被改动过、是否已失效源
- requires: 对应子依赖的依赖,与子依赖的 package.json 中 dependencies的依赖项相同
- dependencies: 存储安装在子依赖 node_modules 中的依赖包。
这里注意,并不是所有的子依赖都有 dependencies 属性,只有子依赖的依赖和当前已安装在根目录的 node_modules 中的依赖冲突之后,才会有这个属性。
1.3 node_modules 中模块目录结构
嵌套结构
npm3.x之前是嵌套结构,那时候如果我们的项目中依赖了公共库 A 和公共库 B,同时公共库 A 也依赖了公共库 B,那公共库 B 会被多次安装 结构如图
node_modules 的结构和 package.json 结构一一对应,层级结构明显,并且保证了每次安装目录结构都是相同的。但是一个项目中引用的模块非常多,嵌套层级很深这时候就出现:在不同层级的依赖中,可能引用了同一个模块,这样这个模块就存在多个地方。显然不符合编码简洁的思路。
扁平结构
为了解决以上问题,npm3版本进行了改造。把嵌套结构改为扁平结构: 安装模块时,不管其是直接依赖还是子依赖的依赖,优先将其安装在 node_modules 根目录。 还是上面的依赖结构,我们在执行 npm install 后将得到下面的目录结构
对应的,如果我们在项目代码中引用了一个模块,模块查找流程如下:
- 在当前模块路径下搜索
- 在当前模块 node_modules 路径下搜素
- 在上级模块的 node_modules 路径下搜索
- 直到搜索到全局路径中的 node_modules
但是有一种情况是,你的项目中没有直接依赖公共库D,但是公共库C和公共库B依赖了不同版本的公共库D,这时候是怎么处理的呢?
这时候版本号,就起到了很好的作用了
1.3、 npm 缓存机制
在执行 npm install 或 npm update命令下载依赖后,除了将依赖包安装在node_modules 目录下外,还会在本地的缓存目录缓存一份。
通过
npm config get cache
命令可以查询到: .npm/_cacache 目录
你也可以通过 文件目录: C:\Users\ {{YourUserName}} \AppData\Roaming\npm-cache_cacache查看
content-v2 里面存放的是一些二进制的文件
index-v5 其实就是存放的 content-v2的索引
tmp 是个空文件夹
1.3.1 这里的缓存是如何存储并且被利用的呢?
npm 在执行安装时,可以根据 package-lock.json
中存储的 integrity、version、name
生成一个唯一的 key 对应到 index-v5 目录下的缓存记录,从而找到 tar包的 hash,然后根据 hash 再去找缓存的 tar包,通过pacote
把对应的二进制文件解压到对应项目的 node_modules 下面,省去了网络下载资源的开销。
备注:pacote 从npm注册表中获取包清单和tarball的工具
npm主要有会有三个地方用到 pacote
:
- 执行 npm install xxx 会通过
pacote.extract
把对应的包解压到对应的node_modules
下面 - 执行 npm cache add xxx (这时候会通过
pacote.tarball 下的 tarballStream
往我们之前看到的_cacache
文件下去添加缓存 - 执行 npm pack xxx 通过
pacote.tarball 下的 _toFile
在当前路径生成对应的压缩文件
注意:以上的缓存策略是从 npm v5 版本开始的,在 npm v5 版本之前,每个缓存的模块在 ~/.npm 文件夹中以模块名的形式直接存储,储存结构是{cache}/{name}/{version}
二、 NPM 私有仓库建设指南
2.1、 npm 中的源(registry)
npm 中的源(registry),其实就是一个查询服务。以 npmjs.org 为例,它的查询服务网址是 registry.npmjs.org/ 这个网址后面跟上模块名,就会得到一个 JSON 对象,里面是该模块所有版本的信息。
在日常开发中,我们也常常会 发现直接用 npm 安装库有时候非常慢,容易安装失败,因为npm安装插件是从国外服务器下载,受网络的影响比较大,可能会出现异常。最好的解决方案是使用淘宝镜像 cnpm替代npm,正如它官网所描述
这是一个完整
npmjs.org
镜像,你可以用此代替官方版本(只读),同步频率目前为 10分钟 一次以保证尽量与官方服务同步。
我们可以直接全局使用cnpm命令行工具代替默认的npm
$ npm install -g cnpm --registry=https://registry.npmmirror.com
当然你可能不喜欢用cnpm命令,为了方便开发,我们可以把npm的源设置为淘宝镜像
$ npm config set registry http://registry.npmmirror.com
2.2、 为什么要搭建npm私有库
当我们业务规模达到一定程度的时候,可能会有一些自己公司私有的的UI的封装或者模块封装,不想通过npm发布,但是又想在一些项目和其他团队共享使用,而且我们不想将公共模块是复制到各个项目中来使用。这时候搭建NPM私有库就显得很有必要
-
npm
私有库只针对公司内部局域网开放,作为内部前端资产,不对外公开,也算是公司前端团队的一个技术亮点 -
速度比在直接在
npm
下载更快,甚至是比淘宝源更快,私有库能够将包资源进行缓存,响应的话会加快下载速度 -
对于发布和下载
npm
包配置权限管理
2.3、 Verdaccio搭建私有npm仓库
搭建npm私有库的方式很多,笔者推荐一款简单的轻量级私有 NPM 仓库Verdaccio
它的原理就是我们平时使用npm publish进行发布时,上传的仓库默认地址是npm,通过Verdaccio工具在本地新建一个仓库地址,再把本地的默认上传仓库地址切换到本地仓库地址即可。当npm install时没有找到本地的仓库,则Verdaccio默认配置中会从npm中央仓库下载。 当然它还可以 设置钉钉机器人推送发布消息呢!这里注意的是 它只支持Node.js>12 。
2.3.1 安装
npm install --location=global verdaccio
安装好后直接将地址 http://localhost:4873/ 粘贴到浏览器
2.3.1 发布
由于我们发布的是自己的私有库,这里发布时先进行指定仓库,否则发布包会发到当前使用的源地址,而不是我们的私有库地址。
我们打开cmd窗口,执行命令
npm publish --registry http://localhost:4873/
具体安装部署细节可以移步到Verdaccio官网
三、 在项目中安装依赖模块npm install报错集合
3.1、 node_modules 删除无权限
解决办法:
npm install rimraf -g
rimraf node_modules
3.2、 Error: Cannot find module 'node-sass'
sass-loader@8.0.0以上版本的时候不需要再安装node-sass, 有时候也会报没有python,也是因为node-sass 需要这个环境导致
解决办法:
npm install --global --production windows-build-tools
npm install node-sass --save-dev
当然大多数时候是你电脑本机的node版本和项目里的 node-sass包之间的版本存在兼容问题,可以通过node-sass查看版本支持情况
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanekek
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
excel下划线不显示怎么办
PHP中文网 06-23 -
怎样阻止微信小程序自动打开
PHP中文网 06-13 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
photoshop蒙版画笔没反应怎么办
PHP中文网 06-24