diff --git a/packages/playground/ssr-react/__tests__/ssr-react.spec.ts b/packages/playground/ssr-react/__tests__/ssr-react.spec.ts index d7c3313b38e57a..2235d4ae4d0edf 100644 --- a/packages/playground/ssr-react/__tests__/ssr-react.spec.ts +++ b/packages/playground/ssr-react/__tests__/ssr-react.spec.ts @@ -4,6 +4,15 @@ import fetch from 'node-fetch' const url = `http://localhost:${port}` +test('/env', async () => { + await page.goto(url + '/env') + expect(await page.textContent('h1')).toMatch('default message here') + + // raw http request + const envHtml = await (await fetch(url + '/env')).text() + expect(envHtml).toMatch('API_KEY_qwertyuiop') +}) + test('/about', async () => { await page.goto(url + '/about') expect(await page.textContent('h1')).toMatch('About') diff --git a/packages/playground/ssr-react/server.js b/packages/playground/ssr-react/server.js index 6e04104181ba56..1876439c18fa88 100644 --- a/packages/playground/ssr-react/server.js +++ b/packages/playground/ssr-react/server.js @@ -5,6 +5,8 @@ const express = require('express') const isTest = process.env.NODE_ENV === 'test' || !!process.env.VITE_TEST_BUILD +process.env.MY_CUSTOM_SECRET = 'API_KEY_qwertyuiop' + async function createServer( root = process.cwd(), isProd = process.env.NODE_ENV === 'production' diff --git a/packages/playground/ssr-react/src/pages/Env.jsx b/packages/playground/ssr-react/src/pages/Env.jsx new file mode 100644 index 00000000000000..1102990f11c8cb --- /dev/null +++ b/packages/playground/ssr-react/src/pages/Env.jsx @@ -0,0 +1,7 @@ +export default function Env() { + let msg = 'default message here' + try { + msg = process.env.MY_CUSTOM_SECRET || msg + } catch {} + return

{msg}

+} diff --git a/packages/vite/src/node/plugins/define.ts b/packages/vite/src/node/plugins/define.ts index bc466cc3daae0a..3b7307b21851ba 100644 --- a/packages/vite/src/node/plugins/define.ts +++ b/packages/vite/src/node/plugins/define.ts @@ -7,6 +7,16 @@ import { isCSSRequest } from './css' export function definePlugin(config: ResolvedConfig): Plugin { const isBuild = config.command === 'build' + const processNodeEnv: Record = { + 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || config.mode), + 'global.process.env.NODE_ENV': JSON.stringify( + process.env.NODE_ENV || config.mode + ), + 'globalThis.process.env.NODE_ENV': JSON.stringify( + process.env.NODE_ENV || config.mode + ) + } + const userDefine: Record = {} for (const key in config.define) { const val = config.define[key] @@ -30,32 +40,42 @@ export function definePlugin(config: ResolvedConfig): Plugin { }) } - const replacements: Record = { - 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || config.mode), - 'global.process.env.NODE_ENV': JSON.stringify( - process.env.NODE_ENV || config.mode - ), - 'globalThis.process.env.NODE_ENV': JSON.stringify( - process.env.NODE_ENV || config.mode - ), - ...userDefine, - ...importMetaKeys, - 'process.env.': `({}).`, - 'global.process.env.': `({}).`, - 'globalThis.process.env.': `({}).` + function generatePattern( + ssr: boolean + ): [Record, RegExp] { + const processEnv: Record = {} + if (!ssr || config.ssr?.target === 'webworker') { + Object.assign(processEnv, { + 'process.env.': `({}).`, + 'global.process.env.': `({}).`, + 'globalThis.process.env.': `({}).` + }) + } + + const replacements: Record = { + ...processNodeEnv, + ...userDefine, + ...importMetaKeys, + ...processEnv + } + + const pattern = new RegExp( + // Do not allow preceding '.', but do allow preceding '...' for spread operations + '(? { + return str.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&') + }) + .join('|') + + ')\\b', + 'g' + ) + + return [replacements, pattern] } - const pattern = new RegExp( - // Do not allow preceding '.', but do allow preceding '...' for spread operations - '(? { - return str.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&') - }) - .join('|') + - ')\\b', - 'g' - ) + const defaultPattern = generatePattern(false) + const ssrPattern = generatePattern(true) return { name: 'vite:define', @@ -74,6 +94,8 @@ export function definePlugin(config: ResolvedConfig): Plugin { return } + const [replacements, pattern] = ssr ? ssrPattern : defaultPattern + if (ssr && !isBuild) { // ssr + dev, simple replace return code.replace(pattern, (_, match) => {