npm 包管理工具及package-lock.json 的更新策略

语义化版本

在一探package-lock.json究竟之前,你必须要理解semver。它是npm背后的小小功臣。你可以从这里了解到npm是如何使用它的。概括来讲,假若你在开发一个可供其它应用使用的应用,你必须说明每次升级变更会对第三方使用产生哪些影响。这就是语义化版本想要传达的。一个版本有三部分:X, Y, Z,分别指代大版本,小版本,与查缺补漏版本。比如1.2.3,那么就是大版本1,小版本2,bugfix版本3。bugfix版本不会影响任何功能,小版本变更往往是增加新功能,也不会影响使用。而大版本变更往往会带来使用层面不兼容的情况,需要再做调整。(想想webpack每次升级的时候!)

NPM包管理

正是为了让包管理变简单,npm出现了。一个项目可能有上百个依赖,每个依赖又有上百个依赖。为了你不陷入依赖地狱,只需简单几行命令,npm就可以安装并管理这些依赖,大大节省了时间。

  • 符号^:表示安装不低于该版本的应用,但是大版本号需相同,例如:vuex: "^3.1.3"3.1.3及其以上的3.x.x都是满足的。
  • 符号~:表示安装不低于该版本的应用,但是大版本号和小版本号需相同,例如:vuex: "^3.1.3"3.1.3及其以上的3.1.x都是满足的。
  • 无符号:无符号表示固定版本号,例如:vuex: "3.1.3",此时一定是安装3.1.3版本。

为什么需要package-lock.json

npm install 的输入是 package.json,它的输出是一棵 node_modules 树。理想情况下,npm install 应该像纯函数一样工作,对于同一个 package.json 总是生成完全相同的 node_modules 树。在某些情况下,确实如此。但在其他很多情况中,npm 无法做到这一点。有以下原因:

  • 不同版本的 npm 的安装算法不同。
  • 某些依赖项自上次安装以来,可能已发布了新版本,因此将根据 package.json 中的 semver-range version 更新依赖。
  • 某个依赖项的依赖项可能已发布新版本,即使您使用了固定依赖项说明符(1.2.3 而不是 ^1.2.3),它也会更新。

为了在不同的环境下生成相同的 node_modules,npm 使用 package-lock.json 或 npm-shrinkwrap.json。这两个文件都被称为 lockfiles。无论何时运行 npm install,npm 都会生成或更新 lockfiles。以下只讨论其中的 package-lock.json。

在.npmrc文件中设置package-lock = true,会在install 的时候产生package-lock.json的文件

 

 

不同 npm 版本下 npm i 的规则

  • npm 5.0.x 版本:不管 package.json 中依赖是否有更新,npm i 都会根据 package-lock.json 下载。针对这种安装策略,有人提出了这个 issue - #16866 ,然后就演变成了 5.1.0 版本后的规则。

  • 5.1.0 版本后:当 package.json 中的依赖项有新版本时,npm install 会无视 package-lock.json 去下载新版本的依赖项并且更新 package-lock.json。针对这种安装策略,又有人提出了一个 issue - #17979 ,参考 npm 贡献者 iarna 的评论,得出 5.4.2 版本后的规则。

  • 5.4.2 版本后:

    • 如果只有一个 package.json 文件,运行 npm i 会根据它生成一个 package-lock.json 文件。

    • 如果 package.json 的 semver-range version 和 package-lock.json 中版本兼容,即使此时 package.json 中有新的版本,执行 npm i 也还是会根据 package-lock.json 下载 - 实践场景1。

    • 如果手动修改了 package.json 的 version ranges,且和 package-lock.json 中版本不兼容,那么执行 npm i 时 package-lock.json 将会更新到兼容 package.json 的版本 - 实践场景2。

实践

npm 版本:6.4.1

场景1
  • 假设刚从远程仓库克隆一个项目,此时本地 node_modules 还不存在,package.json 和 package-lock.json 如下。已知 superagent 3.x.x 的最新版本是 3.8.3,那么运行 npm install 是根据 package-lock.json 中指定的版本 3.5.1 去下载还是根据 package.json 去下载最新的 3.x.x ?

    // package.json
    "dependencies": {
        "superagent": "^3.5.1"
    }
    
    // package-lock.json
    {
      "superagent": {
          "version": "3.5.1",
          "resolved": "https://npm.garenanow.com/superagent/-/superagent-3.5.1.tgz",
          "integrity": "sha1-Ck+u/aM2d3d4iDR917TSH0EMhxs=",
          "requires": {
            "component-emitter": "^1.2.0",
            "cookiejar": "^2.0.6",
            "debug": "^2.2.0",
            "extend": "^3.0.0",
            "form-data": "^2.1.1",
            "formidable": "^1.1.1",
            "methods": "^1.1.1",
            "mime": "^1.3.4",
            "qs": "^6.1.0",
            "readable-stream": "^2.0.5"
          }
        },
    }
    复制代码

    结论:下载的是 3.5.1。此时 package.json 和 package-lock.json 同时存在,package.json 的 version 是 ^3.5.1,package-lock.json 的 version 是 3.5.1,并且当前 node_modules 中下载的也是 3.5.1

场景2
  • 接着场景1,然后手动修改 package.json 中 superagent 的版本为 ^5.1.0,再执行 npm i,发现不管有没有删除已有的 node_modules,package-lock.json 中 superagent 的版本都变成了 5.1.0,node_modules 中的也变成了 5.1.0


链接:https://juejin.cn/post/6844903903193104398

posted on 2021-01-15 15:16  菜鸟丫丫  阅读(3122)  评论(0编辑  收藏  举报

导航