谁动了我的package-lock

7/27/2021 npmpackage-lock

血淋淋的教训只为呈现更好的文章内容

# package-lock 介绍

nodejs 对 package-lock 的介绍:package-lock.json 文件 (opens new window)

最重要的一句就是:

该文件旨在跟踪被安装的每个软件包的确切版本,以便产品可以以相同的方式被 100% 复制(即使软件包的维护者更新了软件包)。

# 问题的出现

今天新开了一个项目,就把一个项目的脚手架复制到另外一个项目去。然后突然出现了各种各样的问题。

最离谱就是同样的代码,另外一个域名运行的好好的,就新项目各种问题。。。没报错,本地运行没警告~

其中遇到最明显的就是 <slot></slot> 变为 undefined

这意味着下面的运行达不到预期的效果:

<!-- 忽略一堆vue的写法。。。 -->
<slot>content</slot>

<!-- 正常输出如下 -->
content

<!-- 打包后 -->
为空,甚至 undefined
1
2
3
4
5
6
7
8

偏偏项目中封装的组件多是用的都是默认插槽,有些甚至加了 v-if的判断,导致页面轻则不显示内容,重则整个页面 GG~

这一切都起源于:vue - 插槽文档 (opens new window) 2.6.0 之后对 slot 改了点东西。

# 问题复现的场景

  • package-lock.json 是忽略的文件
  • 使用 vue.js 并且在 vue.config.js 中使用外部引入 JS 的方式引入的 vue(并非从 node_modules)打包生成
  • 本地调试 OK,CI 打包后 GG
  • slot 多数为默认插槽,并且默认插槽内还有默认内容,甚至有的插槽使用了 v-if
  • pageage.json 中的 vue 版本为 "vue":"^2.6.10"。动态引入的 vue 版本也是 2.6.10

调试一番才发现,本地运行的 vue 版本使用的是 2.6.14。而且 vue-template-compiler 的版本也是 2.6.14。然而上线前的打包后引入的 vue.js 版本是 2.6.10!

不过我觉得最终的问题并不在于 vue 的版本,而是打包的时候 vue-template-compiler 的版本(因为如果单单是 vue 的问题,以前的项目早就出问题了,所以只能是打包时解析 vue 模版的库的版本也 vue 版本对应不上了!)

所以最后是先注释掉了 vue.config.js 中的 externals 配置。把 vue 的 cdn 去掉,还是改用打包的方式引入 vue.js。暂时解决了问题

PS:externals 配置是什么?webpack - externals 配置 (opens new window)

# package.json 文件符号解释

回到本地调试的问题,明明 package.json 写的是 2.6.10 版本,为什么实际使用的是 2.6.14 ?

注意看:"vue":"^2.6.10"。前面的 ^,同样在 package-lock.json 文件 (opens new window) 中有介绍,下面在概括一下

这样的符号一共有 4 个

  1. ^ 表示只锁主版本号"vue":"^2.6.10" 代表主版本号为 2。后面的会获取主版本号下最新的版本,截到现在,最新版本确实就是 2.4.16
  2. ~表示只锁主版本号和次版本号:还是以 "vue":"~2.6.10" 为例,主版本为 2,次版本为 6,最终还是会获取到 2.6.x 下最新的一个版本。
  3. 没有任何符号表示版本锁死"vue":"2.6.10" 就会指定是 2.6.10 。不会有变化
  4. * 代表最新的版本。如果写的是 "vue":"*"。哪天 vue3.0 更新到官网的稳定版了,再去安装会直接升级到 3.0

总结:

  • ^ 锁主版本
  • ~ 锁主+次版本
  • 锁定指定版本号
  • * 最新的版本

# 如何快速找到 node_modules 中的包

了解完 package.json 各个符号的定义后,再来说说我是怎么找到问题的:推荐一个 vscode 插件 Search node_modules (opens new window)

安装后,CTRL+P。输入 >node

然后就可以很快的搜索到我们想找到的 npm 包

打开 vue 的 package.json。虽然 _form 写的是 2.6.10。可是最底下实际安装的 version 是 14 的。

# package-lock 到底要不要删?

在这件事发生之前,我通常都会把 yarn.lock 或者 package-lock.json先删,在 npm i。甚至在项目的 .gitignore 把他们加入到了忽略文件中。

# package-lock.json 他会帮你一直锁定当前运行的版本号。

虽然 package.json 中有 4 种符号,好像如果使用了 ^ 之类的符号就会显得整个程序一直处于版本自动升级的状态。对于企业级项目来说是极其不稳定的,那 package-lock 文件就能帮你锁定当前运行的环境。

假设当前 package.json 的 vue 版本写的还是 "vue":"^2.6.10"。然后当前 vue 最新版本是 "vue":"^2.6.14"。这时候新建项目,安装的就是 "vue":"^2.6.14" 依赖。同时 package-lock.json 会记录下 vue 当前的 2.6.14 版本。

哪怕过了一个月后,vue 更新到了 2.7.0。只要有 package-lock.json 的版本记录,在怎么 npm i。安装的都是 2.6.14。有点类似于 package.json 中的 “空符号” 的意思。

只有完全锁定了版本,才能保证 “产品可以以相同的方式被 100% 复制(即使软件包的维护者更新了软件包)”

所以,你还敢乱删 package-lock.json 吗?

# 总结

  • package.json 的符号有 4 个

    • ^ 锁主版本
    • ~ 锁主+次版本
    • 锁定指定版本号
    • * 最新的版本

  • package-lock.json 视情况删除和忽略

    • 如果你们是一个朝气蓬勃,乐于升级的团队/个人,直接把版本号改为 "*"
    • 如果是项目要持续交付/对稳定运行有很高要求的,就千万别删了
    • 还有就是如果用了 webpack - externals 配置 (opens new window) 的也不要删,因为他会随时让你和你的 CDN 版本对不上号~
      从而引发一系列 “我的电脑上看没问题啊” 的错觉

又是吃一堑长一智的一天

Last Updated: 1/7/2024, 5:51:59 PM