Skip to content

Commit 48fa100

Browse files
Add enableWorkspacePatternAnalysis configuration option
1 parent a592371 commit 48fa100

File tree

5 files changed

+116
-6
lines changed

5 files changed

+116
-6
lines changed

.yarn/versions/607ebb1b.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
releases:
2+
"@yarnpkg/core": patch
3+
4+
declined:
5+
- "@yarnpkg/plugin-catalog"
6+
- "@yarnpkg/plugin-compat"
7+
- "@yarnpkg/plugin-constraints"
8+
- "@yarnpkg/plugin-dlx"
9+
- "@yarnpkg/plugin-essentials"
10+
- "@yarnpkg/plugin-exec"
11+
- "@yarnpkg/plugin-file"
12+
- "@yarnpkg/plugin-git"
13+
- "@yarnpkg/plugin-github"
14+
- "@yarnpkg/plugin-http"
15+
- "@yarnpkg/plugin-init"
16+
- "@yarnpkg/plugin-interactive-tools"
17+
- "@yarnpkg/plugin-jsr"
18+
- "@yarnpkg/plugin-link"
19+
- "@yarnpkg/plugin-nm"
20+
- "@yarnpkg/plugin-npm"
21+
- "@yarnpkg/plugin-npm-cli"
22+
- "@yarnpkg/plugin-pack"
23+
- "@yarnpkg/plugin-patch"
24+
- "@yarnpkg/plugin-pnp"
25+
- "@yarnpkg/plugin-pnpm"
26+
- "@yarnpkg/plugin-stage"
27+
- "@yarnpkg/plugin-typescript"
28+
- "@yarnpkg/plugin-version"
29+
- "@yarnpkg/plugin-workspace-tools"
30+
- "@yarnpkg/builder"
31+
- "@yarnpkg/cli"
32+
- "@yarnpkg/doctor"
33+
- "@yarnpkg/extensions"
34+
- "@yarnpkg/nm"
35+
- "@yarnpkg/pnpify"
36+
- "@yarnpkg/sdks"

packages/acceptance-tests/pkg-tests-specs/sources/commands/patchCommit.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ describe(`Commands`, () => {
114114
});
115115

116116
expect(manifest.resolutions).toEqual({
117-
[`no-deps@npm:1.0.0`]: expect.stringMatching(/^patch:no-deps/),
117+
[`no-deps@npm:1.0.0`]: expect.stringMatching(/^patch:no-deps/),
118118
});
119119
}),
120120
);

packages/acceptance-tests/pkg-tests-specs/sources/workspace.test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,27 @@ describe(`Workspaces tests`, () => {
3535
}),
3636
);
3737

38+
test(
39+
`it should support basic glob patterns with enableWorkspacePatternAnalysis`,
40+
makeTemporaryMonorepoEnv({
41+
workspaces: [
42+
`packages/*`,
43+
],
44+
}, {
45+
[`packages/foo`]: {},
46+
[`packages/bar`]: {},
47+
[`packages/baz`]: {},
48+
}, async ({path, run, source}) => {
49+
await run(`config`, `set`, `enableWorkspacePatternAnalysis`, `true`);
50+
await expect(getWorkspaces(run)).resolves.toStrictEqual([
51+
`.`,
52+
`packages/bar`,
53+
`packages/baz`,
54+
`packages/foo`,
55+
]);
56+
}),
57+
);
58+
3859
test(
3960
`it should support negated glob patterns`,
4061
makeTemporaryMonorepoEnv({
@@ -55,6 +76,27 @@ describe(`Workspaces tests`, () => {
5576
}),
5677
);
5778

79+
test(
80+
`it should support negated glob patterns with enableWorkspacePatternAnalysis`,
81+
makeTemporaryMonorepoEnv({
82+
workspaces: [
83+
`packages/*`,
84+
`!packages/foo`,
85+
],
86+
}, {
87+
[`packages/foo`]: {},
88+
[`packages/bar`]: {},
89+
[`packages/baz`]: {},
90+
}, async ({path, run, source}) => {
91+
await run(`config`, `set`, `enableWorkspacePatternAnalysis`, `true`);
92+
await expect(getWorkspaces(run)).resolves.toStrictEqual([
93+
`.`,
94+
`packages/bar`,
95+
`packages/baz`,
96+
]);
97+
}),
98+
);
99+
58100
test(
59101
`it should not implicitly make workspaces require-able`,
60102
makeTemporaryEnv(

packages/yarnpkg-core/sources/Configuration.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,11 @@ export const coreDefinitions: {[coreSettingName: string]: SettingsDefinition} =
348348
type: SettingsType.STRING,
349349
default: `npm:`,
350350
},
351+
enableWorkspacePatternAnalysis: {
352+
description: `If true, optimizes workspace pattern matching by separating static and dynamic globs for better performance when using mostly static patterns.`,
353+
type: SettingsType.BOOLEAN,
354+
default: false,
355+
},
351356
enableTransparentWorkspaces: {
352357
description: `If false, Yarn won't automatically resolve workspace dependencies unless they use the \`workspace:\` protocol`,
353358
type: SettingsType.BOOLEAN,

packages/yarnpkg-core/sources/Workspace.ts

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,19 +48,46 @@ export class Workspace {
4848
// @ts-expect-error: It's ok to initialize it now, even if it's readonly (setup is called right after construction)
4949
this.anchoredLocator = structUtils.makeLocator(ident, `${WorkspaceResolver.protocol}${this.relativeCwd}`);
5050

51-
const patterns = this.manifest.workspaceDefinitions.map(({pattern}) => pattern);
51+
const workspaceDefinitionPatterns = this.manifest.workspaceDefinitions.map(({pattern}) => pattern);
5252

53-
if (patterns.length === 0)
53+
if (workspaceDefinitionPatterns.length === 0)
5454
return;
5555

56-
const relativeCwds = await fastGlob(patterns, {
56+
const getOptimizedRelativeCwds = async () => {
57+
const staticPatterns: Array<string> = [];
58+
const dynamicPatterns: Array<string> = [];
59+
60+
workspaceDefinitionPatterns.forEach(pattern => {
61+
if (fastGlob.isDynamicPattern(pattern)) {
62+
dynamicPatterns.push(pattern);
63+
} else {
64+
staticPatterns.push(pattern);
65+
}
66+
});
67+
68+
const globResults = dynamicPatterns.length > 0
69+
? await resolveGlobPatterns(dynamicPatterns)
70+
: [];
71+
72+
// fast-glob returns results in arbitrary order
73+
return [...staticPatterns, ...globResults].sort();
74+
};
75+
76+
const getStandardRelativeCwds = async () => {
77+
const relativeCwds = await resolveGlobPatterns(workspaceDefinitionPatterns);
78+
// fast-glob returns results in arbitrary order
79+
return relativeCwds.sort();
80+
};
81+
82+
const resolveGlobPatterns = async (globPatterns: Array<string>) => fastGlob(globPatterns, {
5783
cwd: npath.fromPortablePath(this.cwd),
5884
onlyDirectories: true,
5985
ignore: [`**/node_modules`, `**/.git`, `**/.yarn`],
6086
});
6187

62-
// fast-glob returns results in arbitrary order
63-
relativeCwds.sort();
88+
const relativeCwds = this.project.configuration.get(`enableWorkspacePatternAnalysis`) ?
89+
await getOptimizedRelativeCwds() :
90+
await getStandardRelativeCwds();
6491

6592
await relativeCwds.reduce(async (previousTask, relativeCwd) => {
6693
const candidateCwd = ppath.resolve(this.cwd, npath.toPortablePath(relativeCwd));

0 commit comments

Comments
 (0)