Skip to content
Open
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
19 changes: 10 additions & 9 deletions packages/next/errors.json
Original file line number Diff line number Diff line change
Expand Up @@ -1244,13 +1244,14 @@
"1243": "This \"use cache\" has a dynamic cache life that was propagated to its parent.",
"1244": "A \"use cache\" with short \\`expire\\` (under 5 minutes) is nested inside another \"use cache\" that has no explicit \\`cacheLife\\`, which is not allowed during prerendering. Add \\`cacheLife()\\` to the outer \"use cache\" to choose whether it should be prerendered (with longer \\`expire\\`) or remain dynamic (with short \\`expire\\`). Read more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife",
"1245": "A \"use cache\" with zero \\`revalidate\\` is nested inside another \"use cache\" that has no explicit \\`cacheLife\\`, which is not allowed during prerendering. Add \\`cacheLife()\\` to the outer \"use cache\" to choose whether it should be prerendered (with non-zero \\`revalidate\\`) or remain dynamic (with zero \\`revalidate\\`). Read more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife",
"1246": "Route \"%s\": Next.js encountered uncached data during the initial render or a navigation.\\n\\n\\`fetch(...)\\` or \\`connection()\\` accessed under \\`<Suspense>\\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience.\\n\\nWays to fix this:\\n - Cache the data access with \\`\"use cache\"\\`\\n - Provide a placeholder with \\`<Suspense fallback={...}>\\` around the data access\\n - Set \\`export const instant = false\\` to allow a blocking route\\n\\nLearn more: https://nextjs.org/docs/messages/blocking-route",
"1247": "Route \"%s\": Next.js encountered runtime data during the initial render or a navigation.\\n\\n\\`cookies()\\`, \\`headers()\\`, \\`params\\`, or \\`searchParams\\` accessed under \\`<Suspense>\\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience.\\n\\nWays to fix this:\\n - Use \\`generateStaticParams\\` to make route params static\\n - Provide a placeholder with \\`<Suspense fallback={...}>\\` around the data access\\n - Set \\`export const instant = false\\` to allow a blocking route\\n\\nLearn more: https://nextjs.org/docs/messages/blocking-route",
"1248": "Could not validate instant UI because an expected segment was not rendered.",
"1249": "Route \"%s\": Next.js encountered uncached data during the initial render or a navigation.\\n\\n\\`fetch(...)\\` or \\`connection()\\` accessed outside of \\`<Suspense>\\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience.\\n\\nWays to fix this:\\n - Cache the data access with \\`\"use cache\"\\`\\n - Provide a placeholder with \\`<Suspense fallback={...}>\\` around the data access\\n - Set \\`export const instant = false\\` to allow a blocking route\\n\\nLearn more: https://nextjs.org/docs/messages/blocking-route",
"1250": "Route \"%s\": Next.js encountered runtime data during the initial render or a navigation.\\n\\n\\`cookies()\\`, \\`headers()\\`, \\`params\\`, or \\`searchParams\\` accessed outside of \\`<Suspense>\\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience.\\n\\nWays to fix this:\\n - Use \\`generateStaticParams\\` to make route params static\\n - Provide a placeholder with \\`<Suspense fallback={...}>\\` around the data access\\n - Set \\`export const instant = false\\` to allow a blocking route\\n\\nLearn more: https://nextjs.org/docs/messages/blocking-route",
"1251": "Route \"%s\": Next.js encountered runtime data during the initial render or a navigation.\\n\\n\\`cookies()\\`, \\`headers()\\`, \\`params\\`, or \\`searchParams\\` accessed outside of \\`<Suspense>\\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience.\\n\\nWays to fix this:\\n - Provide a placeholder with \\`<Suspense fallback={...}>\\` around the data access\\n - Use \\`generateStaticParams\\` to make route params static\\n - Set \\`export const instant = false\\` to allow a blocking route\\n\\nLearn more: https://nextjs.org/docs/messages/blocking-route",
"1252": "\\`experimental.cssChunking: \"graph\"\\` is only supported with Turbopack. Please remove the option or run Next.js with Turbopack in %s.",
"1253": "\\`experimental.cssChunking: \"strict\"\\` is only supported with webpack. Please remove the option or run Next.js with webpack in %s.",
"1254": "\\`experimental.cssChunking: false\\` is only supported with webpack. Please remove the option or run Next.js with webpack in %s."
"1246": "Could not validate instant UI because an expected segment was not rendered.",
"1247": "Invariant: expected static metadata route to have a prerender pathname (%s)",
"1248": "\\`experimental.cssChunking: \"graph\"\\` is only supported with Turbopack. Please remove the option or run Next.js with Turbopack in %s.",
"1249": "\\`experimental.cssChunking: \"strict\"\\` is only supported with webpack. Please remove the option or run Next.js with webpack in %s.",
"1250": "\\`experimental.cssChunking: false\\` is only supported with webpack. Please remove the option or run Next.js with webpack in %s.",
"1251": "Route \"%s\": Next.js encountered uncached data during the initial render or a navigation.\\n\\n\\`fetch(...)\\` or \\`connection()\\` accessed under \\`<Suspense>\\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience.\\n\\nWays to fix this:\\n - Cache the data access with \\`\"use cache\"\\`\\n - Provide a placeholder with \\`<Suspense fallback={...}>\\` around the data access\\n - Set \\`export const instant = false\\` to allow a blocking route\\n\\nLearn more: https://nextjs.org/docs/messages/blocking-route",
"1252": "Route \"%s\": Next.js encountered runtime data during the initial render or a navigation.\\n\\n\\`cookies()\\`, \\`headers()\\`, \\`params\\`, or \\`searchParams\\` accessed under \\`<Suspense>\\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience.\\n\\nWays to fix this:\\n - Use \\`generateStaticParams\\` to make route params static\\n - Provide a placeholder with \\`<Suspense fallback={...}>\\` around the data access\\n - Set \\`export const instant = false\\` to allow a blocking route\\n\\nLearn more: https://nextjs.org/docs/messages/blocking-route",
"1253": "Route \"%s\": Next.js encountered uncached data during the initial render or a navigation.\\n\\n\\`fetch(...)\\` or \\`connection()\\` accessed outside of \\`<Suspense>\\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience.\\n\\nWays to fix this:\\n - Cache the data access with \\`\"use cache\"\\`\\n - Provide a placeholder with \\`<Suspense fallback={...}>\\` around the data access\\n - Set \\`export const instant = false\\` to allow a blocking route\\n\\nLearn more: https://nextjs.org/docs/messages/blocking-route",
"1254": "Route \"%s\": Next.js encountered runtime data during the initial render or a navigation.\\n\\n\\`cookies()\\`, \\`headers()\\`, \\`params\\`, or \\`searchParams\\` accessed outside of \\`<Suspense>\\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience.\\n\\nWays to fix this:\\n - Use \\`generateStaticParams\\` to make route params static\\n - Provide a placeholder with \\`<Suspense fallback={...}>\\` around the data access\\n - Set \\`export const instant = false\\` to allow a blocking route\\n\\nLearn more: https://nextjs.org/docs/messages/blocking-route",
"1255": "Route \"%s\": Next.js encountered runtime data during the initial render or a navigation.\\n\\n\\`cookies()\\`, \\`headers()\\`, \\`params\\`, or \\`searchParams\\` accessed outside of \\`<Suspense>\\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience.\\n\\nWays to fix this:\\n - Provide a placeholder with \\`<Suspense fallback={...}>\\` around the data access\\n - Use \\`generateStaticParams\\` to make route params static\\n - Set \\`export const instant = false\\` to allow a blocking route\\n\\nLearn more: https://nextjs.org/docs/messages/blocking-route"
}
17 changes: 10 additions & 7 deletions packages/next/src/build/adapter/build-complete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import {
} from '../../lib/constants'

import { normalizeLocalePath } from '../../shared/lib/i18n/normalize-locale-path'
import { getStaticMetadataPrerenderPathname } from '../../lib/metadata/get-metadata-route'
import { isStaticMetadataFile } from '../../lib/metadata/is-metadata-route'
import { addPathPrefix } from '../../shared/lib/router/utils/add-path-prefix'
import { getRedirectStatus, modifyRouteRegex } from '../../lib/redirect-status'
Expand Down Expand Up @@ -988,19 +989,17 @@ export async function handleBuildComplete({
// Dynamic metadata routes (e.g. robots/sitemap using connection())
// should remain app routes in adapter outputs.
const isStaticMetadataRoute = isStaticMetadataFile(normalizedPage)
const staticMetadataPrerenderPathname =
getStaticMetadataPrerenderPathname(normalizedPage) ?? normalizedPage
const isPrerenderedMetadataRoute =
prerenderManifest.routes[normalizedPage] ||
prerenderManifest.dynamicRoutes[normalizedPage] ||
prerenderManifest.routes[staticMetadataPrerenderPathname] ||
config.i18n?.locales?.some((locale) => {
const localePathname = path.posix.join(
'/',
locale,
normalizedPage.slice(1)
)
return (
prerenderManifest.routes[localePathname] ||
prerenderManifest.dynamicRoutes[localePathname]
staticMetadataPrerenderPathname.slice(1)
)
return prerenderManifest.routes[localePathname]
})

if (isStaticMetadataRoute && isPrerenderedMetadataRoute) {
Expand Down Expand Up @@ -1522,6 +1521,10 @@ export async function handleBuildComplete({
}

for (const dynamicRoute in prerenderManifest.dynamicRoutes) {
if (isStaticMetadataFile(dynamicRoute)) {
continue
}

const {
fallback,
fallbackExpire,
Expand Down
60 changes: 56 additions & 4 deletions packages/next/src/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ import { webpackBuild } from './webpack-build'
import { NextBuildContext } from './build-context'
import { normalizePathSep } from '../shared/lib/page-path/normalize-path-sep'
import { isAppRouteRoute } from '../lib/is-app-route-route'
import { getStaticMetadataPrerenderPathname } from '../lib/metadata/get-metadata-route'
import { isStaticMetadataFile } from '../lib/metadata/is-metadata-route'
import { createClientRouterFilter } from '../lib/create-client-router-filter'
import { startTypeChecking } from './type-check'
import { generateInterceptionRoutesRewrites } from '../lib/generate-interception-routes-rewrites'
Expand Down Expand Up @@ -3183,13 +3185,39 @@ export default async function build(
const unsortedUnknownPrerenderRoutes: PrerenderedRoute[] = []
const unsortedKnownPrerenderRoutes: PrerenderedRoute[] = []
for (const prerenderedRoute of prerenderedRoutes) {
let route = prerenderedRoute
// Static metadata files under dynamic segments (e.g.
// `/[id]/apple-icon.png`) produce the same bytes regardless of
// params, so they prerender once to a canonical pathname with
// dynamic segments replaced by `-` (e.g. `/-/apple-icon.png`).
// Rewriting here ensures they land in `prerenderManifest.routes`
// as known static entries rather than in `dynamicRoutes` with
// fallback params, which they don't actually need.
const staticMetadataPrerenderPathname =
getStaticMetadataPrerenderPathname(prerenderedRoute.pathname)

if (
prerenderedRoute.fallbackRouteParams &&
prerenderedRoute.fallbackRouteParams.length > 0
staticMetadataPrerenderPathname &&
staticMetadataPrerenderPathname !== prerenderedRoute.pathname
) {
unsortedUnknownPrerenderRoutes.push(prerenderedRoute)
route = {
params: prerenderedRoute.params,
pathname: staticMetadataPrerenderPathname,
encodedPathname: staticMetadataPrerenderPathname,
fallbackRouteParams: undefined,
fallbackMode: prerenderedRoute.fallbackMode,
fallbackRootParams: undefined,
throwOnEmptyStaticShell: undefined,
}
}

if (
route.fallbackRouteParams &&
route.fallbackRouteParams.length > 0
) {
unsortedUnknownPrerenderRoutes.push(route)
} else {
unsortedKnownPrerenderRoutes.push(prerenderedRoute)
unsortedKnownPrerenderRoutes.push(route)
}
}

Expand Down Expand Up @@ -3363,6 +3391,16 @@ export default async function build(
}

for (const route of dynamicPrerenderedRoutes) {
// Static metadata files are rewritten above into the known
// static bucket under their `-`-placeholder pathname, so any
// entry that slips through here (e.g. an unexpected fallback
// shape) must not generate a dynamic PRERENDER manifest entry
// — the route handler shipped with the dynamic route still
// serves these at runtime.
if (isStaticMetadataFile(route.pathname)) {
continue
}

const normalizedRoute = normalizePagePath(route.pathname)
const parentPageInfo = pageInfos.get(page) as PageInfo

Expand Down Expand Up @@ -4069,6 +4107,20 @@ export default async function build(
NextBuildContext.allowedRevalidateHeaderKeys =
config.experimental.allowedRevalidateHeaderKeys

// Defensive sweep: static metadata files should never end up in
// `dynamicRoutes` because they are rewritten to the `-`-placeholder
// pathname and added to `routes` above. If anything upstream
// (e.g. a code path that calls `addDynamicRoute` directly) still
// registers a bracketed entry like `/[id]/apple-icon.png` here, the
// adapter would later look for a parent app output that doesn't
// exist and throw an invariant error. Strip those entries before the
// manifest is written.
for (const route of Object.keys(prerenderManifest.dynamicRoutes)) {
if (isStaticMetadataFile(route)) {
delete prerenderManifest.dynamicRoutes[route]
}
}

await writePrerenderManifest(distDir, prerenderManifest)
await writeManifest(
path.join(distDir, SERVER_DIRECTORY, PREFETCH_HINTS),
Expand Down
Loading
Loading