diff --git a/benchmark/babel-helper-compilation-targets/getTargets.mjs b/benchmark/babel-helper-compilation-targets/getTargets.mjs new file mode 100644 index 000000000000..f9ec4c321bc8 --- /dev/null +++ b/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(); diff --git a/benchmark/package.json b/benchmark/package.json index 7042661b5518..aba199ebabb5 100644 --- a/benchmark/package.json +++ b/benchmark/package.json @@ -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:^", diff --git a/packages/babel-helper-compilation-targets/package.json b/packages/babel-helper-compilation-targets/package.json index a628ee254235..3f925b8467e0 100644 --- a/packages/babel-helper-compilation-targets/package.json +++ b/packages/babel-helper-compilation-targets/package.json @@ -25,6 +25,7 @@ "@babel/compat-data": "workspace:^", "@babel/helper-validator-option": "workspace:^", "browserslist": "^4.21.3", + "lru-cache": "condition:BABEL_8_BREAKING ? ^7.14.1 : ^5.1.1", "semver": "condition:BABEL_8_BREAKING ? ^7.3.4 : ^6.3.0" }, "peerDependencies": { @@ -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": { diff --git a/packages/babel-helper-compilation-targets/src/debug.ts b/packages/babel-helper-compilation-targets/src/debug.ts index d1ee514cd980..7a7aa2c52846 100644 --- a/packages/babel-helper-compilation-targets/src/debug.ts +++ b/packages/babel-helper-compilation-targets/src/debug.ts @@ -12,7 +12,7 @@ export function getInclusionReasons( targetVersions: Targets, list: { [key: string]: Targets }, ) { - const minVersions = list[item] || ({} as Targets); + const minVersions = list[item] || {}; return (Object.keys(targetVersions) as Target[]).reduce((result, env) => { const minVersion = getLowestImplementedVersion(minVersions, env); diff --git a/packages/babel-helper-compilation-targets/src/index.ts b/packages/babel-helper-compilation-targets/src/index.ts index 2cce6d1f53d4..f93194611deb 100644 --- a/packages/babel-helper-compilation-targets/src/index.ts +++ b/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, @@ -45,7 +46,7 @@ function validateTargetNames(targets: Targets): TargetsTuple { } } - return targets as any; + return targets; } export function isBrowsersQueryValid(browsers: unknown): boolean { @@ -70,7 +71,7 @@ function getLowestVersions(browsers: Array): Targets { BrowserslistBrowserName, string, ]; - const target: Target = browserNameMap[browserName]; + const target = browserNameMap[browserName]; if (!target) { return all; @@ -108,7 +109,7 @@ function getLowestVersions(browsers: Array): Targets { function outputDecimalWarning( decimalTargets: Array<{ target: string; value: number }>, -): void { +) { if (!decimalTargets.length) { return; } @@ -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) { @@ -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( @@ -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 { @@ -169,6 +170,18 @@ function resolveTargets(queries: Browsers, env?: string): Targets { return getLowestVersions(resolved); } +const targetsCache = new LruCache({ max: 64 }); + +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; @@ -181,7 +194,7 @@ type GetTargetsOption = { }; export default function getTargets( - inputTargets: InputTargets = {} as InputTargets, + inputTargets: InputTargets = {}, options: GetTargetsOption = {}, ): Targets { let { browsers, esmodules } = inputTargets; @@ -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; @@ -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[]) { @@ -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]; diff --git a/packages/babel-helper-compilation-targets/src/pretty.ts b/packages/babel-helper-compilation-targets/src/pretty.ts index 34f5257b15ae..1902788bdaa4 100644 --- a/packages/babel-helper-compilation-targets/src/pretty.ts +++ b/packages/babel-helper-compilation-targets/src/pretty.ts @@ -7,9 +7,9 @@ export function prettifyVersion(version: string) { return version; } - const parts = [semver.major(version)]; - const minor = semver.minor(version); - const patch = semver.patch(version); + const { major, minor, patch } = semver.parse(version); + + const parts = [major]; if (minor || patch) { parts.push(minor); diff --git a/packages/babel-helper-compilation-targets/src/types.d.ts b/packages/babel-helper-compilation-targets/src/types.d.ts index e64cb458c97a..c2436c7e5291 100644 --- a/packages/babel-helper-compilation-targets/src/types.d.ts +++ b/packages/babel-helper-compilation-targets/src/types.d.ts @@ -17,10 +17,8 @@ export type Targets = { [target in Target]?: string; }; -export type TargetsTuple = { - [target in Exclude]: string; -} & { - node: string | true; +export type TargetsTuple = Omit & { + node?: string | true; }; export type Browsers = string | ReadonlyArray; diff --git a/packages/babel-helper-compilation-targets/src/utils.ts b/packages/babel-helper-compilation-targets/src/utils.ts index 4fba5a5c7959..984eba747df1 100644 --- a/packages/babel-helper-compilation-targets/src/utils.ts +++ b/packages/babel-helper-compilation-targets/src/utils.ts @@ -29,11 +29,14 @@ export function semverify(version: number | string): string { `'${version}' is not a valid version`, ); - const split = version.toString().split("."); - while (split.length < 3) { - split.push("0"); + version = version.toString(); + + let pos = 0; + let num = 0; + while ((pos = version.indexOf(".", pos + 1)) > 0) { + num++; } - return split.join("."); + return version + ".0".repeat(2 - num); } export function isUnreleasedVersion( diff --git a/yarn.lock b/yarn.lock index 8ba1cf3aed27..e940a46144e0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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" @@ -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:^" @@ -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" @@ -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: "condition:BABEL_8_BREAKING ? ^7.14.1 : ^5.1.1" semver: "condition:BABEL_8_BREAKING ? ^7.3.4 : ^6.3.0" peerDependencies: "@babel/core": ^7.0.0 @@ -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" @@ -11157,6 +11168,32 @@ fsevents@^1.2.7: languageName: node linkType: hard +"lru-cache-BABEL_8_BREAKING-false@npm:lru-cache@^5.1.1, lru-cache@npm:^5.1.1": + version: 5.1.1 + resolution: "lru-cache@npm:5.1.1" + dependencies: + yallist: ^3.0.2 + checksum: c154ae1cbb0c2206d1501a0e94df349653c92c8cbb25236d7e85190bcaf4567a03ac6eb43166fabfa36fd35623694da7233e88d9601fbf411a9a481d85dbd2cb + languageName: node + linkType: hard + +"lru-cache-BABEL_8_BREAKING-true@npm:lru-cache@^7.14.1": + version: 7.14.1 + resolution: "lru-cache@npm:7.14.1" + checksum: d72c6713c6a6d86836a7a6523b3f1ac6764768cca47ec99341c3e76db06aacd4764620e5e2cda719a36848785a52a70e531822dc2b33fb071fa709683746c104 + languageName: node + linkType: hard + +"lru-cache@condition:BABEL_8_BREAKING ? ^7.14.1 : ^5.1.1": + version: 0.0.0-condition-86c673 + resolution: "lru-cache@condition:BABEL_8_BREAKING?^7.14.1:^5.1.1#86c673" + dependencies: + lru-cache-BABEL_8_BREAKING-false: "npm:lru-cache@^5.1.1" + lru-cache-BABEL_8_BREAKING-true: "npm:lru-cache@^7.14.1" + checksum: 9a90e9b7fff14a71bd363ac5e40cea193f2da3380ca92d012589d3da49cc6af9c9a8399fc59b57b206e62753347ff4d77769a1e3bc0dd5550f3a8225a1a78a9a + languageName: node + linkType: hard + "lru-cache@npm:^4.0.1": version: 4.1.5 resolution: "lru-cache@npm:4.1.5" @@ -11167,15 +11204,6 @@ fsevents@^1.2.7: languageName: node linkType: hard -"lru-cache@npm:^5.1.1": - version: 5.1.1 - resolution: "lru-cache@npm:5.1.1" - dependencies: - yallist: ^3.0.2 - checksum: c154ae1cbb0c2206d1501a0e94df349653c92c8cbb25236d7e85190bcaf4567a03ac6eb43166fabfa36fd35623694da7233e88d9601fbf411a9a481d85dbd2cb - languageName: node - linkType: hard - "lru-cache@npm:^6.0.0": version: 6.0.0 resolution: "lru-cache@npm:6.0.0"