今天学到了什么|npm install引发的一系列问题

1,431 阅读5分钟

一、起因

elemenu-ui只支持vue2.x的版本,而我们整个项目是基于vue3的,想在Vue3.x中使用,需要引入element-plus~

  • 安装:
npm install element-plus --save
// 或者:
yarn add element-plus --save
  • main.ts中引入:
import { createApp } from 'vue'
import ElementPlus from 'element-plus';
import 'element-plus/lib/theme-chalk/index.css';
import App from './App.vue';
 
const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')

OK,正常work!

二、问题

之前按照上述步骤安装element-plus能正常work,然而某天我新增了一个依赖包并npm install之后element-plus却一直报错,debug了好久,终于发现了问题所在。原来是因为element-plus近期更新比较频繁,npm install之后安装了最新版本,导致了一系列的错误。

image.png 试了试更新Vue版本至Vue3.3+,可以正常使用element-plus,但这又导致我们项目中使用的另一个包出现了问题不能正常work,最后还是将element-plus回退到了之前的版本。 

// eg:
npm i element-plus@1.0.2-beta.71 --save

三、深入

1、devDependencies与dependencies

我们在使用npm install 安装模块或插件的时候,有两种命令将其写入到package.json文件:

--save-dev 和 --save
// 简写形式:
-D 和 -S

它们的区别在于:使用--save-dev安装的模块或插件,会被写入到devDependencies里面,而使用--save安装的,则是被写入到dependencies里面。

package.json里面的devDependencies和dependencies对象又有什么区别呢?

devDependencies里面的插件只用于开发环境,不用于生产环境,而dependencies是需要发布到生产环境的。比如我们写项目页面要依赖于element-plus,没有这个包的依赖运行就会报错,这时候就需要写入dependencies;而我们使用的一些构建工具比如webpack这些只是在开发中使用的包,上线后就和它们没关系了,所以将它们写入devDependencies。

2、npm install发生了什么

大致流程:

(1)确定首层依赖——package.json中dependencies 和 devDependencies 属性中直接指定的依赖;

(2)递归获取模块:模块信息——模块实体——模块依赖;

(3)模块扁平化:去掉冗余模块;(v3之后)

(4)安装模块,更新node_modules;

(5)生成或更新版本描述文件。

3、npm install的不确定性

前面提到我遇到的问题是因为npm install时自动更新了版本,npm的依赖版本管理非常宽松,同一个项目一天之内可能会install不同版本的依赖,而依赖包的升级很有可能带来bug。

我们在dependencies里面指定的版本号称为语义化版本号,这里插播一下语义化版本号的规则:主版本号.次版本号.修订号,并且版本号的递增规则如下:

  • 主版本号:做了不兼容的 API 修改
  • 次版本号:做了向下兼容的功能性新增
  • 修订号:做了向下兼容的问题修复

依赖的版本范围用三种符号指定:

  • ~:只升级修订号
  • ^:升级次版本号和修订号
  • *:升级到最新版本

比如我们的package.json里有这样的依赖:

  "dependencies": {
    "echarts": "^5.1.1",
    "vue": "^3.0.11"
  },

我们就知道^是什么意思 & npm install的时候会安装什么了。在这个例子中,如果echarts的版本超过5.1.1并在大版本号(5)上相同,就允许下载最新的echarts包,我们npm install的时候下载的具体版本号可能是5.2.1(或者别的)。

语义化版本号定义了我们理想的版本更新规则,但在实际安装时依赖版本有可能和我们指定的不一致,这就是npm install的不确定性问题。为了解决这一问题,npm在5.0+默认会生成package-lock.json文件“锁”住版本号。

自npm 5.0版本发布以来,npm install的规则发生了三次变化:

  • npm 5.0.x 版本,不管package.json怎么变,npm install时都会根据package-lock.json文件下载;
  • 5.1.0版本后,npm install会无视package-lock.json文件去下载最新的包;
  • 5.4.2版本后,如果改了package.json,且package.json和package-lock.json文件不同,那么执行npm install时npm会根据package.json中的版本号以及语义含义去下载最新的包,并更新至package-lock.json。如果两者是同一状态,那么执行npm install会根据package-lock.json下载,不会理会package.json实际包的版本是否有更新。

4、npm install相关问题排查

我们拿到一个项目,要本地运行起来的第一步一般都是执行npm install,但往往npm install的时候并不顺利,常常报错。我们一般怎么去解决呢?

1、根据报错信息debug

报错的原因千千万,不能一言以蔽之,这时候还需要具体问题具体对待。

2、查看node版本和registry

通过查看node版本和registry,可以判断是不是因为项目所依赖的包和我们所使用的node版本存在不兼容问题,或是我们要下载的包是通过当前registry下载不到的,从而排查问题。

3、清除npm缓存

npm会缓存每个包的具体版本和下载链接,后续就不需要再去远程仓库进行查询,从而减少了大量网络请求。但是缓存也可能导致问题出现,试试清除缓存:

npm cache clean --force
4、尝试yarn

有时候npm install报错,但yarn install却能成功安装。yarn的出现是为了解决npm v3版本的问题,它除了带来安装速度的提升以外,最大的贡献是通过lock文件来保证安装依赖的确定性,不论在何种环境何种机器上安装依赖都会得到相同的结果,也就是相同的node_modules目录结构。  

四、总结

通过此次debug,学到了:

(1)安装依赖时,选择合适的--save-dev 或 --save;

(2)安装依赖时单独安装,避免手动修改 package.json 或 yarn.lock 等文件;

(3)npm install报错时该怎么去排查问题。