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) => {