npm与一次版本更新事故

最近Element-ui发布了2.0的版本,打算将之前为项目搭的后台管理系统进行升级,由于之前这方面的经验比较少,导致出现了一些比较蛋疼的问题,甚至导致本地的开发环境接近崩溃,于是记录下来,并整理的与npm相关的一些问题。

<!--more-->

参考:

1. 起因

事情的经过是这样的:

去官网查文档的时候提示发布了2.0正式版,发现添加了一些比较有用的功能(比如嵌套dialog、自定义icon以及组件样式更新等),于是在本地开了一个分支update_ele

由于node_modules一般会放在.gitignore中忽略提交,因此对于这种需要进行依赖库升级的分支,必须在切换分支时手动更新依赖库。(实际上克隆仓库然后单独更新应该是更明智的做法,但是当时脑子抽了,导致了后面的一系列问题)

事实上我对于npm也只停留在初级使用的阶段,所以相关的更新操作等都是边查文档边进行的。

然后就开始折腾了。

2. npm安装依赖包

2.1. 安装细节

通常在开发过程中,我们会按需安装相关的包,并且可以通过savesave-dev连个参数将该包添加进package.json,方便多人协作开发。他们的区别在于:

  • save将包添加进dependencies字段下,对应的运行时依赖库,即项目本身依赖的库,比如vue,jQuery等,简写方式-S
  • save-dev将包添加进devDependencies下,对应的时开发时依赖库,比如gulp等,简写方式-D

然而打开package.json我们会发现,大部分依赖包前面的都会有^~的符号,他们的意思是,在使用npm install命令时:

  • ^会匹配最新的大版本依赖包,比如^1.2.3会匹配所有1.x.x的包,包括1.3.0,但是不包括2.0.0
  • ~会匹配最近的小版本依赖包,比如~1.2.3会匹配所有1.2.x版本,但是不包括1.3.0
  • 如果没有任何前置修饰符,则表示安装对应制定的版本号

详情可见文档。默认使用-S-D安装时会自动添加^修饰符,因此在某些时候会造成版本的不兼容(所以说发版本包的时候版本号不能乱取啊)

2.2. 查看已安装的版本

通过上面我们知道package.json中的版本号,如果有前缀修饰符,则不能代表当前项目中具体使用的版本,如果我们需要查看具体的版本号,可以使用

npm list --depth=0

对应包名后面的`@x.x.x`即为当前使用的版本号,由npm自动帮助我们管理版本依赖。

2.3. 安装指定版本

# 查看对应包的所有可用版本
npm view element-ui versions

# 安装2.0.0
npm i element-ui@2.0.0 -S

2.4. 锁定版本

npm install会根据修饰符更新版本带来的一个问题就是版本兼容,如果我们自己的项目依赖于某个包的某个版本的特性,在该依赖包升级之后,向后兼容的代价也许会比较大。因此我们可能需要某种锁定包版本的问题。

一种方法是使用去除package.json的前缀修饰符,仅保留精确的版本号。

另一种方法是package-lock.json

升级到node8.0以后,npm也会升级到npm5,在之前的项目中使用npm进行安装的时候,会发现多了一个package-lock.json的文件,

  • 该文件中已经记录了整个 node_modules 文件夹的树状结构,甚至连模块的下载地址都记录了,再重新安装的时候只需要直接下载文件即可。
  • 当存在package-lock.json的文件时,使用npm install将不会再根据前缀修饰符更新模块(准确的说不会根据package.json文件安装模块),更新模块只能使用npm install xxx@v.v.v这样的形式进行,此时会自动更新package-lock.json的信息。

通过package-lock的文件可以保证项目保持一系列固定的依赖版本,而不同担心依赖库升级导致的版本冲突。

在之前使用过的PHP包管理工具composer中貌似也有对应的用于锁定版本的处理机制,即composer-lock文件。

2.5. 镜像

国内使用npm安装包比较慢,一般会使用镜像比如淘宝镜像,这里存在的坑是:尽量使用修改镜像仓库地址的方式,而不是使用cnpm

npm config set registry http://registry.npm.taobao.org/

因为早前使用cnpm遇见了很多依赖库版本不一致产生的冲突问题,比如

3. 版本升级

上面整理了npm使用过程中遇见的一些知识点。接下来就是回顾这次element-ui版本升级中遇见的一些问题。这应该也是大部分依赖库的升级过程中可能会遇到的问题。

3.1. 接口兼容

类似于1.x2.x之类的大版本更新,相关的接口改动可能会比较多,因此动手之前记得先查看官方的更新日志,比如releases。这样对于可能产生冲突的地方会有大致的了解。

比如element-ui2.0的版本对图标、dialog等组件进行了调整,在控制台也可以看见相关的警告(侧面说明选择一个稳定的库是多么重要)

3.2. 版本兼容

当我在新分支安装了2.0,更新了新接口之后,切换到旧分支时,需要重新安装对应版本的element-ui,通过查看package.json中的分支

"dependencies": {
    "element-ui": "^1.2.9",
}

然后手动安装了npm i element-ui@1.2.9 -S,然后发现样式不对~想必您已经知道原因了:前缀修饰符的存在导致package.json中的版本不一定正确。

然而当时我并不知道这个原因,然后又升级了vue的版本,接着vue-loader等一系列脚手架依赖库都报出了版本不对的错误,整个人都懵逼了。最后折腾了半天,删除了node_modules文件重新安装,最终可以跑起来了,然而我到现在都还不知道有没有引入新的BUG。

正如前面提到的,针对项目依赖库的升级,更明智的选择应当是克隆一个本地仓库然后独立进行开发,由于.gitignore的存在,多个分支会公用这部分本地文件,而来回的改动肯定会比较麻烦。

4. 小结

git用的不是很熟,npm用的也不熟,所以导致了这次事故的发生,幸好只是本地的开发环境崩掉了,不然后果还是比较严重的。

另外关于yarn基本上也没有接触过,有空可以试试。

《同构JavaScript应用开发》读书笔记 自定义Hexo主题