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') + }) }) }) })