add experimental flag to allow forcing NODE_ENV=development in builds (#65463)
For debugging purposes, it can be useful to set `NODE_ENV=development` during a `next build`. Currently this value is forced to be production in Next.js. This PR adds an experimental flag to not force a mode of `production` when the flag is set. To use this flag, you'll still need to explicitly set `NODE_ENV=development`, while also enabling `nextConfig.experimental.allowDevelopmentBuild` Closes NEXT-3277
This commit is contained in:
parent
d0d22ac625
commit
8b9aa2dcc5
9 changed files with 126 additions and 2 deletions
|
@ -117,7 +117,9 @@ async function loaderTransform(
|
|||
filename,
|
||||
isServer,
|
||||
isPageFile,
|
||||
development: this.mode === 'development',
|
||||
development:
|
||||
this.mode === 'development' ||
|
||||
!!nextConfig.experimental?.allowDevelopmentBuild,
|
||||
hasReactRefresh,
|
||||
modularizeImports: nextConfig?.modularizeImports,
|
||||
optimizePackageImports: nextConfig?.experimental?.optimizePackageImports,
|
||||
|
|
|
@ -159,7 +159,10 @@ export function getDefineEnv({
|
|||
'process.turbopack': isTurbopack,
|
||||
'process.env.TURBOPACK': isTurbopack,
|
||||
// TODO: enforce `NODE_ENV` on `process.env`, and add a test:
|
||||
'process.env.NODE_ENV': dev ? 'development' : 'production',
|
||||
'process.env.NODE_ENV':
|
||||
dev || config.experimental.allowDevelopmentBuild
|
||||
? 'development'
|
||||
: 'production',
|
||||
'process.env.NEXT_RUNTIME': isEdgeServer
|
||||
? 'edge'
|
||||
: isNodeServer
|
||||
|
|
|
@ -421,6 +421,7 @@ export const configSchema: zod.ZodType<NextConfig> = z.lazy(() =>
|
|||
useEarlyImport: z.boolean().optional(),
|
||||
testProxy: z.boolean().optional(),
|
||||
defaultTestRunner: z.enum(SUPPORTED_TEST_RUNNERS_LIST).optional(),
|
||||
allowDevelopmentBuild: z.literal(true).optional(),
|
||||
})
|
||||
.optional(),
|
||||
exportPathMap: z
|
||||
|
|
|
@ -452,6 +452,10 @@ export interface ExperimentalConfig {
|
|||
* Set a default test runner to be used by `next experimental-test`.
|
||||
*/
|
||||
defaultTestRunner?: SupportedTestRunners
|
||||
/**
|
||||
* Allow NODE_ENV=development even for `next build`.
|
||||
*/
|
||||
allowDevelopmentBuild?: true
|
||||
}
|
||||
|
||||
export type ExportPathMap = {
|
||||
|
@ -963,6 +967,7 @@ export const defaultConfig: NextConfig = {
|
|||
dynamic: 30,
|
||||
static: 300,
|
||||
},
|
||||
allowDevelopmentBuild: undefined,
|
||||
},
|
||||
bundlePagesRouterDependencies: false,
|
||||
}
|
||||
|
|
|
@ -262,6 +262,15 @@ function assignDefaults(
|
|||
|
||||
const result = { ...defaultConfig, ...config }
|
||||
|
||||
if (
|
||||
result.experimental?.allowDevelopmentBuild &&
|
||||
process.env.NODE_ENV !== 'development'
|
||||
) {
|
||||
throw new Error(
|
||||
`The experimental.allowDevelopmentBuild option requires NODE_ENV to be explicitly set to 'development'.`
|
||||
)
|
||||
}
|
||||
|
||||
if (
|
||||
result.experimental?.ppr &&
|
||||
!process.env.__NEXT_VERSION!.includes('canary') &&
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
import { nextTestSetup } from 'e2e-utils'
|
||||
import { retry } from 'next-test-utils'
|
||||
|
||||
describe('allow-development-build', () => {
|
||||
describe('with NODE_ENV set to development', () => {
|
||||
const { next } = nextTestSetup({
|
||||
files: __dirname,
|
||||
env: {
|
||||
NODE_ENV: 'development',
|
||||
},
|
||||
nextConfig: {
|
||||
experimental: {
|
||||
allowDevelopmentBuild: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
it('should warn about a non-standard NODE_ENV', () => {
|
||||
expect(next.cliOutput).toContain(
|
||||
'You are using a non-standard "NODE_ENV" value in your environment'
|
||||
)
|
||||
})
|
||||
|
||||
it.each(['app-page', 'pages-page'])(
|
||||
`should show React development errors in %s`,
|
||||
async (page) => {
|
||||
const browser = await next.browser(page, {
|
||||
pushErrorAsConsoleLog: true,
|
||||
})
|
||||
|
||||
await retry(async () => {
|
||||
const logs = await browser.log()
|
||||
|
||||
const errorLogs = logs.filter((log) => log.source === 'error')
|
||||
|
||||
expect(errorLogs).toEqual(
|
||||
expect.arrayContaining([
|
||||
{
|
||||
message: expect.toBeOneOf([
|
||||
expect.stringContaining(
|
||||
"Hydration failed because the server rendered HTML didn't match the client. As a result this tree will be regenerated on the client."
|
||||
),
|
||||
expect.stringContaining(
|
||||
'There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.'
|
||||
),
|
||||
]),
|
||||
source: 'error',
|
||||
},
|
||||
])
|
||||
)
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
describe('with NODE_ENV not set to development', () => {
|
||||
const { next } = nextTestSetup({
|
||||
files: __dirname,
|
||||
skipStart: true,
|
||||
nextConfig: {
|
||||
experimental: {
|
||||
allowDevelopmentBuild: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
it('should fail the build with a message about not setting NODE_ENV', async () => {
|
||||
await next.start().catch(() => {})
|
||||
expect(next.cliOutput).toContain(
|
||||
"The experimental.allowDevelopmentBuild option requires NODE_ENV to be explicitly set to 'development'"
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
|
@ -0,0 +1,11 @@
|
|||
'use client'
|
||||
import React from 'react'
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<div>
|
||||
Hello World{' '}
|
||||
{typeof window !== 'undefined' && <span>Hydration Error!</span>}
|
||||
</div>
|
||||
)
|
||||
}
|
11
test/production/allow-development-build/app/layout.tsx
Normal file
11
test/production/allow-development-build/app/layout.tsx
Normal file
|
@ -0,0 +1,11 @@
|
|||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
export default function Page() {
|
||||
return (
|
||||
<div>
|
||||
Hello World{' '}
|
||||
{typeof window !== 'undefined' && <span>Hydration Error!</span>}
|
||||
</div>
|
||||
)
|
||||
}
|
Loading…
Reference in a new issue