From ed99a2cd31e8d3c2b791885bcc4b188570539e45 Mon Sep 17 00:00:00 2001 From: btea <2356281422@qq.com> Date: Fri, 22 Nov 2024 17:36:26 +0800 Subject: [PATCH] perf: reduce bundle size for `Object.keys(import.meta.glob(...))` / `Object.values(import.meta.glob(...))` (#18666) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 翠 / green --- .../__snapshots__/fixture.spec.ts.snap | 96 +++++++++++++++++-- .../plugins/importGlob/fixture-a/index.ts | 42 ++++++++ .../vite/src/node/plugins/importMetaGlob.ts | 51 ++++++++-- 3 files changed, 175 insertions(+), 14 deletions(-) diff --git a/packages/vite/src/node/__tests__/plugins/importGlob/__snapshots__/fixture.spec.ts.snap b/packages/vite/src/node/__tests__/plugins/importGlob/__snapshots__/fixture.spec.ts.snap index f187b9e0ab0a03..f3b469e811ed68 100644 --- a/packages/vite/src/node/__tests__/plugins/importGlob/__snapshots__/fixture.spec.ts.snap +++ b/packages/vite/src/node/__tests__/plugins/importGlob/__snapshots__/fixture.spec.ts.snap @@ -1,20 +1,60 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`fixture > transform 1`] = ` -"import * as __vite_glob_1_0 from "./modules/a.ts";import * as __vite_glob_1_1 from "./modules/b.ts";import * as __vite_glob_1_2 from "./modules/index.ts";import { name as __vite_glob_3_0 } from "./modules/a.ts";import { name as __vite_glob_3_1 } from "./modules/b.ts";import { name as __vite_glob_3_2 } from "./modules/index.ts";import { default as __vite_glob_5_0 } from "./modules/a.ts?raw";import { default as __vite_glob_5_1 } from "./modules/b.ts?raw";import "types/importMeta"; +"import * as __vite_glob_3_0 from "./modules/a.ts";import * as __vite_glob_3_1 from "./modules/b.ts";import * as __vite_glob_3_2 from "./modules/index.ts";import * as __vite_glob_5_0 from "./modules/a.ts";import * as __vite_glob_5_1 from "./modules/b.ts";import * as __vite_glob_5_2 from "./modules/index.ts";import { name as __vite_glob_9_0 } from "./modules/a.ts";import { name as __vite_glob_9_1 } from "./modules/b.ts";import { name as __vite_glob_9_2 } from "./modules/index.ts";import { name as __vite_glob_11_0 } from "./modules/a.ts";import { name as __vite_glob_11_1 } from "./modules/b.ts";import { name as __vite_glob_11_2 } from "./modules/index.ts";import { default as __vite_glob_15_0 } from "./modules/a.ts?raw";import { default as __vite_glob_15_1 } from "./modules/b.ts?raw";import "types/importMeta"; export const basic = /* #__PURE__ */ Object.assign({"./modules/a.ts": () => import("./modules/a.ts"),"./modules/b.ts": () => import("./modules/b.ts"),"./modules/index.ts": () => import("./modules/index.ts")}); -export const basicEager = /* #__PURE__ */ Object.assign({"./modules/a.ts": __vite_glob_1_0,"./modules/b.ts": __vite_glob_1_1,"./modules/index.ts": __vite_glob_1_2 +export const basicWithObjectKeys = Object.keys({"./modules/a.ts": 0,"./modules/b.ts": 0,"./modules/index.ts": 0}); +export const basicWithObjectValues = Object.values([() => import("./modules/a.ts"),() => import("./modules/b.ts"),() => import("./modules/index.ts")]); +export const basicEager = /* #__PURE__ */ Object.assign({"./modules/a.ts": __vite_glob_3_0,"./modules/b.ts": __vite_glob_3_1,"./modules/index.ts": __vite_glob_3_2 }); +export const basicEagerWithObjectKeys = Object.keys( + {"./modules/a.ts": 0,"./modules/b.ts": 0,"./modules/index.ts": 0 + +} +); +export const basicEagerWithObjectValues = Object.values( + [__vite_glob_5_0,__vite_glob_5_1,__vite_glob_5_2 + +] +); export const ignore = /* #__PURE__ */ Object.assign({"./modules/a.ts": () => import("./modules/a.ts"),"./modules/b.ts": () => import("./modules/b.ts")}); -export const namedEager = /* #__PURE__ */ Object.assign({"./modules/a.ts": __vite_glob_3_0,"./modules/b.ts": __vite_glob_3_1,"./modules/index.ts": __vite_glob_3_2 +export const ignoreWithObjectKeys = Object.keys( + {"./modules/a.ts": 0,"./modules/b.ts": 0} +); +export const ignoreWithObjectValues = Object.values( + [() => import("./modules/a.ts"),() => import("./modules/b.ts")] +); +export const namedEager = /* #__PURE__ */ Object.assign({"./modules/a.ts": __vite_glob_9_0,"./modules/b.ts": __vite_glob_9_1,"./modules/index.ts": __vite_glob_9_2 }); +export const namedEagerWithObjectKeys = Object.keys( + {"./modules/a.ts": 0,"./modules/b.ts": 0,"./modules/index.ts": 0 + + +} +); +export const namedEagerWithObjectValues = Object.values( + [__vite_glob_11_0,__vite_glob_11_1,__vite_glob_11_2 + + +] +); export const namedDefault = /* #__PURE__ */ Object.assign({"./modules/a.ts": () => import("./modules/a.ts").then(m => m["default"]),"./modules/b.ts": () => import("./modules/b.ts").then(m => m["default"]),"./modules/index.ts": () => import("./modules/index.ts").then(m => m["default"]) }); -export const eagerAs = /* #__PURE__ */ Object.assign({"./modules/a.ts": __vite_glob_5_0,"./modules/b.ts": __vite_glob_5_1 +export const namedDefaultWithObjectKeys = Object.keys( + {"./modules/a.ts": 0,"./modules/b.ts": 0,"./modules/index.ts": 0 + +} +); +export const namedDefaultWithObjectValues = Object.values( + [() => import("./modules/a.ts").then(m => m["default"]),() => import("./modules/b.ts").then(m => m["default"]),() => import("./modules/index.ts").then(m => m["default"]) + +] +); +export const eagerAs = /* #__PURE__ */ Object.assign({"./modules/a.ts": __vite_glob_15_0,"./modules/b.ts": __vite_glob_15_1 }); @@ -56,20 +96,60 @@ export const cleverCwd2 = /* #__PURE__ */ Object.assign({"./modules/a.ts": () => `; exports[`fixture > transform with restoreQueryExtension 1`] = ` -"import * as __vite_glob_1_0 from "./modules/a.ts";import * as __vite_glob_1_1 from "./modules/b.ts";import * as __vite_glob_1_2 from "./modules/index.ts";import { name as __vite_glob_3_0 } from "./modules/a.ts";import { name as __vite_glob_3_1 } from "./modules/b.ts";import { name as __vite_glob_3_2 } from "./modules/index.ts";import { default as __vite_glob_5_0 } from "./modules/a.ts?raw";import { default as __vite_glob_5_1 } from "./modules/b.ts?raw";import "types/importMeta"; +"import * as __vite_glob_3_0 from "./modules/a.ts";import * as __vite_glob_3_1 from "./modules/b.ts";import * as __vite_glob_3_2 from "./modules/index.ts";import * as __vite_glob_5_0 from "./modules/a.ts";import * as __vite_glob_5_1 from "./modules/b.ts";import * as __vite_glob_5_2 from "./modules/index.ts";import { name as __vite_glob_9_0 } from "./modules/a.ts";import { name as __vite_glob_9_1 } from "./modules/b.ts";import { name as __vite_glob_9_2 } from "./modules/index.ts";import { name as __vite_glob_11_0 } from "./modules/a.ts";import { name as __vite_glob_11_1 } from "./modules/b.ts";import { name as __vite_glob_11_2 } from "./modules/index.ts";import { default as __vite_glob_15_0 } from "./modules/a.ts?raw";import { default as __vite_glob_15_1 } from "./modules/b.ts?raw";import "types/importMeta"; export const basic = /* #__PURE__ */ Object.assign({"./modules/a.ts": () => import("./modules/a.ts"),"./modules/b.ts": () => import("./modules/b.ts"),"./modules/index.ts": () => import("./modules/index.ts")}); -export const basicEager = /* #__PURE__ */ Object.assign({"./modules/a.ts": __vite_glob_1_0,"./modules/b.ts": __vite_glob_1_1,"./modules/index.ts": __vite_glob_1_2 +export const basicWithObjectKeys = Object.keys({"./modules/a.ts": 0,"./modules/b.ts": 0,"./modules/index.ts": 0}); +export const basicWithObjectValues = Object.values([() => import("./modules/a.ts"),() => import("./modules/b.ts"),() => import("./modules/index.ts")]); +export const basicEager = /* #__PURE__ */ Object.assign({"./modules/a.ts": __vite_glob_3_0,"./modules/b.ts": __vite_glob_3_1,"./modules/index.ts": __vite_glob_3_2 }); +export const basicEagerWithObjectKeys = Object.keys( + {"./modules/a.ts": 0,"./modules/b.ts": 0,"./modules/index.ts": 0 + +} +); +export const basicEagerWithObjectValues = Object.values( + [__vite_glob_5_0,__vite_glob_5_1,__vite_glob_5_2 + +] +); export const ignore = /* #__PURE__ */ Object.assign({"./modules/a.ts": () => import("./modules/a.ts"),"./modules/b.ts": () => import("./modules/b.ts")}); -export const namedEager = /* #__PURE__ */ Object.assign({"./modules/a.ts": __vite_glob_3_0,"./modules/b.ts": __vite_glob_3_1,"./modules/index.ts": __vite_glob_3_2 +export const ignoreWithObjectKeys = Object.keys( + {"./modules/a.ts": 0,"./modules/b.ts": 0} +); +export const ignoreWithObjectValues = Object.values( + [() => import("./modules/a.ts"),() => import("./modules/b.ts")] +); +export const namedEager = /* #__PURE__ */ Object.assign({"./modules/a.ts": __vite_glob_9_0,"./modules/b.ts": __vite_glob_9_1,"./modules/index.ts": __vite_glob_9_2 }); +export const namedEagerWithObjectKeys = Object.keys( + {"./modules/a.ts": 0,"./modules/b.ts": 0,"./modules/index.ts": 0 + + +} +); +export const namedEagerWithObjectValues = Object.values( + [__vite_glob_11_0,__vite_glob_11_1,__vite_glob_11_2 + + +] +); export const namedDefault = /* #__PURE__ */ Object.assign({"./modules/a.ts": () => import("./modules/a.ts").then(m => m["default"]),"./modules/b.ts": () => import("./modules/b.ts").then(m => m["default"]),"./modules/index.ts": () => import("./modules/index.ts").then(m => m["default"]) }); -export const eagerAs = /* #__PURE__ */ Object.assign({"./modules/a.ts": __vite_glob_5_0,"./modules/b.ts": __vite_glob_5_1 +export const namedDefaultWithObjectKeys = Object.keys( + {"./modules/a.ts": 0,"./modules/b.ts": 0,"./modules/index.ts": 0 + +} +); +export const namedDefaultWithObjectValues = Object.values( + [() => import("./modules/a.ts").then(m => m["default"]),() => import("./modules/b.ts").then(m => m["default"]),() => import("./modules/index.ts").then(m => m["default"]) + +] +); +export const eagerAs = /* #__PURE__ */ Object.assign({"./modules/a.ts": __vite_glob_15_0,"./modules/b.ts": __vite_glob_15_1 }); diff --git a/packages/vite/src/node/__tests__/plugins/importGlob/fixture-a/index.ts b/packages/vite/src/node/__tests__/plugins/importGlob/fixture-a/index.ts index 8a2311051a8d09..5262dd99969f46 100644 --- a/packages/vite/src/node/__tests__/plugins/importGlob/fixture-a/index.ts +++ b/packages/vite/src/node/__tests__/plugins/importGlob/fixture-a/index.ts @@ -5,21 +5,63 @@ export interface ModuleType { } export const basic = import.meta.glob('./modules/*.ts') +// prettier-ignore +export const basicWithObjectKeys = Object.keys(import.meta.glob('./modules/*.ts')) +// prettier-ignore +export const basicWithObjectValues = Object.values(import.meta.glob('./modules/*.ts')) export const basicEager = import.meta.glob('./modules/*.ts', { eager: true, }) +export const basicEagerWithObjectKeys = Object.keys( + import.meta.glob('./modules/*.ts', { + eager: true, + }), +) +export const basicEagerWithObjectValues = Object.values( + import.meta.glob('./modules/*.ts', { + eager: true, + }), +) export const ignore = import.meta.glob(['./modules/*.ts', '!**/index.ts']) +export const ignoreWithObjectKeys = Object.keys( + import.meta.glob(['./modules/*.ts', '!**/index.ts']), +) +export const ignoreWithObjectValues = Object.values( + import.meta.glob(['./modules/*.ts', '!**/index.ts']), +) export const namedEager = import.meta.glob('./modules/*.ts', { eager: true, import: 'name', }) +export const namedEagerWithObjectKeys = Object.keys( + import.meta.glob('./modules/*.ts', { + eager: true, + import: 'name', + }), +) +export const namedEagerWithObjectValues = Object.values( + import.meta.glob('./modules/*.ts', { + eager: true, + import: 'name', + }), +) export const namedDefault = import.meta.glob('./modules/*.ts', { import: 'default', }) +export const namedDefaultWithObjectKeys = Object.keys( + import.meta.glob('./modules/*.ts', { + import: 'default', + }), +) +export const namedDefaultWithObjectValues = Object.values( + import.meta.glob('./modules/*.ts', { + import: 'default', + }), +) export const eagerAs = import.meta.glob( ['./modules/*.ts', '!**/index.ts'], diff --git a/packages/vite/src/node/plugins/importMetaGlob.ts b/packages/vite/src/node/plugins/importMetaGlob.ts index b167bd16ef57d2..43534d7d82bca5 100644 --- a/packages/vite/src/node/plugins/importMetaGlob.ts +++ b/packages/vite/src/node/plugins/importMetaGlob.ts @@ -32,6 +32,8 @@ export interface ParsedImportGlob { options: ParsedGeneralImportGlobOptions start: number end: number + onlyKeys: boolean + onlyValues: boolean } interface ParsedGeneralImportGlobOptions extends GeneralImportGlobOptions { @@ -107,6 +109,8 @@ export function importGlobPlugin(config: ResolvedConfig): Plugin { } const importGlobRE = /\bimport\.meta\.glob(?:<\w+>)?\s*\(/g +const objectKeysRE = /\bObject\.keys\(\s*$/ +const objectValuesRE = /\bObject\.values\(\s*$/ const knownOptions = { as: ['string'], @@ -306,6 +310,12 @@ export async function parseImportGlob( globs.map((glob) => toAbsoluteGlob(glob, root, importer, resolveId)), ) const isRelative = globs.every((i) => '.!'.includes(i[0])) + const sliceCode = cleanCode.slice(0, start) + const onlyKeys = objectKeysRE.test(sliceCode) + let onlyValues = false + if (!onlyKeys) { + onlyValues = objectValuesRE.test(sliceCode) + } return { index, @@ -315,6 +325,8 @@ export async function parseImportGlob( options, start, end, + onlyKeys, + onlyValues, } }) @@ -390,7 +402,16 @@ export async function transformGlobImport( const staticImports = ( await Promise.all( matches.map( - async ({ globsResolved, isRelative, options, index, start, end }) => { + async ({ + globsResolved, + isRelative, + options, + index, + start, + end, + onlyKeys, + onlyValues, + }) => { const cwd = getCommonBase(globsResolved) ?? root const files = ( await glob(globsResolved, { @@ -437,6 +458,11 @@ export async function transformGlobImport( let importPath = paths.importPath let importQuery = options.query ?? '' + if (onlyKeys) { + objectProps.push(`${JSON.stringify(filePath)}: 0`) + return + } + if (importQuery && importQuery !== '?raw') { const fileExtension = basename(file).split('.').slice(-1)[0] if (fileExtension && restoreQueryExtension) @@ -458,13 +484,19 @@ export async function transformGlobImport( staticImports.push( `import ${expression} from ${JSON.stringify(importPath)}`, ) - objectProps.push(`${JSON.stringify(filePath)}: ${variableName}`) + objectProps.push( + onlyValues + ? `${variableName}` + : `${JSON.stringify(filePath)}: ${variableName}`, + ) } else { let importStatement = `import(${JSON.stringify(importPath)})` if (importKey) importStatement += `.then(m => m[${JSON.stringify(importKey)}])` objectProps.push( - `${JSON.stringify(filePath)}: () => ${importStatement}`, + onlyValues + ? `() => ${importStatement}` + : `${JSON.stringify(filePath)}: () => ${importStatement}`, ) } }) @@ -477,10 +509,17 @@ export async function transformGlobImport( originalLineBreakCount > 0 ? '\n'.repeat(originalLineBreakCount) : '' + let replacement = '' + if (onlyKeys) { + replacement = `{${objectProps.join(',')}${lineBreaks}}` + } else if (onlyValues) { + replacement = `[${objectProps.join(',')}${lineBreaks}]` + } else { + replacement = `/* #__PURE__ */ Object.assign({${objectProps.join( + ',', + )}${lineBreaks}})` + } - const replacement = `/* #__PURE__ */ Object.assign({${objectProps.join( - ',', - )}${lineBreaks}})` s.overwrite(start, end, replacement) return staticImports