yarn;扁平化结构;

疑问

  • 某次升级g6时,发生了包版本错误,错误的包为tslib,详见2021.3.2,同样的问题在新项目中未发生。当时认为发生错误的原因是因为项目中有过多依赖tslib不同版本的包,但只是猜测, 实际情况是?

    • 猜测的大前提是正确的,装包时首先会安装首层依赖xxxDependencies中列明的包,然后会解析首层依赖依赖的包,且不同的装包顺序会导致最后的包版本不同。当项目中有过多依赖依赖tslib时,发生错误的可能性会提高很多。
    • 但是依然存在问题,既然g6需求某个版本的tslib,为什么最后的装包结果出现异常,是否是因为g6自己没处理好包管理问题?

      摘录&心得

  • yarn是一个javascript包管理器

  • npm的不足
    • npm依赖完整性和一致性保障较差(npm新版学习了yarn,在这点上有了进步)
    • npm慢
  • yarn的优点
    • 确定性:引入了yarn.lock机制,后来npm v5后也借鉴了yarn,采用package-lock机制。
    • 扁平化安装:不同版本的依赖包会(按照一定策略?)归结为一个版本(npm也抄了这个)
    • 网络性能:总之就是快
    • 缓存、离线:顾名思义,npm也有类似机制
  • yarn没有采用JSON格式,自成一体
  • yarn.lock 中子依赖的版本号不是固定版本,因此需要和package.json联合确定node_modules结构。
  • Yarn 默认优先使用网络数据,请求失败才使用缓存数据

    yarn安装机制

    image.png

  • 检测包:检测有无npm相关文件、和可能导致失败的问题。

  • 解析包
    1. 首层依赖:package.json 定义的 dependencies、devDependencies、optionalDependencies
    2. 遍历首层依赖,递归每个依赖下的嵌套依赖
      • 将解析过的、未解析过的包用Set数据结构存储,保证同一个版本范围内的包不会被重复解析。
      • 如果在 yarn.lock 中没有找到包 A,则向 Registry 发起请求获取满足版本范围的已知最高版本的包信息,获取后将当前包标记为已解析。
  • 获取包:缓存中存在则直接用,不存在、出错时都重新下载更新缓存。
  • 链接包
    • 上一步是下载,这一步是复制到项目node_modules目录
    • yarn会优先检测peerDependecies,找不到会警告,但是默默复制拷贝一份到项目中。
    • 遵循扁平化原则
  • 构建包:包中存在二进制包时会触发

    破解依赖困境

  • 什么是依赖困境

    • 嵌套地狱(早期npm v2):项目依赖树的层级非常深
      • 路径名过长,在windows下失败
    • 可能存在同版本的相同依赖
      • 依赖冗余,安装过程过长
  • 如何破解
    • 依靠扁平化原则管理依赖包

      扁平化结构原理

      模块的安装顺序可能影响 node_modules 内的文件结构
      1、一开始,APP依赖A1,A1依赖B1
      image.png
      2、然后,APP添加了依赖C1,C1依赖B2
      image.png
      3、然后,APP添加依赖D1,D1依赖B2
      image.png
      4、然后,APP添加依赖E1,E1依赖B1
      image.png
      5、然后,A1更新为A2,A2依赖B2
      image.png
      6、设想如果E1更新到E2,E2依赖B2呢?
      image.png
      7、可以删除 node_modules,重新安装,利用 npm 的依赖分析能力,得到一个更清爽的结构。(或使用 npm dedupe)。如果使用yarn的话,在安装依赖时会自动执行 dedupe 命令。
      image.png