我们在使用 npm 安装项目依赖的时候,发现依赖都有相应的符合,那么这些符号的作用是什么呢?

    1. "dependencies": {
    2. "amfe-flexible": "^2.2.1",
    3. "axios": "^0.21.1",
    4. "chalk": "^2.4.2",
    5. "core-js": "^3.6.5"
    6. }

    如果我们编写一个 npm A 包,然后这个 A 又依赖于 B,我们在编写代码的时候 B 的版本是 2.3.4,我们希望别人使用我们 A 包的时候一定也要安装 B 包,并且是 2.3.4 这个版本或者更高的版本,那么这个更高到底是多高呢?

    下面是包版本的规范:
    包的版本主要是三部分组成:主版本号.次版本号.补丁版本号

    • 主版本号:仅当程序发生了重大变化时才会增长,如新增了重要功能、新增了大量的 API、技术架构发生了重大变化
    • 次版本号:仅当程序发生了一些小变化时才会增长,如新增了一些小功能、新增了一些辅助型的 API
    • 补丁版本号:仅当解决了一些 bug 或 进行了一些局部优化时更新,如修复了某个函数的 bug、提升了某个函数的运行效率

    有的时候,我们希望安装某个依赖包的时候,次版本号和补丁版本号是可以有提升的,但是主版本号不能变化,因为内容发生了重大的更新。
    有的时候,我们又希望安装依赖包的时候,只有补丁版本号可以提升,其他都不能提升,因为只修复了某些 bug。
    甚至我们希望依赖包保持固定的版本,尽管这比较少见。
    这样一来,就需要在配置文件中描述清楚具体的依赖规则,而不是直接写上版本号那么简单,所以我们需要一种机制来描述安装依赖时候我能接受的版本范围。

    符号 描述 示例 示例描述
    > 大于某个版本 >1.2.1 大于1.2.1版本
    >= 大于等于某个版本 >=1.2.1 大于等于1.2.1版本
    < 小于某个版本 <1.2.1 小于1.2.1版本
    <= 小于等于某个版本 <=1.2.1 小于等于1.2.1版本
    - 介于两个版本之间 1.2.1 - 1.4.5 介于1.2.1和1.4.5之间
    x 不固定的版本号 1.3.x 只要保证主版本号是1,次版本号是3即可
    ~ 补丁版本号可增 ~1.3.4 保证主版本号是1,次版本号是3,补丁版本号大于等于4
    ^ 此版本和补丁版本可增 ^1.3.4 保证主版本号是1,次版本号可以大于等于3,补丁版本号可以大于等于4
    * 最新版本 * 始终安装最新版本

    版本依赖控制始终是一个两难的问题:
    如果允许版本增加,可以让依赖包的 bug 得以修复(补丁版本号),但是又可能带来一些意外的惊喜(次版本号),但同样可能带来不确定的风险(新的 bug)。
    如果不允许版本增加,可以获得最好的稳定性,但失去了依赖包自我优化的能力。
    而有的时候情况更加复杂,如果依赖包升级后,依赖也发生了变化,会有更多不确定的情况出现。
    基于此,npm 在安装包的时候,会自动生成一个 package-lock.json 文件,该文件记录了安装包时的确切依赖关系。
    当别人拷贝我们工程目录的时候,如果拷贝了 package-lock.json 文件,恢复安装时,会按照 package-lock.json 文件中的确切依赖进行安装,最大限度的避免了差异。

    npm 安装依赖最初是嵌套的结构:

    1. node_modules
    2. A
    3. node_modules
    4. B
    5. node_modules
    6. C
    7. node_modules

    后来优化改成了扁平化的处理:

    1. node_modules
    2. A
    3. B
    4. C

    这个时候,如果两个包依赖同一个包的不同版本,那么 npm 会把冲突的包继续使用嵌套的结构:

    1. node_modules
    2. A
    3. node_modules
    4. lodash@3.2.1
    5. B
    6. node_modules
    7. lodash@4.5.6
    8. C