linkPeers

tcmts.loader.packages.linkPeers · #426xqvdx · term · runs on the server

uses node:fs

Point each installed package's peers at the locked range its peer range accepts. Package managers resolve a peer by name across the whole install, so with two ranges of React in the cache, React DOM 18 could get React 19 (pnpm), or a second copy at the same version (npm). Two copies of one React break it, and the wrong one breaks it worse. A link inside the package wins: Node resolution looks there first.

import { compareVersions, satisfies as satisfies_ } from "#codebase/tcmts/core/semver";
import type { Layout } from "#codebase/tcmts/loader";
import { installDir, oneCopyEach, resolvesTo } from "#codebase/tcmts/loader/packages";
import type { PackageLock } from "#codebase/tcmts/loader/packages";
import fs from "node:fs";
import path from "node:path";

export function linkPeers(lay: Layout, lock: PackageLock) {
  const locked = lock.all();
  // (and the copy npm puts at a peer's name is the alias's)
  oneCopyEach(lay, locked);
  for (const l of locked) {
    const dir = installDir(lay, l.name, l.range);
    let real: string;
    let peers: Record<string, string>;
    try {
      real = fs.realpathSync(dir);
      peers =
        (
          JSON.parse(fs.readFileSync(path.join(real, "package.json"), "utf8")) as {
            peerDependencies?: Record<string, string>;
          }
        ).peerDependencies ?? {};
    } catch {
      continue;
    }
    for (const [peer, range] of Object.entries(peers)) {
      const fits = locked
        .filter((p) => p.name === peer && satisfies_(p.version, range))
        .sort((a, b) => compareVersions(b.version, a.version))[0];
      if (!fits) continue;
      let target: string;
      try {
        target = fs.realpathSync(installDir(lay, fits.name, fits.range));
      } catch {
        continue;
      }
      if (resolvesTo(peer, real) === target) continue;
      const link = path.join(real, "node_modules", peer);
      fs.mkdirSync(path.dirname(link), { recursive: true });
      fs.rmSync(link, { recursive: true, force: true });
      fs.symlinkSync(target, link, "dir");
    }
  }
}

uses

used by