diff --git a/.changeset/twelve-gifts-rescue.md b/.changeset/twelve-gifts-rescue.md new file mode 100644 index 0000000000..004b2fb250 --- /dev/null +++ b/.changeset/twelve-gifts-rescue.md @@ -0,0 +1,5 @@ +--- +"@pnpm/workspace.pkgs-graph": patch +--- + +Speed up createPkgGraph when directory specifiers are present diff --git a/workspace/pkgs-graph/src/index.ts b/workspace/pkgs-graph/src/index.ts index 008f87d25c..8bbfa9974b 100644 --- a/workspace/pkgs-graph/src/index.ts +++ b/workspace/pkgs-graph/src/index.ts @@ -36,12 +36,8 @@ export function createPkgGraph (pkgs: Array, opts?: { } { const pkgMap = createPkgMap(pkgs) const pkgMapValues = Object.values(pkgMap) - const pkgMapByManifestName: Record = {} - for (const pkg of pkgMapValues) { - if (pkg.manifest.name) { - (pkgMapByManifestName[pkg.manifest.name] ??= []).push(pkg) - } - } + let pkgMapByManifestName: Record | undefined + let pkgMapByDir: Record | undefined const unmatched: Array<{ pkgName: string, range: string }> = [] const graph = mapValues((pkg) => ({ dependencies: createNode(pkg), @@ -73,15 +69,25 @@ export function createPkgGraph (pkgs: Array, opts?: { } if (spec.type === 'directory') { + pkgMapByDir ??= getPkgMapByDir(pkgMapValues) + const resolvedPath = path.resolve(pkg.dir, spec.fetchSpec) + const found = pkgMapByDir[resolvedPath] + if (found) { + return found.dir + } + + // Slow path; only needed when there are case mismatches on case-insensitive filesystems. const matchedPkg = pkgMapValues.find(pkg => path.relative(pkg.dir, spec.fetchSpec) === '') if (matchedPkg == null) { return '' } + pkgMapByDir[resolvedPath] = matchedPkg return matchedPkg.dir } if (spec.type !== 'version' && spec.type !== 'range') return '' + pkgMapByManifestName ??= getPkgMapByManifestName(pkgMapValues) const pkgs = pkgMapByManifestName[depName] if (!pkgs || pkgs.length === 0) return '' const versions = pkgs.filter(({ manifest }) => manifest.version) @@ -120,3 +126,21 @@ function createPkgMap (pkgs: Package[]): Record { } return pkgMap } + +function getPkgMapByManifestName (pkgMapValues: Package[]) { + const pkgMapByManifestName: Record = {} + for (const pkg of pkgMapValues) { + if (pkg.manifest.name) { + (pkgMapByManifestName[pkg.manifest.name] ??= []).push(pkg) + } + } + return pkgMapByManifestName +} + +function getPkgMapByDir (pkgMapValues: Package[]) { + const pkgMapByDir: Record = {} + for (const pkg of pkgMapValues) { + pkgMapByDir[path.resolve(pkg.dir)] = pkg + } + return pkgMapByDir +}