diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts
index 00573948a1c48..34cbe9cce37f9 100644
--- a/packages/next/build/webpack-config.ts
+++ b/packages/next/build/webpack-config.ts
@@ -867,15 +867,10 @@ export default async function getBaseWebpackConfig(
}
: undefined),
// stub process.env with proxy to warn a missing value is
- // being accessed
- ...(config.experimental.pageEnv
+ // being accessed in development mode
+ ...(config.experimental.pageEnv && process.env.NODE_ENV !== 'production'
? {
- 'process.env':
- process.env.NODE_ENV === 'production'
- ? isServer
- ? 'process.env'
- : '{}'
- : `
+ 'process.env': `
new Proxy(${isServer ? 'process.env' : '{}'}, {
get(target, prop) {
if (typeof target[prop] === 'undefined') {
diff --git a/test/integration/process-env-stub/components/hello.js b/test/integration/process-env-stub/components/hello.js
new file mode 100644
index 0000000000000..2c15eec0e9d52
--- /dev/null
+++ b/test/integration/process-env-stub/components/hello.js
@@ -0,0 +1,11 @@
+import { PHASE_PRODUCTION_BUILD } from 'next/constants'
+
+const { NODE_ENV } = process.env
+const { NEXT_PHASE } = process.env
+const SENTRY_DSN = process.env.NEXT_PUBLIC_SENTRY_DSN
+
+if (NODE_ENV !== 'development' && NEXT_PHASE !== PHASE_PRODUCTION_BUILD) {
+ console.log('next start', SENTRY_DSN)
+}
+
+export default () => process.env.HELLO || 'hi'
diff --git a/test/integration/process-env-stub/pages/missing.js b/test/integration/process-env-stub/pages/missing.js
index 7432bad23e77b..3a6edf410f886 100644
--- a/test/integration/process-env-stub/pages/missing.js
+++ b/test/integration/process-env-stub/pages/missing.js
@@ -1,4 +1,15 @@
+import dynamic from 'next/dynamic'
+
+const Hello = dynamic(() => import('../components/hello'), { ssr: true })
+
export default () => {
- console.log(process.env.hi)
- return
hi there 👋
+ // make sure we handle this syntax correctly
+ const { hi } = process.env
+ console.log(hi)
+ return (
+ <>
+ hi there 👋
+
+ >
+ )
}
diff --git a/test/integration/process-env-stub/test/index.test.js b/test/integration/process-env-stub/test/index.test.js
index b27b32817d87f..8b0968a26abf4 100644
--- a/test/integration/process-env-stub/test/index.test.js
+++ b/test/integration/process-env-stub/test/index.test.js
@@ -6,6 +6,8 @@ import {
launchApp,
renderViaHTTP,
waitFor,
+ nextBuild,
+ nextStart,
} from 'next-test-utils'
import { join } from 'path'
import webdriver from 'next-webdriver'
@@ -54,57 +56,113 @@ const checkMissingClient = async (pathname, prop, shouldWarn = false) => {
}
describe('process.env stubbing', () => {
- beforeAll(async () => {
- appPort = await findPort()
- app = await launchApp(appDir, appPort, {
- env: {
- NEXT_PUBLIC_HI: 'hi',
- I_SHOULD_BE_HERE: 'hello',
- },
- onStderr(msg) {
- stderr += msg || ''
- },
+ describe('dev mode', () => {
+ beforeAll(async () => {
+ appPort = await findPort()
+ app = await launchApp(appDir, appPort, {
+ env: {
+ NEXT_PUBLIC_HI: 'hi',
+ I_SHOULD_BE_HERE: 'hello',
+ },
+ onStderr(msg) {
+ stderr += msg || ''
+ },
+ })
})
- })
- afterAll(() => killApp(app))
+ afterAll(() => killApp(app))
- describe('server side', () => {
- it('should not show missing env value when its not missing public', async () => {
- await checkMissing('/not-missing', 'NEXT_PUBLIC_HI')
- })
+ describe('server side', () => {
+ it('should not show missing env value when its not missing public', async () => {
+ await checkMissing('/not-missing', 'NEXT_PUBLIC_HI')
+ })
- it('should not show missing env value when its not missing runtime', async () => {
- await checkMissing('/also-not-missing', 'I_SHOULD_BE_HERE')
- })
+ it('should not show missing env value when its not missing runtime', async () => {
+ await checkMissing('/also-not-missing', 'I_SHOULD_BE_HERE')
+ })
- it('should show missing env value when its missing normal', async () => {
- await checkMissing('/missing', 'hi', true)
- })
+ it('should show missing env value when its missing normal', async () => {
+ await checkMissing('/missing', 'hi', true)
+ })
- it('should show missing env value when its missing GSP', async () => {
- await checkMissing('/missing-gsp', 'SECRET', true)
- })
+ it('should show missing env value when its missing GSP', async () => {
+ await checkMissing('/missing-gsp', 'SECRET', true)
+ })
+
+ it('should show missing env value when its missing GSSP', async () => {
+ await checkMissing('/missing-gssp', 'SECRET', true)
+ })
- it('should show missing env value when its missing GSSP', async () => {
- await checkMissing('/missing-gssp', 'SECRET', true)
+ it('should show missing env value when its missing API', async () => {
+ await checkMissing('/api/hi', 'where_is_it', true)
+ })
})
- it('should show missing env value when its missing API', async () => {
- await checkMissing('/api/hi', 'where_is_it', true)
+ describe('client side', () => {
+ it('should not show missing env value when its not missing public', async () => {
+ await checkMissingClient('/not-missing', 'NEXT_PUBLIC_HI')
+ })
+
+ it('should show missing env value when its missing runtime', async () => {
+ await checkMissingClient('/also-not-missing', 'I_SHOULD_BE_HERE', true)
+ })
+
+ it('should show missing env value when its missing normal', async () => {
+ await checkMissingClient('/missing', 'hi', true)
+ })
})
})
- describe('client side', () => {
- it('should not show missing env value when its not missing public', async () => {
- await checkMissingClient('/not-missing', 'NEXT_PUBLIC_HI')
+ describe('production mode', () => {
+ beforeAll(async () => {
+ const { code } = await nextBuild(appDir)
+ if (code !== 0) throw new Error(`build failed with code ${code}`)
+ appPort = await findPort()
+ app = await nextStart(appDir, appPort, {
+ onStderr(msg) {
+ stderr += msg || ''
+ },
+ })
})
+ afterAll(() => killApp(app))
- it('should show missing env value when its missing runtime', async () => {
- await checkMissingClient('/also-not-missing', 'I_SHOULD_BE_HERE', true)
+ describe('server side', () => {
+ it('should not show missing env value when its not missing public', async () => {
+ await checkMissing('/not-missing', 'NEXT_PUBLIC_HI')
+ })
+
+ it('should not show missing env value when its not missing runtime', async () => {
+ await checkMissing('/also-not-missing', 'I_SHOULD_BE_HERE')
+ })
+
+ it('should not show missing env value when its missing normal', async () => {
+ await checkMissing('/missing', 'hi')
+ })
+
+ it('should not show missing env value when its missing GSP', async () => {
+ await checkMissing('/missing-gsp', 'SECRET')
+ })
+
+ it('should not show missing env value when its missing GSSP', async () => {
+ await checkMissing('/missing-gssp', 'SECRET')
+ })
+
+ it('should not show missing env value when its missing API', async () => {
+ await checkMissing('/api/hi', 'where_is_it')
+ })
})
- it('should show missing env value when its missing normal', async () => {
- await checkMissingClient('/missing', 'hi', true)
+ describe('client side', () => {
+ it('should not show missing env value when its not missing public', async () => {
+ await checkMissingClient('/not-missing', 'NEXT_PUBLIC_HI')
+ })
+
+ it('should not show missing env value when its missing runtime', async () => {
+ await checkMissingClient('/also-not-missing', 'I_SHOULD_BE_HERE')
+ })
+
+ it('should not show missing env value when its missing normal', async () => {
+ await checkMissingClient('/missing', 'hi')
+ })
})
})
})