Skip to content

Commit 0871ade

Browse files
committed
perf(workspace): lazy import for filtered graph building
When building filtered graphs (e.g., aspects-only), use preferDependencyGraph and filter deps before import to avoid fetching huge dependency trees for components that will be filtered out.
1 parent fa18e57 commit 0871ade

File tree

1 file changed

+32
-5
lines changed

1 file changed

+32
-5
lines changed

scopes/workspace/workspace/build-graph-from-fs.ts

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,16 @@ export class GraphFromFsBuilder {
5959
* we keep performance sane as the importMany doesn't run multiple time and therefore the round
6060
* trips to the remotes are minimal.
6161
*
62+
* LAZY IMPORT MODE (when shouldLoadItsDeps is provided):
63+
* when a filter function (shouldLoadItsDeps) is provided, we use "lazy import" mode to optimize
64+
* performance. instead of importing all flattened dependencies at once, we:
65+
* 1. only import dependencies that pass the filter (e.g., only aspects)
66+
* 2. don't fetch their flattened dependencies upfront (includeDependencies: false)
67+
* 3. let the recursive depth iteration handle importing deps as needed
68+
* this is much more efficient when building filtered graphs (e.g., aspects-only graph) because
69+
* we avoid fetching huge dependency trees for components we don't care about.
70+
*
71+
* TRADITIONAL MODE (without filter):
6272
* normally, one importMany of the seeders is enough as importMany knows to fetch all flattened.
6373
* however, since this buildGraph is performed on the workspace, a dependency may be new or
6474
* modified and as such, we don't know its flattened yet.
@@ -106,24 +116,41 @@ export class GraphFromFsBuilder {
106116
/**
107117
* only for components from the workspace that can be modified to add/remove dependencies, we need to make sure that
108118
* all their dependencies are imported.
109-
* remember that `importMany` fetches all flattened dependencies. once a component from scope is imported, we know
110-
* that all its flattened dependencies are there. no need to call importMany again for them.
119+
*
120+
* when `shouldLoadItsDeps` is provided, we use "lazy import" mode:
121+
* - only import filtered dependencies (those passing the shouldLoadItsDeps check)
122+
* - use preferDependencyGraph to avoid fetching flattened dependencies
123+
* - the recursive depth iteration will handle importing deps as needed
124+
* this is much more efficient when building a filtered graph (e.g., aspects-only graph)
125+
*
126+
* without a filter, we use the traditional approach:
127+
* - `importMany` fetches all flattened dependencies (preferDependencyGraph: false)
128+
* - once a component from scope is imported, all its flattened dependencies are there
111129
*/
112130
private async importObjects(components: Component[]) {
113131
const workspaceIds = this.workspace.listIds();
114132
const compOnWorkspaceOnly = components.filter((comp) => workspaceIds.find((id) => id.isEqual(comp.id)));
115-
const allDeps = (await Promise.all(compOnWorkspaceOnly.map((c) => this.getAllDepsUnfiltered(c)))).flat();
133+
134+
// when shouldLoadItsDeps is provided, use lazy import: only import filtered deps without their flattened
135+
const useLazyImport = Boolean(this.shouldLoadItsDeps);
136+
const getDepsFunc = useLazyImport
137+
? (c: Component) => this.getAllDepsFiltered(c)
138+
: (c: Component) => this.getAllDepsUnfiltered(c);
139+
140+
const allDeps = (await Promise.all(compOnWorkspaceOnly.map(getDepsFunc))).flat();
116141
const allDepsNotImported = allDeps.filter((d) => !this.importedIds.includes(d.toString()));
117142
const exportedDeps = allDepsNotImported.map((id) => id).filter((dep) => this.workspace.isExported(dep));
118143
const scopeComponentsImporter = this.consumer.scope.scopeImporter;
119144
await scopeComponentsImporter.importMany({
120145
ids: ComponentIdList.uniqFromArray(exportedDeps),
121-
preferDependencyGraph: false,
146+
preferDependencyGraph: useLazyImport,
122147
throwForDependencyNotFound: this.shouldThrowOnMissingDep,
123148
throwForSeederNotFound: this.shouldThrowOnMissingDep,
124149
reFetchUnBuiltVersion: false,
125150
lane: this.currentLane,
126-
reason: 'for building a graph from the workspace',
151+
reason: useLazyImport
152+
? 'for building a filtered graph from the workspace (lazy)'
153+
: 'for building a graph from the workspace',
127154
});
128155
allDepsNotImported.map((id) => this.importedIds.push(id.toString()));
129156
}

0 commit comments

Comments
 (0)