From e686d749d673c02ff4395971ac74340082da14e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=81=E8=92=B8=E5=8D=81=E5=9B=9B?= <55919198+yuzheng14@users.noreply.github.com> Date: Thu, 15 Aug 2024 14:52:55 +0800 Subject: [PATCH] fix(build): avoid re-define `__vite_import_meta_env__` (#17876) Co-authored-by: bluwy --- .../src/node/__tests__/plugins/define.spec.ts | 27 ++++++++ packages/vite/src/node/plugins/define.ts | 62 ++++++++++++++----- 2 files changed, 72 insertions(+), 17 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..b0b42678ed1130 100644 --- a/packages/vite/src/node/__tests__/plugins/define.spec.ts +++ b/packages/vite/src/node/__tests__/plugins/define.spec.ts @@ -109,4 +109,31 @@ 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__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__1);\n const env = import.meta.env;', + ), + ).toMatch( + /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( + 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__1 = .*;\nconsole.log\(__vite_import_meta_env__\);\nconst env = __vite_import_meta_env__1;\nconsole.log\(undefined {26}\);/, + ) + }) }) diff --git a/packages/vite/src/node/plugins/define.ts b/packages/vite/src/node/plugins/define.ts index 585bc0154fa263..a880fb0236f082 100644 --- a/packages/vite/src/node/plugins/define.ts +++ b/packages/vite/src/node/plugins/define.ts @@ -9,8 +9,7 @@ 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') +const importMetaEnvKeyReCache = new Map() export function definePlugin(config: ResolvedConfig): Plugin { const isBuild = config.command === 'build' @@ -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,28 +120,49 @@ export function definePlugin(config: ResolvedConfig): Plugin { return } - const [define, pattern, banner] = ssr ? ssrPattern : defaultPattern + let [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 - const result = await replaceDefine(code, id, define, config) + const hasDefineImportMetaEnv = 'import.meta.env' in define + let marker = importMetaEnvMarker - // Replace `import.meta.env.*` with undefined - result.code = result.code.replaceAll(importMetaEnvKeyRe, (m) => - 'undefined'.padEnd(m.length), - ) + 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 there's bare `import.meta.env` references, prepend the banner - if (bareImportMetaEnvRe.test(result.code)) { - result.code = banner + result.code + if (marker !== importMetaEnvMarker) { + define = { ...define, 'import.meta.env': marker } + } + } - if (result.map) { - const map = JSON.parse(result.map) - map.mappings = ';' + map.mappings - result.map = map + const result = await replaceDefine(code, id, define, config) + + 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 (result.map) { + const map = JSON.parse(result.map) + map.mappings = ';' + map.mappings + result.map = map + } } } @@ -219,3 +238,12 @@ function handleDefineValue(value: any): string { if (typeof value === 'string') return value return JSON.stringify(value) } + +function getImportMetaEnvKeyRe(marker: string): RegExp { + let re = importMetaEnvKeyReCache.get(marker) + if (!re) { + re = new RegExp(`${marker}\\..+?\\b`, 'g') + importMetaEnvKeyReCache.set(marker, re) + } + return re +}