Skip to content

Commit 00783f5

Browse files
authored
perf: Speed up getTargets (#15228)
1 parent 543c15a commit 00783f5

9 files changed

Lines changed: 134 additions & 45 deletions

File tree

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import Benchmark from "benchmark";
2+
import baseline from "@babel-baseline/helper-compilation-targets";
3+
import current from "@babel/helper-compilation-targets";
4+
import { report } from "../util.mjs";
5+
6+
const suite = new Benchmark.Suite("", { initCount: 0 });
7+
function benchCases(implementation, name) {
8+
suite.add(name + "#getTargets last1", () => {
9+
implementation({
10+
browsers: [
11+
"last 1 chrome version",
12+
"last 1 firefox version",
13+
"last 1 safari version",
14+
"last 1 iOS version",
15+
"last 1 edge version",
16+
],
17+
});
18+
});
19+
suite.add(name + "#getTargets last100", () => {
20+
implementation({
21+
browsers: [
22+
"last 100 chrome version",
23+
"last 100 firefox version",
24+
"last 100 safari version",
25+
"last 100 iOS version",
26+
"last 100 edge version",
27+
],
28+
});
29+
});
30+
suite.add(name + "#getTargets chrome 49 ie 11", () => {
31+
implementation({
32+
browsers: ["chrome 49", "ie 11"],
33+
});
34+
});
35+
}
36+
37+
benchCases(baseline.default, "baseline");
38+
benchCases(current.default, "current");
39+
40+
suite.on("cycle", report).run();

benchmark/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@
55
"devDependencies": {
66
"@babel-baseline/core": "npm:@babel/core@7.18.5",
77
"@babel-baseline/generator": "npm:@babel/generator@7.18.2",
8+
"@babel-baseline/helper-compilation-targets": "npm:@babel/helper-compilation-targets@7.20.0",
89
"@babel-baseline/helper-validator-identifier": "npm:@babel/helper-validator-identifier@7.16.7",
910
"@babel-baseline/parser": "npm:@babel/parser@7.18.5",
1011
"@babel-baseline/traverse": "npm:@babel/traverse@7.18.5",
1112
"@babel-baseline/types": "npm:@babel/types@7.18.4",
1213
"@babel/core": "workspace:^",
1314
"@babel/generator": "workspace:^",
15+
"@babel/helper-compilation-targets": "workspace:^",
1416
"@babel/helper-validator-identifier": "workspace:^",
1517
"@babel/parser": "workspace:^",
1618
"@babel/preset-env": "workspace:^",

packages/babel-helper-compilation-targets/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"@babel/compat-data": "workspace:^",
2626
"@babel/helper-validator-option": "workspace:^",
2727
"browserslist": "^4.21.3",
28+
"lru-cache": "condition:BABEL_8_BREAKING ? ^7.14.1 : ^5.1.1",
2829
"semver": "condition:BABEL_8_BREAKING ? ^7.3.4 : ^6.3.0"
2930
},
3031
"peerDependencies": {
@@ -33,6 +34,7 @@
3334
"devDependencies": {
3435
"@babel/core": "workspace:^",
3536
"@babel/helper-plugin-test-runner": "workspace:^",
37+
"@types/lru-cache": "^5.1.1",
3638
"@types/semver": "^5.5.0"
3739
},
3840
"engines": {

packages/babel-helper-compilation-targets/src/debug.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export function getInclusionReasons(
1212
targetVersions: Targets,
1313
list: { [key: string]: Targets },
1414
) {
15-
const minVersions = list[item] || ({} as Targets);
15+
const minVersions = list[item] || {};
1616

1717
return (Object.keys(targetVersions) as Target[]).reduce((result, env) => {
1818
const minVersion = getLowestImplementedVersion(minVersions, env);

packages/babel-helper-compilation-targets/src/index.ts

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import browserslist from "browserslist";
22
import { findSuggestion } from "@babel/helper-validator-option";
33
import browserModulesData from "@babel/compat-data/native-modules";
4+
import LruCache from "lru-cache";
45

56
import {
67
semverify,
@@ -45,7 +46,7 @@ function validateTargetNames(targets: Targets): TargetsTuple {
4546
}
4647
}
4748

48-
return targets as any;
49+
return targets;
4950
}
5051

5152
export function isBrowsersQueryValid(browsers: unknown): boolean {
@@ -70,7 +71,7 @@ function getLowestVersions(browsers: Array<string>): Targets {
7071
BrowserslistBrowserName,
7172
string,
7273
];
73-
const target: Target = browserNameMap[browserName];
74+
const target = browserNameMap[browserName];
7475

7576
if (!target) {
7677
return all;
@@ -108,7 +109,7 @@ function getLowestVersions(browsers: Array<string>): Targets {
108109

109110
function outputDecimalWarning(
110111
decimalTargets: Array<{ target: string; value: number }>,
111-
): void {
112+
) {
112113
if (!decimalTargets.length) {
113114
return;
114115
}
@@ -123,7 +124,7 @@ getting parsed as 6.1, which can lead to unexpected behavior.
123124
`);
124125
}
125126

126-
function semverifyTarget(target: keyof Targets, value: string) {
127+
function semverifyTarget(target: Target, value: string) {
127128
try {
128129
return semverify(value);
129130
} catch (error) {
@@ -141,7 +142,7 @@ function nodeTargetParser(value: true | string) {
141142
value === true || value === "current"
142143
? process.versions.node
143144
: semverifyTarget("node", value);
144-
return ["node" as const, parsed] as const;
145+
return ["node", parsed] as const;
145146
}
146147

147148
function defaultTargetParser(
@@ -158,7 +159,7 @@ function generateTargets(inputTargets: InputTargets): Targets {
158159
const input = { ...inputTargets };
159160
delete input.esmodules;
160161
delete input.browsers;
161-
return input as any as Targets;
162+
return input;
162163
}
163164

164165
function resolveTargets(queries: Browsers, env?: string): Targets {
@@ -169,6 +170,18 @@ function resolveTargets(queries: Browsers, env?: string): Targets {
169170
return getLowestVersions(resolved);
170171
}
171172

173+
const targetsCache = new LruCache({ max: 64 });
174+
175+
function resolveTargetsCached(queries: Browsers, env?: string): Targets {
176+
const cacheKey = typeof queries === "string" ? queries : queries.join() + env;
177+
let cached = targetsCache.get(cacheKey) as Targets | undefined;
178+
if (!cached) {
179+
cached = resolveTargets(queries, env);
180+
targetsCache.set(cacheKey, cached);
181+
}
182+
return { ...cached };
183+
}
184+
172185
type GetTargetsOption = {
173186
// This is not the path of the config file, but the path where start searching it from
174187
configPath?: string;
@@ -181,7 +194,7 @@ type GetTargetsOption = {
181194
};
182195

183196
export default function getTargets(
184-
inputTargets: InputTargets = {} as InputTargets,
197+
inputTargets: InputTargets = {},
185198
options: GetTargetsOption = {},
186199
): Targets {
187200
let { browsers, esmodules } = inputTargets;
@@ -190,7 +203,7 @@ export default function getTargets(
190203
validateBrowsers(browsers);
191204

192205
const input = generateTargets(inputTargets);
193-
let targets: TargetsTuple = validateTargetNames(input);
206+
let targets = validateTargetNames(input);
194207

195208
const shouldParseBrowsers = !!browsers;
196209
const hasTargets = shouldParseBrowsers || Object.keys(targets).length > 0;
@@ -233,7 +246,10 @@ export default function getTargets(
233246
// or an empty array (without any user config, use default config),
234247
// we don't need to call `resolveTargets` to execute the related methods of `browserslist` library.
235248
if (browsers?.length) {
236-
const queryBrowsers = resolveTargets(browsers, options.browserslistEnv);
249+
const queryBrowsers = resolveTargetsCached(
250+
browsers,
251+
options.browserslistEnv,
252+
);
237253

238254
if (esmodules === "intersect") {
239255
for (const browser of Object.keys(queryBrowsers) as Target[]) {
@@ -258,7 +274,7 @@ export default function getTargets(
258274
}
259275

260276
// Parse remaining targets
261-
const result: Targets = {} as Targets;
277+
const result: Targets = {};
262278
const decimalWarnings = [];
263279
for (const target of Object.keys(targets).sort() as Target[]) {
264280
const value = targets[target];

packages/babel-helper-compilation-targets/src/pretty.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ export function prettifyVersion(version: string) {
77
return version;
88
}
99

10-
const parts = [semver.major(version)];
11-
const minor = semver.minor(version);
12-
const patch = semver.patch(version);
10+
const { major, minor, patch } = semver.parse(version);
11+
12+
const parts = [major];
1313

1414
if (minor || patch) {
1515
parts.push(minor);

packages/babel-helper-compilation-targets/src/types.d.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,8 @@ export type Targets = {
1717
[target in Target]?: string;
1818
};
1919

20-
export type TargetsTuple = {
21-
[target in Exclude<Target, "node">]: string;
22-
} & {
23-
node: string | true;
20+
export type TargetsTuple = Omit<Targets, "node"> & {
21+
node?: string | true;
2422
};
2523

2624
export type Browsers = string | ReadonlyArray<string>;

packages/babel-helper-compilation-targets/src/utils.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,14 @@ export function semverify(version: number | string): string {
2929
`'${version}' is not a valid version`,
3030
);
3131

32-
const split = version.toString().split(".");
33-
while (split.length < 3) {
34-
split.push("0");
32+
version = version.toString();
33+
34+
let pos = 0;
35+
let num = 0;
36+
while ((pos = version.indexOf(".", pos + 1)) > 0) {
37+
num++;
3538
}
36-
return split.join(".");
39+
return version + ".0".repeat(2 - num);
3740
}
3841

3942
export function isUnreleasedVersion(

yarn.lock

Lines changed: 51 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,20 @@ __metadata:
5555
languageName: node
5656
linkType: hard
5757

58+
"@babel-baseline/helper-compilation-targets@npm:@babel/helper-compilation-targets@7.20.0, @babel/helper-compilation-targets@npm:^7.17.7, @babel/helper-compilation-targets@npm:^7.18.2, @babel/helper-compilation-targets@npm:^7.18.9, @babel/helper-compilation-targets@npm:^7.20.0":
59+
version: 7.20.0
60+
resolution: "@babel/helper-compilation-targets@npm:7.20.0"
61+
dependencies:
62+
"@babel/compat-data": ^7.20.0
63+
"@babel/helper-validator-option": ^7.18.6
64+
browserslist: ^4.21.3
65+
semver: ^6.3.0
66+
peerDependencies:
67+
"@babel/core": ^7.0.0
68+
checksum: bc183f2109648849c8fde0b3c5cf08adf2f7ad6dc617b546fd20f34c8ef574ee5ee293c8d1bd0ed0221212e8f5907cdc2c42097870f1dcc769a654107d82c95b
69+
languageName: node
70+
linkType: hard
71+
5872
"@babel-baseline/helper-validator-identifier@npm:@babel/helper-validator-identifier@7.16.7":
5973
version: 7.16.7
6074
resolution: "@babel/helper-validator-identifier@npm:7.16.7"
@@ -154,12 +168,14 @@ __metadata:
154168
dependencies:
155169
"@babel-baseline/core": "npm:@babel/core@7.18.5"
156170
"@babel-baseline/generator": "npm:@babel/generator@7.18.2"
171+
"@babel-baseline/helper-compilation-targets": "npm:@babel/helper-compilation-targets@7.20.0"
157172
"@babel-baseline/helper-validator-identifier": "npm:@babel/helper-validator-identifier@7.16.7"
158173
"@babel-baseline/parser": "npm:@babel/parser@7.18.5"
159174
"@babel-baseline/traverse": "npm:@babel/traverse@7.18.5"
160175
"@babel-baseline/types": "npm:@babel/types@7.18.4"
161176
"@babel/core": "workspace:^"
162177
"@babel/generator": "workspace:^"
178+
"@babel/helper-compilation-targets": "workspace:^"
163179
"@babel/helper-validator-identifier": "workspace:^"
164180
"@babel/parser": "workspace:^"
165181
"@babel/preset-env": "workspace:^"
@@ -528,20 +544,6 @@ __metadata:
528544
languageName: unknown
529545
linkType: soft
530546

531-
"@babel/helper-compilation-targets@npm:^7.17.7, @babel/helper-compilation-targets@npm:^7.18.2, @babel/helper-compilation-targets@npm:^7.18.9, @babel/helper-compilation-targets@npm:^7.20.0":
532-
version: 7.20.0
533-
resolution: "@babel/helper-compilation-targets@npm:7.20.0"
534-
dependencies:
535-
"@babel/compat-data": ^7.20.0
536-
"@babel/helper-validator-option": ^7.18.6
537-
browserslist: ^4.21.3
538-
semver: ^6.3.0
539-
peerDependencies:
540-
"@babel/core": ^7.0.0
541-
checksum: bc183f2109648849c8fde0b3c5cf08adf2f7ad6dc617b546fd20f34c8ef574ee5ee293c8d1bd0ed0221212e8f5907cdc2c42097870f1dcc769a654107d82c95b
542-
languageName: node
543-
linkType: hard
544-
545547
"@babel/helper-compilation-targets@workspace:^, @babel/helper-compilation-targets@workspace:packages/babel-helper-compilation-targets":
546548
version: 0.0.0-use.local
547549
resolution: "@babel/helper-compilation-targets@workspace:packages/babel-helper-compilation-targets"
@@ -550,8 +552,10 @@ __metadata:
550552
"@babel/core": "workspace:^"
551553
"@babel/helper-plugin-test-runner": "workspace:^"
552554
"@babel/helper-validator-option": "workspace:^"
555+
"@types/lru-cache": ^5.1.1
553556
"@types/semver": ^5.5.0
554557
browserslist: ^4.21.3
558+
lru-cache: "condition:BABEL_8_BREAKING ? ^7.14.1 : ^5.1.1"
555559
semver: "condition:BABEL_8_BREAKING ? ^7.3.4 : ^6.3.0"
556560
peerDependencies:
557561
"@babel/core": ^7.0.0
@@ -4553,6 +4557,13 @@ __metadata:
45534557
languageName: node
45544558
linkType: hard
45554559

4560+
"@types/lru-cache@npm:^5.1.1":
4561+
version: 5.1.1
4562+
resolution: "@types/lru-cache@npm:5.1.1"
4563+
checksum: e1d6c0085f61b16ec5b3073ec76ad1be4844ea036561c3f145fc19f71f084b58a6eb600b14128aa95809d057d28f1d147c910186ae51219f58366ffd2ff2e118
4564+
languageName: node
4565+
linkType: hard
4566+
45564567
"@types/minimatch@npm:*, @types/minimatch@npm:^3.0.3":
45574568
version: 3.0.5
45584569
resolution: "@types/minimatch@npm:3.0.5"
@@ -11157,6 +11168,32 @@ fsevents@^1.2.7:
1115711168
languageName: node
1115811169
linkType: hard
1115911170

11171+
"lru-cache-BABEL_8_BREAKING-false@npm:lru-cache@^5.1.1, lru-cache@npm:^5.1.1":
11172+
version: 5.1.1
11173+
resolution: "lru-cache@npm:5.1.1"
11174+
dependencies:
11175+
yallist: ^3.0.2
11176+
checksum: c154ae1cbb0c2206d1501a0e94df349653c92c8cbb25236d7e85190bcaf4567a03ac6eb43166fabfa36fd35623694da7233e88d9601fbf411a9a481d85dbd2cb
11177+
languageName: node
11178+
linkType: hard
11179+
11180+
"lru-cache-BABEL_8_BREAKING-true@npm:lru-cache@^7.14.1":
11181+
version: 7.14.1
11182+
resolution: "lru-cache@npm:7.14.1"
11183+
checksum: d72c6713c6a6d86836a7a6523b3f1ac6764768cca47ec99341c3e76db06aacd4764620e5e2cda719a36848785a52a70e531822dc2b33fb071fa709683746c104
11184+
languageName: node
11185+
linkType: hard
11186+
11187+
"lru-cache@condition:BABEL_8_BREAKING ? ^7.14.1 : ^5.1.1":
11188+
version: 0.0.0-condition-86c673
11189+
resolution: "lru-cache@condition:BABEL_8_BREAKING?^7.14.1:^5.1.1#86c673"
11190+
dependencies:
11191+
lru-cache-BABEL_8_BREAKING-false: "npm:lru-cache@^5.1.1"
11192+
lru-cache-BABEL_8_BREAKING-true: "npm:lru-cache@^7.14.1"
11193+
checksum: 9a90e9b7fff14a71bd363ac5e40cea193f2da3380ca92d012589d3da49cc6af9c9a8399fc59b57b206e62753347ff4d77769a1e3bc0dd5550f3a8225a1a78a9a
11194+
languageName: node
11195+
linkType: hard
11196+
1116011197
"lru-cache@npm:^4.0.1":
1116111198
version: 4.1.5
1116211199
resolution: "lru-cache@npm:4.1.5"
@@ -11167,15 +11204,6 @@ fsevents@^1.2.7:
1116711204
languageName: node
1116811205
linkType: hard
1116911206

11170-
"lru-cache@npm:^5.1.1":
11171-
version: 5.1.1
11172-
resolution: "lru-cache@npm:5.1.1"
11173-
dependencies:
11174-
yallist: ^3.0.2
11175-
checksum: c154ae1cbb0c2206d1501a0e94df349653c92c8cbb25236d7e85190bcaf4567a03ac6eb43166fabfa36fd35623694da7233e88d9601fbf411a9a481d85dbd2cb
11176-
languageName: node
11177-
linkType: hard
11178-
1117911207
"lru-cache@npm:^6.0.0":
1118011208
version: 6.0.0
1118111209
resolution: "lru-cache@npm:6.0.0"

0 commit comments

Comments
 (0)