diff --git a/packages/vitest/src/node/plugins/envRelacer.ts b/packages/vitest/src/node/plugins/envRelacer.ts new file mode 100644 index 000000000000..f2e7d6d9775e --- /dev/null +++ b/packages/vitest/src/node/plugins/envRelacer.ts @@ -0,0 +1,32 @@ +import MagicString from 'magic-string' +import type { Plugin } from 'vite' + +// so people can reassign envs at runtime +// import.meta.env.VITE_NAME = 'app' -> process.env.VITE_NAME = 'app' +export const EnvReplacerPlugin = (): Plugin => { + return { + name: 'vitest:env-replacer', + enforce: 'pre', + transform(code) { + let s: MagicString | null = null + + const envs = code.matchAll(/\bimport\.meta\.env\b/g) + + for (const env of envs) { + s ||= new MagicString(code) + + const startIndex = env.index! + const endIndex = startIndex + env[0].length + + s.overwrite(startIndex, endIndex, 'process.env') + } + + if (s) { + return { + code: s.toString(), + map: s.generateMap({ hires: true }), + } + } + }, + } +} diff --git a/packages/vitest/src/node/plugins/index.ts b/packages/vitest/src/node/plugins/index.ts index 3d7dddf523b3..da461cb54984 100644 --- a/packages/vitest/src/node/plugins/index.ts +++ b/packages/vitest/src/node/plugins/index.ts @@ -4,6 +4,7 @@ import type { ResolvedConfig, UserConfig } from '../../types' import { deepMerge, ensurePackageInstalled, notNullish } from '../../utils' import { resolveApiConfig } from '../config' import { Vitest } from '../core' +import { EnvReplacerPlugin } from './envRelacer' import { GlobalSetupPlugin } from './globalSetup' import { MocksPlugin } from './mock' @@ -66,14 +67,6 @@ export async function VitestPlugin(options: UserConfig = {}, ctx = new Vitest()) // setting this option can bypass that and fallback to cjs version mainFields: [], }, - define: { - 'process.env.NODE_ENV': 'process.env.NODE_ENV', - 'global.process.env.NODE_ENV': 'global.process.env.NODE_ENV', - 'globalThis.process.env.NODE_ENV': 'globalThis.process.env.NODE_ENV', - // so people can reassign envs at runtime - // import.meta.env.VITE_NAME = 'app' -> process.env.VITE_NAME = 'app' - 'import.meta.env': 'process.env', - }, server: { ...preOptions.api, open: preOptions.ui && preOptions.open @@ -99,6 +92,16 @@ export async function VitestPlugin(options: UserConfig = {}, ctx = new Vitest()) ) options.api = resolveApiConfig(options) + // we cannot replace them, because esbuild will throw an error, + // so we are removing them to allow reassigning + const define = viteConfig.define + + if (define) { + delete define['process.env.NODE_ENV'] + delete define['global.process.env.NODE_ENV'] + delete define['globalThis.process.env.NODE_ENV'] + } + // we replace every "import.meta.env" with "process.env" // to allow reassigning, so we need to put all envs on process.env const { PROD, DEV, ...envs } = viteConfig.env @@ -125,6 +128,7 @@ export async function VitestPlugin(options: UserConfig = {}, ctx = new Vitest()) await server.watcher.close() }, }, + EnvReplacerPlugin(), MocksPlugin(), GlobalSetupPlugin(ctx), options.ui