Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: Speed up getTargets #15228

Merged
merged 5 commits into from Dec 5, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
40 changes: 40 additions & 0 deletions benchmark/babel-helper-compilation-targets/getTargets.mjs
@@ -0,0 +1,40 @@
import Benchmark from "benchmark";
import baseline from "@babel-baseline/helper-compilation-targets";
import current from "@babel/helper-compilation-targets";
import { report } from "../util.mjs";

const suite = new Benchmark.Suite("", { initCount: 0 });
function benchCases(implementation, name) {
suite.add(name + "#getTargets last1", () => {
implementation({
browsers: [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version",
"last 1 iOS version",
"last 1 edge version",
],
});
});
suite.add(name + "#getTargets last100", () => {
implementation({
browsers: [
"last 100 chrome version",
"last 100 firefox version",
"last 100 safari version",
"last 100 iOS version",
"last 100 edge version",
],
});
});
suite.add(name + "#getTargets chrome 49 ie 11", () => {
implementation({
browsers: ["chrome 49", "ie 11"],
});
});
}

benchCases(baseline.default, "baseline");
benchCases(current.default, "current");

suite.on("cycle", report).run();
2 changes: 2 additions & 0 deletions benchmark/package.json
Expand Up @@ -5,12 +5,14 @@
"devDependencies": {
"@babel-baseline/core": "npm:@babel/core@7.18.5",
"@babel-baseline/generator": "npm:@babel/generator@7.18.2",
"@babel-baseline/helper-compilation-targets": "npm:@babel/helper-compilation-targets@7.20.0",
"@babel-baseline/helper-validator-identifier": "npm:@babel/helper-validator-identifier@7.16.7",
"@babel-baseline/parser": "npm:@babel/parser@7.18.5",
"@babel-baseline/traverse": "npm:@babel/traverse@7.18.5",
"@babel-baseline/types": "npm:@babel/types@7.18.4",
"@babel/core": "workspace:^",
"@babel/generator": "workspace:^",
"@babel/helper-compilation-targets": "workspace:^",
"@babel/helper-validator-identifier": "workspace:^",
"@babel/parser": "workspace:^",
"@babel/preset-env": "workspace:^",
Expand Down
2 changes: 2 additions & 0 deletions packages/babel-helper-compilation-targets/package.json
Expand Up @@ -25,6 +25,7 @@
"@babel/compat-data": "workspace:^",
"@babel/helper-validator-option": "workspace:^",
"browserslist": "^4.21.3",
"lru-cache": "^5.1.1",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we update lru-cache to 7.14.1 for Babel 8?

"semver": "condition:BABEL_8_BREAKING ? ^7.3.4 : ^6.3.0"
},
"peerDependencies": {
Expand All @@ -33,6 +34,7 @@
"devDependencies": {
"@babel/core": "workspace:^",
"@babel/helper-plugin-test-runner": "workspace:^",
"@types/lru-cache": "^5.1.1",
"@types/semver": "^5.5.0"
},
"engines": {
Expand Down
34 changes: 25 additions & 9 deletions packages/babel-helper-compilation-targets/src/index.ts
@@ -1,6 +1,7 @@
import browserslist from "browserslist";
import { findSuggestion } from "@babel/helper-validator-option";
import browserModulesData from "@babel/compat-data/native-modules";
import LruCache from "lru-cache";

import {
semverify,
Expand Down Expand Up @@ -70,7 +71,7 @@ function getLowestVersions(browsers: Array<string>): Targets {
BrowserslistBrowserName,
string,
];
const target: Target = browserNameMap[browserName];
const target = browserNameMap[browserName];

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

function outputDecimalWarning(
decimalTargets: Array<{ target: string; value: number }>,
): void {
) {
if (!decimalTargets.length) {
return;
}
Expand All @@ -123,7 +124,7 @@ getting parsed as 6.1, which can lead to unexpected behavior.
`);
}

function semverifyTarget(target: keyof Targets, value: string) {
function semverifyTarget(target: Target, value: string) {
try {
return semverify(value);
} catch (error) {
Expand All @@ -141,7 +142,7 @@ function nodeTargetParser(value: true | string) {
value === true || value === "current"
? process.versions.node
: semverifyTarget("node", value);
return ["node" as const, parsed] as const;
return ["node", parsed] as const;
}

function defaultTargetParser(
Expand All @@ -158,7 +159,7 @@ function generateTargets(inputTargets: InputTargets): Targets {
const input = { ...inputTargets };
delete input.esmodules;
delete input.browsers;
return input as any as Targets;
return input;
}

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

const targetsCache = new LruCache(64);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably need less than 64, since the targets are usually the same for every file (I believe that 8 would be enough). However it doesn't really matter, since 64 small allocations already has a very small memory footprint.


function resolveTargetsCached(queries: Browsers, env?: string): Targets {
const cacheKey = typeof queries === "string" ? queries : queries.join() + env;
let cached = targetsCache.get(cacheKey) as Targets | undefined;
if (!cached) {
cached = resolveTargets(queries, env);
targetsCache.set(cacheKey, cached);
}
return { ...cached };
}

type GetTargetsOption = {
// This is not the path of the config file, but the path where start searching it from
configPath?: string;
Expand All @@ -181,7 +194,7 @@ type GetTargetsOption = {
};

export default function getTargets(
inputTargets: InputTargets = {} as InputTargets,
inputTargets: InputTargets = {},
options: GetTargetsOption = {},
): Targets {
let { browsers, esmodules } = inputTargets;
Expand All @@ -190,7 +203,7 @@ export default function getTargets(
validateBrowsers(browsers);

const input = generateTargets(inputTargets);
let targets: TargetsTuple = validateTargetNames(input);
let targets = validateTargetNames(input);

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

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

// Parse remaining targets
const result: Targets = {} as Targets;
const result: Targets = {};
const decimalWarnings = [];
for (const target of Object.keys(targets).sort() as Target[]) {
const value = targets[target];
Expand Down
39 changes: 25 additions & 14 deletions yarn.lock
Expand Up @@ -55,6 +55,20 @@ __metadata:
languageName: node
linkType: hard

"@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":
version: 7.20.0
resolution: "@babel/helper-compilation-targets@npm:7.20.0"
dependencies:
"@babel/compat-data": ^7.20.0
"@babel/helper-validator-option": ^7.18.6
browserslist: ^4.21.3
semver: ^6.3.0
peerDependencies:
"@babel/core": ^7.0.0
checksum: bc183f2109648849c8fde0b3c5cf08adf2f7ad6dc617b546fd20f34c8ef574ee5ee293c8d1bd0ed0221212e8f5907cdc2c42097870f1dcc769a654107d82c95b
languageName: node
linkType: hard

"@babel-baseline/helper-validator-identifier@npm:@babel/helper-validator-identifier@7.16.7":
version: 7.16.7
resolution: "@babel/helper-validator-identifier@npm:7.16.7"
Expand Down Expand Up @@ -154,12 +168,14 @@ __metadata:
dependencies:
"@babel-baseline/core": "npm:@babel/core@7.18.5"
"@babel-baseline/generator": "npm:@babel/generator@7.18.2"
"@babel-baseline/helper-compilation-targets": "npm:@babel/helper-compilation-targets@7.20.0"
"@babel-baseline/helper-validator-identifier": "npm:@babel/helper-validator-identifier@7.16.7"
"@babel-baseline/parser": "npm:@babel/parser@7.18.5"
"@babel-baseline/traverse": "npm:@babel/traverse@7.18.5"
"@babel-baseline/types": "npm:@babel/types@7.18.4"
"@babel/core": "workspace:^"
"@babel/generator": "workspace:^"
"@babel/helper-compilation-targets": "workspace:^"
"@babel/helper-validator-identifier": "workspace:^"
"@babel/parser": "workspace:^"
"@babel/preset-env": "workspace:^"
Expand Down Expand Up @@ -528,20 +544,6 @@ __metadata:
languageName: unknown
linkType: soft

"@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":
version: 7.20.0
resolution: "@babel/helper-compilation-targets@npm:7.20.0"
dependencies:
"@babel/compat-data": ^7.20.0
"@babel/helper-validator-option": ^7.18.6
browserslist: ^4.21.3
semver: ^6.3.0
peerDependencies:
"@babel/core": ^7.0.0
checksum: bc183f2109648849c8fde0b3c5cf08adf2f7ad6dc617b546fd20f34c8ef574ee5ee293c8d1bd0ed0221212e8f5907cdc2c42097870f1dcc769a654107d82c95b
languageName: node
linkType: hard

"@babel/helper-compilation-targets@workspace:^, @babel/helper-compilation-targets@workspace:packages/babel-helper-compilation-targets":
version: 0.0.0-use.local
resolution: "@babel/helper-compilation-targets@workspace:packages/babel-helper-compilation-targets"
Expand All @@ -550,8 +552,10 @@ __metadata:
"@babel/core": "workspace:^"
"@babel/helper-plugin-test-runner": "workspace:^"
"@babel/helper-validator-option": "workspace:^"
"@types/lru-cache": ^5.1.1
"@types/semver": ^5.5.0
browserslist: ^4.21.3
lru-cache: ^5.1.1
semver: "condition:BABEL_8_BREAKING ? ^7.3.4 : ^6.3.0"
peerDependencies:
"@babel/core": ^7.0.0
Expand Down Expand Up @@ -4553,6 +4557,13 @@ __metadata:
languageName: node
linkType: hard

"@types/lru-cache@npm:^5.1.1":
version: 5.1.1
resolution: "@types/lru-cache@npm:5.1.1"
checksum: e1d6c0085f61b16ec5b3073ec76ad1be4844ea036561c3f145fc19f71f084b58a6eb600b14128aa95809d057d28f1d147c910186ae51219f58366ffd2ff2e118
languageName: node
linkType: hard

"@types/minimatch@npm:*, @types/minimatch@npm:^3.0.3":
version: 3.0.5
resolution: "@types/minimatch@npm:3.0.5"
Expand Down