Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions packages/next/src/server/config-shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export type NextConfigComplete = Required<Omit<NextConfig, 'configFile'>> & {
prefetchInlining?: PrefetchInliningConfig
// Normalized by config.ts: defaulted to 90% of staticPageGenerationTimeout
useCacheTimeout: number
// Normalized by config.ts `finalizeConfig`: defaulted to `'manual-warning'`
// Normalized by config.ts `finalizeConfig`: defaulted to `'warning'`
instantInsights: { validationLevel: ValidationLevel }
}
// The root directory of the distDir. In development mode, this is the parent directory of `distDir`
Expand Down Expand Up @@ -1086,10 +1086,10 @@ export interface ExperimentalConfig {
/**
* Controls the validation behavior of Instant Insights
*
* - `'warning'`: Validates all navigations for Instant UI in development
* - `'manual-warning'`: Validates navigations for Instant UI in development when configured with `unstable_instant` in Pages and Layouts
* - `'warning'` (default): Validates all navigations for Instant UI in development
* - `'manual-warning'`: Validates navigations for Instant UI in development only when configured with `unstable_instant` in Pages and Layouts
* - `'experimental-error'`: Validates all navigations for Instant in development and build. Use with caution.
* - `'experimental-manual-error'`: Validates navigations for Instant UI in developement and build when configured with `unstable_instant` in Pages and Layouts. Use with caution.
* - `'experimental-manual-error'`: Validates navigations for Instant UI in development and build when configured with `unstable_instant` in Pages and Layouts. Use with caution.
*/
validationLevel?: ValidationLevel
}
Expand Down
2 changes: 1 addition & 1 deletion packages/next/src/server/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1618,7 +1618,7 @@ function assignDefaultsAndValidate(
function finalizeConfig(config: NextConfigComplete): NextConfigComplete {
config.experimental.instantInsights = {
validationLevel:
config.experimental.instantInsights?.validationLevel ?? 'manual-warning',
config.experimental.instantInsights?.validationLevel ?? 'warning',
Comment thread
vercel[bot] marked this conversation as resolved.
}
return config
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
*/
const nextConfig = {
cacheComponents: true,
experimental: {
instantInsights: {
validationLevel: 'manual-warning',
},
},
}

module.exports = nextConfig
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
/**
* @type {import('next').NextConfig}
*/
const nextConfig = {}
const nextConfig = {
experimental: {
instantInsights: {
validationLevel: 'manual-warning',
},
},
}

module.exports = nextConfig
12 changes: 12 additions & 0 deletions test/development/app-dir/hmr-iframe/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* @type {import('next').NextConfig}
*/
const nextConfig = {
experimental: {
instantInsights: {
validationLevel: 'manual-warning',
},
},
}

module.exports = nextConfig
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
/**
* @type {import('next').NextConfig}
*/
const nextConfig = {}
const nextConfig = {
experimental: {
instantInsights: {
validationLevel: 'manual-warning',
},
},
}

module.exports = nextConfig
8 changes: 7 additions & 1 deletion test/development/app-dir/owner-stack/next.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
/**
* @type {import('next').NextConfig}
*/
const nextConfig = {}
const nextConfig = {
experimental: {
instantInsights: {
validationLevel: 'manual-warning',
},
},
}

module.exports = nextConfig
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
*/
const nextConfig = {
cacheComponents: true,
experimental: {
instantInsights: {
validationLevel: 'manual-warning',
},
},
}

module.exports = nextConfig
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ const nextConfig = {
cacheComponents: true,
experimental: {
authInterrupts: true,
instantInsights: {
validationLevel: 'manual-warning',
},
},
}

Expand Down
5 changes: 5 additions & 0 deletions test/e2e/app-dir/cache-components/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ const nextConfig = {
cacheComponents: true,
adapterPath:
process.env.NEXT_ADAPTER_PATH ?? require.resolve('./my-adapter.mjs'),
experimental: {
instantInsights: {
validationLevel: 'manual-warning',
},
},
}

module.exports = nextConfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Bare page (no `unstable_instant` config). Under the framework default
// (`'warning'`), implicit validation fires on this page in dev. The runtime
// data accessed at the top of the page is the "Suspense too high for instant
// navigation" violation that instant validation specifically flags. The root
// layout's Suspense satisfies static-shell validation, so the only error in
// dev is the instant one.
import { connection } from 'next/server'

export default async function Page() {
await connection()
return (
<main>
<p>bare page (no unstable_instant), runtime data at the top.</p>
</main>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Page explicitly opts out of instant validation. Under the framework
// default (`'warning'`), this segment-level override suppresses the
// implicit validation that would otherwise fire on a bare page, so no
// redbox appears.
import { connection } from 'next/server'

export const unstable_instant = false

export default async function Page() {
await connection()
return (
<main>
<p>explicit-false page (segment opts out of validation).</p>
</main>
)
}
23 changes: 23 additions & 0 deletions test/e2e/app-dir/instant-validation-level-default/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Suspense, type ReactNode } from 'react'

// Validation level is not set in next.config.ts, so the framework default
// applies. The default is 'warning' — implicit validation fires on bare
// page/default segments in dev only (build is unaffected unless a segment
// explicitly escalates with `level: 'experimental-error'`).
//
// Children are wrapped in Suspense so that pages with runtime data
// accessed at the top of the page don't fail static-shell validation
// (the Suspense fallback renders into the static shell). Instant
// validation flags "Suspense too high for instant navigation" as an
// instant-specific violation when it runs.
export const unstable_instant = false

export default function RootLayout({ children }: { children: ReactNode }) {
return (
<html>
<body>
<Suspense fallback={<p>loading…</p>}>{children}</Suspense>
</body>
</html>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { nextTestSetup } from 'e2e-utils'
import { expectBuildValidationSkipped } from 'e2e-utils/instant-validation'
import { waitForNoErrorToast } from '../../../lib/next-test-utils'

// This fixture intentionally omits `experimental.instantInsights` from
// next.config.ts. It pins the framework default for `validationLevel` —
// the framework should resolve the default to `'warning'`, which means
// implicit validation fires on bare pages in dev. If the framework default
// ever changes, this test should fail, alerting whoever changes it.
//
// For exhaustive coverage of explicit levels and per-segment overrides,
// see the sibling `instant-validation-level-{warning,manual-warning,error,
// manual-error}` fixtures.
describe('instant validation - default level', () => {
const { next, skipped, isNextDev, isNextStart, isTurbopack } = nextTestSetup({
files: __dirname,
skipStart: true,
skipDeployment: true,
env: {
NEXT_TEST_LOG_VALIDATION: '1',
},
})
if (skipped) return

if (isNextStart && !isTurbopack) {
it.skip('TODO: snapshot tests for webpack', () => {})
return
}

if (isNextStart) {
beforeAll(async () => {
await next.build({ args: ['--experimental-build-mode', 'compile'] })
})
afterEach(async () => {
await next.stop()
})
} else {
beforeAll(async () => {
await next.start()
})
}

const prerender = async (pathname: string) => {
return await next.build({
args: [
'--experimental-build-mode',
'generate',
'--debug-build-paths',
`app${pathname}/page.tsx`,
],
})
}

if (isNextDev) {
describe('dev', () => {
it('bare page: framework default matches `warning`, implicit validation fires', async () => {
const browser = await next.browser('/bare')
await expect(browser).toDisplayCollapsedRedbox(`
{
"code": "E1264",
"description": "Next.js encountered uncached data during a navigation.",
"environmentLabel": "Server",
"label": "Instant",
"source": "app/bare/page.tsx (10:19) @ Page
> 10 | await connection()
| ^",
"stack": [
"Page app/bare/page.tsx (10:19)",
],
}
`)
})

it('explicit-false page: per-segment opt-out still works under default', async () => {
const browser = await next.browser('/explicit-false')
await browser.elementByCss('main')
await waitForNoErrorToast(browser, { waitInMs: 500 })
})
})
} else {
describe('build', () => {
it('bare page: framework default is dev-only, build skips validation', async () => {
const result = await prerender('/bare')
expectBuildValidationSkipped(result)
})

it('explicit-false page: per-segment opt-out keeps build clean', async () => {
const result = await prerender('/explicit-false')
expectBuildValidationSkipped(result)
})
})
}
})
10 changes: 10 additions & 0 deletions test/e2e/app-dir/instant-validation-level-default/next.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
cacheComponents: true,
typescript: {
ignoreBuildErrors: true,
},
}

export default nextConfig
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ const nextConfig = {
images: {
loaderFile: '/dummy-loader.ts',
},
experimental: {
instantInsights: {
validationLevel: 'manual-warning',
},
},
}

module.exports = nextConfig
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
/**
* @type {import('next').NextConfig}
*/
const nextConfig = {}
const nextConfig = {
experimental: {
instantInsights: {
validationLevel: 'manual-warning',
},
},
}

module.exports = nextConfig
8 changes: 7 additions & 1 deletion test/e2e/app-dir/router-autoscroll/next.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
/**
* @type {import('next').NextConfig}
*/
const config = {}
const config = {
experimental: {
instantInsights: {
validationLevel: 'manual-warning',
},
},
}

module.exports = config
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ const nextConfig = {
experimental: {
cpus: 1,
serverSourceMaps: true,
instantInsights: {
validationLevel: 'manual-warning',
},
},
serverExternalPackages: ['external-pkg'],
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ const nextConfig = {
experimental: {
cpus: 1,
serverSourceMaps: true,
instantInsights: {
validationLevel: 'manual-warning',
},
},
}

Expand Down
5 changes: 5 additions & 0 deletions test/e2e/legacy-link-behavior/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
*/
const nextConfig = {
cacheComponents: true,
experimental: {
instantInsights: {
validationLevel: 'manual-warning',
},
},
}

module.exports = nextConfig
5 changes: 5 additions & 0 deletions test/e2e/next-image-new/app-dir-localpatterns/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,9 @@ module.exports = {
},
],
},
experimental: {
instantInsights: {
validationLevel: 'manual-warning',
},
},
}
Loading
Loading