Skip to content
On this page

用过changesets的都知道,他在changeset version的时候会去寻找依赖当前包的包。然后提升另外一个包的依赖,递归下去。
简单来说就是假如你有 A,B,C,D四个包,且他们存在下面的依赖关系

json
// A pakcage.json
"dependencies":{
  "B":"workspace:*"
}
// B pakcage.json
"dependencies":{
  "C":"workspace:*"
}
// C pakcage.json
"dependencies":{
  "D":"workspace:*"
}
// D pakcage.json
"dependencies":{
  "lodash":"^1.0.0"
}

如果A需要发布新版本那 changesets只会发布 A
如果B发布新版本changesets会发布B ,A
如果D发布新版本changesets会发布D,C,B,A
那是如何实现这样的呢?

实现

假设工作区内的包版本数据如下

javascript
const deps = {
  shard: { version: "0.0.1", dep: { a: "0.0.1", b: "0.0.1", c: "0.0.1" } },
  sfc: { version: "0.0.1", dep: { d: "0.0.1", e: "0.0.1", shard: "0.0.1" } },
  utils: { version: "0.0.1", dep: { sfc: "0.0.1" } },
  e: { version: "0.0.1", dep: { a: "0.0.1" } },
  b: { version: "0.0.1", dep: {} },
  a: { version: "0.0.1", dep: {} },
  f: { version: "0.0.1", dep: { h: "0.0.1" } },
  h: { version: "0.0.1", dep: {} },
};

目标

  • h 升级变成 0.0.2 那 f 的 version 要变成 0.0.2
  • a 升级变成 0.0.2 那 shard sfc utils e 的 version 要变成 0.0.2
javascript
function getDepsGraph(pkgs) {
  let depsMap = new Map();
  let workspacePkgs = Object.keys(pkgs);
  // 初始化图谱
  for (let pkg of workspacePkgs) {
    depsMap.set(pkg, { version: pkgs[pkg].version, effect: new Set() });
  }
  // 遍历所有数据 将是工具区内的包加入到本包的 effect 中。
  for (let pkg in pkgs) {
    const curItem = pkgs[pkg];
    for (let dep in curItem.dep) {
      if (workspacePkgs.includes(dep)) {
        const target = depsMap.get(dep);
        target.effect.add(pkg);
      }
    }
  }
  return depsMap;
}

function getUpdatePkgs(updatePkg, pkgs) {
  const depsMap = getDepsGraph(pkgs);
  // 根据需要更新的包,找到它的依赖关系
  let updateEffects = getEffect(updatePkg, depsMap);

  return [...new Set(updateEffects)];
}

function getEffect(updatePkg, depsMap) {
  let arr = [];
  let effects = [...depsMap.get(updatePkg).effect];
  // 根据依赖关系找到 依赖包的依赖包
  // 比如 a=>b b=>c  所以需要找到C
  for (let effect of effects) {
    arr.push(effect);
    arr = arr.concat(getEffect(effect, depsMap));
  }
  return arr;
}

getDepsGraph方法调用后我们会得到一份与元数据相反的 索引MAP
image.png
它并不是记录那个包依赖那个包。**而是记录当前包被哪个包所依赖。**这个是关键!!!

javascript
console.log(getUpdatePkgs("shard", sfc)); // [ 'sfc', 'utils' ]

console.log(getUpdatePkgs("h", sfc)); // [ 'f' ]

console.log(getUpdatePkgs("a", sfc)); // [ 'shard', 'sfc', 'utils', 'e' ]

changesets实现这部分的逻辑在 packages/get-dependents-graph/index.ts可自行查看。

有了这些关系,我们甚至可以做更多的事情。比如 根据这个依赖关系 实现依赖关系的构建 ? 这是changesets没有的功能