diff --git a/packages/playground/ssr-react/__tests__/ssr-react.spec.ts b/packages/playground/ssr-react/__tests__/ssr-react.spec.ts index bf161e03e5143c..b39fa20ddb2567 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..f1b3ea9f58c312 --- /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 7bc8f5ecfd5c90..190fcf97766fc5 100644 --- a/packages/vite/src/node/plugins/define.ts +++ b/packages/vite/src/node/plugins/define.ts @@ -30,31 +30,54 @@ 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 = ssr + ? { + // account for non-node environments like v8 + 'process.env.': `(typeof process === 'undefined' ? {} : process.env).`, + 'global.process.env.': `(typeof global.process === 'undefined' ? {} : global.process.env).`, + 'globalThis.process.env.': `(typeof globalThis.process === 'undefined' ? {} : globalThis.process.env).` + } + : { + // client never has process + 'process.env.': `({}).`, + 'global.process.env.': `({}).`, + 'globalThis.process.env.': `({}).` + } + + 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, + ...processEnv + } + + const pattern = new RegExp( + '(? { + return str.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&') + }) + .join('|') + + ')\\b', + 'g' + ) + + return [replacements, pattern] } - const pattern = new RegExp( - '(? { - return str.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&') - }) - .join('|') + - ')\\b', - 'g' - ) + const defaultPattern = generatePattern(false) + const ssrPattern = generatePattern(true) return { name: 'vite:define', @@ -73,6 +96,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) => {