• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

前端工程化(2)npm的内部机制和核心原理

武飞扬头像
juejin
帮助666

前言

当我们拉取一个前端工程化项目,都会通过npm/Yarn/pnpm 管理工具来安装项目的依赖,运行项目,打包项目,基本上是前端开发三部曲。不知在前端开发过程中你是否考虑过下面几个问题:

1、安装依赖的时候(npm install),具体执行了什么操作?

2、怎么建设NPM私有库

3、在项目中安装依赖模块npm install报错和处理办法

带着以上几个问题的思考,我们一起来探索前端安装依赖相关的知识点~

一、从内部机制和核心原理了解npm

1.1、 npm 的安装机制和背后思想

未命名文件.png

1、npm install 执行之后,首先,检查并获取 npm 配置

2、检查项目中是否有 package-lock.json 文件

  1. 若有: 检查 package-lock.json 和 package.json 中声明的依赖是否一致:一致就直接使用package-lock.json 中的信息,从缓存或网络资源中加载依赖;不一致,则依据npm的版本进行处理
  2. 若无:则根据 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(例如下图)

微信截图_20210622155341.png

看看其文件结构,我们可以看到最外面的两个属性 name 、version 同 package.json 中的 name 和 version ,用于描述当前包名称和版本。

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

  1. version: 包版本这个包当前安装在 node_modules 中的版本
  2. resolved: 包具体的安装来源,通常是npm,也有是私有源
  3. integrity: 包 hash 值,来判断安装的依赖包是否被改动过、是否已失效源
  4. requires: 对应子依赖的依赖,与子依赖的 package.json 中 dependencies的依赖项相同
  5. dependencies: 存储安装在子依赖 node_modules 中的依赖包。

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

1.3 node_modules 中模块目录结构

嵌套结构

npm3.x之前是嵌套结构,那时候如果我们的项目中依赖了公共库 A 和公共库 B,同时公共库 A 也依赖了公共库 B,那公共库 B 会被多次安装 结构如图

未命名文件(1).png

node_modules 的结构和 package.json 结构一一对应,层级结构明显,并且保证了每次安装目录结构都是相同的。但是一个项目中引用的模块非常多,嵌套层级很深这时候就出现:在不同层级的依赖中,可能引用了同一个模块,这样这个模块就存在多个地方。显然不符合编码简洁的思路。

扁平结构

为了解决以上问题,npm3版本进行了改造。把嵌套结构改为扁平结构: 安装模块时,不管其是直接依赖还是子依赖的依赖,优先将其安装在 node_modules 根目录。 还是上面的依赖结构,我们在执行 npm install 后将得到下面的目录结构

image.png

未命名文件(1)(1).png

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

  1. 在当前模块路径下搜索
  2. 在当前模块 node_modules 路径下搜素
  3. 在上级模块的 node_modules 路径下搜索
  4. 直到搜索到全局路径中的 node_modules

但是有一种情况是,你的项目中没有直接依赖公共库D,但是公共库C和公共库B依赖了不同版本的公共库D,这时候是怎么处理的呢?

未命名文件(1)(2).png

这时候版本号,就起到了很好的作用了

1.3、 npm 缓存机制

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

通过

npm config get cache 

命令可以查询到: .npm/_cacache 目录

微信截图_20210622173746.png
你也可以通过 文件目录: C:\Users\ {{YourUserName}} \AppData\Roaming\npm-cache_cacache查看

微信截图_20210622173956.png content-v2 里面存放的是一些二进制的文件

image.png

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

image.png

安装好后直接将地址 http://localhost:4873/  粘贴到浏览器

2.3.1 发布

由于我们发布的是自己的私有库,这里发布时先进行指定仓库,否则发布包会发到当前使用的源地址,而不是我们的私有库地址。
我们打开cmd窗口,执行命令

npm publish --registry http://localhost:4873/

具体安装部署细节可以移步到Verdaccio官网

三、 在项目中安装依赖模块npm install报错集合

3.1、 node_modules 删除无权限

image.png

解决办法:

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 需要这个环境导致

image.png

解决办法:

npm install --global --production windows-build-tools
npm install node-sass --save-dev

当然大多数时候是你电脑本机的node版本和项目里的 node-sass包之间的版本存在兼容问题,可以通过node-sass查看版本支持情况

image.png

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanekek
系列文章
更多 icon
同类精品
更多 icon
继续加载