From 2f8e6ca369977fc887ffb7ca01e7dc3aea320568 Mon Sep 17 00:00:00 2001 From: yuzheng14 <422450117@qq.com> Date: Mon, 12 Aug 2024 20:34:17 +0800 Subject: [PATCH 1/5] fix(build): avoid re-define `__vite_import_meta_env__` Closes #17874 --- .../src/node/__tests__/plugins/define.spec.ts | 19 ++++++++++++++++++ packages/vite/src/node/plugins/define.ts | 20 +++++++++++++------ 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/packages/vite/src/node/__tests__/plugins/define.spec.ts b/packages/vite/src/node/__tests__/plugins/define.spec.ts index 2165461c77acaa..0742853947cec2 100644 --- a/packages/vite/src/node/__tests__/plugins/define.spec.ts +++ b/packages/vite/src/node/__tests__/plugins/define.spec.ts @@ -109,4 +109,23 @@ describe('definePlugin', () => { /const __vite_import_meta_env__ = .*;\nconst env = __vite_import_meta_env__;/, ) }) + + test('already has marker', async () => { + const transform = await createDefinePluginTransform() + expect( + await transform( + 'console.log(__vite_import_meta_env__);\nconst env = import.meta.env;', + ), + ).toMatch( + /const __vite_import_meta_env__\$ = .*;\nconsole.log\(__vite_import_meta_env__\);\nconst env = __vite_import_meta_env__\$;/, + ) + + expect( + await transform( + 'console.log(__vite_import_meta_env__, __vite_import_meta_env__$);\n const env = import.meta.env;', + ), + ).toMatch( + /const __vite_import_meta_env__\$\$ = .*;\nconsole.log\(__vite_import_meta_env__, __vite_import_meta_env__\$\);\nconst env = __vite_import_meta_env__\$\$;/, + ) + }) }) diff --git a/packages/vite/src/node/plugins/define.ts b/packages/vite/src/node/plugins/define.ts index 585bc0154fa263..87e6dbab5c8e2d 100644 --- a/packages/vite/src/node/plugins/define.ts +++ b/packages/vite/src/node/plugins/define.ts @@ -9,7 +9,6 @@ import { isHTMLRequest } from './html' const nonJsRe = /\.json(?:$|\?)/ const isNonJsRequest = (request: string): boolean => nonJsRe.test(request) const importMetaEnvMarker = '__vite_import_meta_env__' -const bareImportMetaEnvRe = new RegExp(`${importMetaEnvMarker}(?!\\.)\\b`) const importMetaEnvKeyRe = new RegExp(`${importMetaEnvMarker}\\..+?\\b`, 'g') export function definePlugin(config: ResolvedConfig): Plugin { @@ -80,7 +79,6 @@ export function definePlugin(config: ResolvedConfig): Plugin { SSR: ssr + '', ...userDefineEnv, }) - const banner = `const ${importMetaEnvMarker} = ${importMetaEnvVal};\n` // Create regex pattern as a fast check before running esbuild const patternKeys = Object.keys(userDefine) @@ -94,7 +92,7 @@ export function definePlugin(config: ResolvedConfig): Plugin { ? new RegExp(patternKeys.map(escapeRegex).join('|')) : null - return [define, pattern, banner] as const + return [define, pattern, importMetaEnvVal] as const } const defaultPattern = generatePattern(false) @@ -122,13 +120,23 @@ export function definePlugin(config: ResolvedConfig): Plugin { return } - const [define, pattern, banner] = ssr ? ssrPattern : defaultPattern + const [define, pattern, importMetaEnvVal] = ssr + ? ssrPattern + : defaultPattern if (!pattern) return // Check if our code needs any replacements before running esbuild pattern.lastIndex = 0 if (!pattern.test(code)) return + let marker = importMetaEnvMarker + while (new RegExp(escapeRegex(marker)).test(code)) { + marker += '$' + } + if (marker !== importMetaEnvMarker && 'import.meta.env' in define) { + define['import.meta.env'] = marker + } + const result = await replaceDefine(code, id, define, config) // Replace `import.meta.env.*` with undefined @@ -137,8 +145,8 @@ export function definePlugin(config: ResolvedConfig): Plugin { ) // If there's bare `import.meta.env` references, prepend the banner - if (bareImportMetaEnvRe.test(result.code)) { - result.code = banner + result.code + if (new RegExp(escapeRegex(marker)).test(result.code)) { + result.code = `const ${marker} = ${importMetaEnvVal};\n` + result.code if (result.map) { const map = JSON.parse(result.map) From 9296542c54d6906059bde4bdfe70ccf86daaaaa3 Mon Sep 17 00:00:00 2001 From: yuzheng14 <422450117@qq.com> Date: Tue, 13 Aug 2024 09:37:04 +0800 Subject: [PATCH 2/5] fix(build): forget to modify reg of bare import.meta.env --- packages/vite/src/node/__tests__/plugins/define.spec.ts | 8 ++++++++ packages/vite/src/node/plugins/define.ts | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/vite/src/node/__tests__/plugins/define.spec.ts b/packages/vite/src/node/__tests__/plugins/define.spec.ts index 0742853947cec2..acaa5c80c25743 100644 --- a/packages/vite/src/node/__tests__/plugins/define.spec.ts +++ b/packages/vite/src/node/__tests__/plugins/define.spec.ts @@ -127,5 +127,13 @@ describe('definePlugin', () => { ).toMatch( /const __vite_import_meta_env__\$\$ = .*;\nconsole.log\(__vite_import_meta_env__, __vite_import_meta_env__\$\);\nconst env = __vite_import_meta_env__\$\$;/, ) + + expect( + await transform( + 'console.log(__vite_import_meta_env__);\nconst env = import.meta.env;\nconsole.log(import.meta.env.UNDEFINED);', + ), + ).toMatch( + /const __vite_import_meta_env__\$ = .*;\nconsole.log\(__vite_import_meta_env__\);\nconst env = __vite_import_meta_env__\$;\nconsole.log\(undefined {26}\);/, + ) }) }) diff --git a/packages/vite/src/node/plugins/define.ts b/packages/vite/src/node/plugins/define.ts index 87e6dbab5c8e2d..6913a90ce6e922 100644 --- a/packages/vite/src/node/plugins/define.ts +++ b/packages/vite/src/node/plugins/define.ts @@ -9,7 +9,6 @@ import { isHTMLRequest } from './html' const nonJsRe = /\.json(?:$|\?)/ const isNonJsRequest = (request: string): boolean => nonJsRe.test(request) const importMetaEnvMarker = '__vite_import_meta_env__' -const importMetaEnvKeyRe = new RegExp(`${importMetaEnvMarker}\\..+?\\b`, 'g') export function definePlugin(config: ResolvedConfig): Plugin { const isBuild = config.command === 'build' @@ -140,8 +139,9 @@ export function definePlugin(config: ResolvedConfig): Plugin { const result = await replaceDefine(code, id, define, config) // Replace `import.meta.env.*` with undefined - result.code = result.code.replaceAll(importMetaEnvKeyRe, (m) => - 'undefined'.padEnd(m.length), + result.code = result.code.replaceAll( + new RegExp(`${escapeRegex(marker)}\\..+?\\b`, 'g'), + (m) => 'undefined'.padEnd(m.length), ) // If there's bare `import.meta.env` references, prepend the banner From 980e28c18767a6f987ab01aac693cd8beb6bf05f Mon Sep 17 00:00:00 2001 From: yuzheng14 <422450117@qq.com> Date: Wed, 14 Aug 2024 10:06:19 +0800 Subject: [PATCH 3/5] perf(build): :zap: improve performance of regex using `includes` and cache --- packages/vite/src/node/plugins/define.ts | 32 ++++++++++++++++++------ 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/packages/vite/src/node/plugins/define.ts b/packages/vite/src/node/plugins/define.ts index 6913a90ce6e922..fbf640e9f30cc7 100644 --- a/packages/vite/src/node/plugins/define.ts +++ b/packages/vite/src/node/plugins/define.ts @@ -9,6 +9,7 @@ import { isHTMLRequest } from './html' const nonJsRe = /\.json(?:$|\?)/ const isNonJsRequest = (request: string): boolean => nonJsRe.test(request) const importMetaEnvMarker = '__vite_import_meta_env__' +const markerReCache = new Map() export function definePlugin(config: ResolvedConfig): Plugin { const isBuild = config.command === 'build' @@ -128,24 +129,29 @@ export function definePlugin(config: ResolvedConfig): Plugin { pattern.lastIndex = 0 if (!pattern.test(code)) return + // append `$` to the marker until it's unique, + // to avoid there is a marker already in the code let marker = importMetaEnvMarker - while (new RegExp(escapeRegex(marker)).test(code)) { + while (code.includes(marker)) { marker += '$' } + + // copy define to finalDefine and replace `import.meta.env` with marker, + // avoiding affecting the original define object + const finalDefine = { ...define } if (marker !== importMetaEnvMarker && 'import.meta.env' in define) { - define['import.meta.env'] = marker + finalDefine['import.meta.env'] = marker } - const result = await replaceDefine(code, id, define, config) + const result = await replaceDefine(code, id, finalDefine, config) // Replace `import.meta.env.*` with undefined - result.code = result.code.replaceAll( - new RegExp(`${escapeRegex(marker)}\\..+?\\b`, 'g'), - (m) => 'undefined'.padEnd(m.length), + result.code = result.code.replaceAll(createMarkerRe(marker), (m) => + 'undefined'.padEnd(m.length), ) // If there's bare `import.meta.env` references, prepend the banner - if (new RegExp(escapeRegex(marker)).test(result.code)) { + if (result.code.includes(marker)) { result.code = `const ${marker} = ${importMetaEnvVal};\n` + result.code if (result.map) { @@ -227,3 +233,15 @@ function handleDefineValue(value: any): string { if (typeof value === 'string') return value return JSON.stringify(value) } + +/** get marker regexp using cache */ +function createMarkerRe(marker: string): RegExp { + return ( + markerReCache.get(marker) || + (markerReCache.set( + marker, + new RegExp(`${escapeRegex(marker)}\\..+?\\b`, 'g'), + ), + markerReCache.get(marker)!) + ) +} From 4a84cdffe4ff3904659df06f049014e73016f5f1 Mon Sep 17 00:00:00 2001 From: bluwy Date: Wed, 14 Aug 2024 15:53:28 +0800 Subject: [PATCH 4/5] refactor: update --- packages/vite/src/node/plugins/define.ts | 70 ++++++++++++------------ 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/packages/vite/src/node/plugins/define.ts b/packages/vite/src/node/plugins/define.ts index fbf640e9f30cc7..a880fb0236f082 100644 --- a/packages/vite/src/node/plugins/define.ts +++ b/packages/vite/src/node/plugins/define.ts @@ -9,7 +9,7 @@ import { isHTMLRequest } from './html' const nonJsRe = /\.json(?:$|\?)/ const isNonJsRequest = (request: string): boolean => nonJsRe.test(request) const importMetaEnvMarker = '__vite_import_meta_env__' -const markerReCache = new Map() +const importMetaEnvKeyReCache = new Map() export function definePlugin(config: ResolvedConfig): Plugin { const isBuild = config.command === 'build' @@ -120,7 +120,7 @@ export function definePlugin(config: ResolvedConfig): Plugin { return } - const [define, pattern, importMetaEnvVal] = ssr + let [define, pattern, importMetaEnvVal] = ssr ? ssrPattern : defaultPattern if (!pattern) return @@ -129,35 +129,40 @@ export function definePlugin(config: ResolvedConfig): Plugin { pattern.lastIndex = 0 if (!pattern.test(code)) return - // append `$` to the marker until it's unique, - // to avoid there is a marker already in the code + const hasDefineImportMetaEnv = 'import.meta.env' in define let marker = importMetaEnvMarker - while (code.includes(marker)) { - marker += '$' - } - // copy define to finalDefine and replace `import.meta.env` with marker, - // avoiding affecting the original define object - const finalDefine = { ...define } - if (marker !== importMetaEnvMarker && 'import.meta.env' in define) { - finalDefine['import.meta.env'] = marker + if (hasDefineImportMetaEnv && code.includes(marker)) { + // append a number to the marker until it's unique, to avoid if there is a + // marker already in the code + let i = 1 + do { + marker = importMetaEnvMarker + i++ + } while (code.includes(marker)) + + if (marker !== importMetaEnvMarker) { + define = { ...define, 'import.meta.env': marker } + } } - const result = await replaceDefine(code, id, finalDefine, config) + const result = await replaceDefine(code, id, define, config) - // Replace `import.meta.env.*` with undefined - result.code = result.code.replaceAll(createMarkerRe(marker), (m) => - 'undefined'.padEnd(m.length), - ) + if (hasDefineImportMetaEnv) { + // Replace `import.meta.env.*` with undefined + result.code = result.code.replaceAll( + getImportMetaEnvKeyRe(marker), + (m) => 'undefined'.padEnd(m.length), + ) - // If there's bare `import.meta.env` references, prepend the banner - if (result.code.includes(marker)) { - result.code = `const ${marker} = ${importMetaEnvVal};\n` + result.code + // If there's bare `import.meta.env` references, prepend the banner + if (result.code.includes(marker)) { + result.code = `const ${marker} = ${importMetaEnvVal};\n` + result.code - if (result.map) { - const map = JSON.parse(result.map) - map.mappings = ';' + map.mappings - result.map = map + if (result.map) { + const map = JSON.parse(result.map) + map.mappings = ';' + map.mappings + result.map = map + } } } @@ -234,14 +239,11 @@ function handleDefineValue(value: any): string { return JSON.stringify(value) } -/** get marker regexp using cache */ -function createMarkerRe(marker: string): RegExp { - return ( - markerReCache.get(marker) || - (markerReCache.set( - marker, - new RegExp(`${escapeRegex(marker)}\\..+?\\b`, 'g'), - ), - markerReCache.get(marker)!) - ) +function getImportMetaEnvKeyRe(marker: string): RegExp { + let re = importMetaEnvKeyReCache.get(marker) + if (!re) { + re = new RegExp(`${marker}\\..+?\\b`, 'g') + importMetaEnvKeyReCache.set(marker, re) + } + return re } From 7fd010bf82d316c7641875faa3fbe6cdca783909 Mon Sep 17 00:00:00 2001 From: bluwy Date: Wed, 14 Aug 2024 15:55:39 +0800 Subject: [PATCH 5/5] chore: update test --- packages/vite/src/node/__tests__/plugins/define.spec.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/vite/src/node/__tests__/plugins/define.spec.ts b/packages/vite/src/node/__tests__/plugins/define.spec.ts index acaa5c80c25743..b0b42678ed1130 100644 --- a/packages/vite/src/node/__tests__/plugins/define.spec.ts +++ b/packages/vite/src/node/__tests__/plugins/define.spec.ts @@ -117,15 +117,15 @@ describe('definePlugin', () => { 'console.log(__vite_import_meta_env__);\nconst env = import.meta.env;', ), ).toMatch( - /const __vite_import_meta_env__\$ = .*;\nconsole.log\(__vite_import_meta_env__\);\nconst env = __vite_import_meta_env__\$;/, + /const __vite_import_meta_env__1 = .*;\nconsole.log\(__vite_import_meta_env__\);\nconst env = __vite_import_meta_env__1;/, ) expect( await transform( - 'console.log(__vite_import_meta_env__, __vite_import_meta_env__$);\n const env = import.meta.env;', + 'console.log(__vite_import_meta_env__, __vite_import_meta_env__1);\n const env = import.meta.env;', ), ).toMatch( - /const __vite_import_meta_env__\$\$ = .*;\nconsole.log\(__vite_import_meta_env__, __vite_import_meta_env__\$\);\nconst env = __vite_import_meta_env__\$\$;/, + /const __vite_import_meta_env__2 = .*;\nconsole.log\(__vite_import_meta_env__, __vite_import_meta_env__1\);\nconst env = __vite_import_meta_env__2;/, ) expect( @@ -133,7 +133,7 @@ describe('definePlugin', () => { 'console.log(__vite_import_meta_env__);\nconst env = import.meta.env;\nconsole.log(import.meta.env.UNDEFINED);', ), ).toMatch( - /const __vite_import_meta_env__\$ = .*;\nconsole.log\(__vite_import_meta_env__\);\nconst env = __vite_import_meta_env__\$;\nconsole.log\(undefined {26}\);/, + /const __vite_import_meta_env__1 = .*;\nconsole.log\(__vite_import_meta_env__\);\nconst env = __vite_import_meta_env__1;\nconsole.log\(undefined {26}\);/, ) }) })