Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build and generate cleanup #59420

Closed
wants to merge 1 commit into from
Closed
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
12 changes: 5 additions & 7 deletions packages/next/src/build/collect-build-traces.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Span } from '../trace'
import type { NextConfigComplete } from '../server/config-shared'
import type { PageInfoRegistry } from './page-info'

import {
TRACE_IGNORES,
Expand All @@ -14,7 +15,6 @@ import {

import path from 'path'
import fs from 'fs/promises'
import type { PageInfo } from './utils'
import { loadBindings } from './swc'
import { nonNullable } from '../lib/non-nullable'
import * as ciEnvironment from '../telemetry/ci-info'
Expand Down Expand Up @@ -67,7 +67,7 @@ export async function collectBuildTraces({
dir,
config,
distDir,
pageInfos,
pageInfoRegistry,
staticPages,
nextBuildSpan = new Span({ name: 'build' }),
hasSsrAmpPages,
Expand All @@ -79,7 +79,7 @@ export async function collectBuildTraces({
staticPages: string[]
hasSsrAmpPages: boolean
outputFileTracingRoot: string
pageInfos: [string, PageInfo][]
pageInfoRegistry: PageInfoRegistry | undefined
nextBuildSpan?: Span
config: NextConfigComplete
buildTraceContext?: BuildTraceContext
Expand Down Expand Up @@ -638,10 +638,8 @@ export async function collectBuildTraces({
}

// edge routes have no trace files
const [, pageInfo] = pageInfos.find((item) => item[0] === route) || []
if (pageInfo?.runtime === 'edge') {
return
}
const pageInfo = pageInfoRegistry?.get(route)
if (pageInfo?.runtime === 'edge') return

const combinedIncludes = new Set<string>()
const combinedExcludes = new Set<string>()
Expand Down
167 changes: 88 additions & 79 deletions packages/next/src/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,8 @@ import {
isReservedPage,
isAppBuiltinNotFoundPage,
} from './utils'
import type { PageInfo, AppConfig } from './utils'
import { PageInfoRegistry } from './page-info'
import type { AppConfig } from './utils'
import { writeBuildId } from './write-build-id'
import { normalizeLocalePath } from '../shared/lib/i18n/normalize-locale-path'
import isError from '../lib/is-error'
Expand Down Expand Up @@ -349,6 +350,34 @@ function pageToRoute(page: string) {
}
}

function createAppDataRouteInfo(
page: string,
{
supportsPPR,
isRouteHandler,
}: {
supportsPPR: boolean
isRouteHandler: boolean
}
): DataRouteRouteInfo {
const normalizedRoute = normalizePagePath(page)

// If the page is not a route handler we need to generate a data route.
let dataRoute: string | null = null
if (!isRouteHandler) {
dataRoute = path.posix.join(`${normalizedRoute}${RSC_SUFFIX}`)
}

let prefetchDataRoute: string | undefined
if (supportsPPR) {
prefetchDataRoute = path.posix.join(
`${normalizedRoute}${RSC_PREFETCH_SUFFIX}`
)
}

return { dataRoute, prefetchDataRoute }
}

export default async function build(
dir: string,
reactProductionProfiling = false,
Expand Down Expand Up @@ -395,6 +424,8 @@ export default async function build(
process.env.NEXT_DEPLOYMENT_ID = config.experimental.deploymentId || ''
NextBuildContext.config = config

const nextConfigPPREnabled = config.experimental.ppr === true

let configOutDir = 'out'
if (config.output === 'export' && config.distDir !== '.next') {
// In the past, a user had to run "next build" to generate
Expand Down Expand Up @@ -1109,7 +1140,7 @@ export default async function build(
dir,
config,
distDir,
pageInfos: [],
pageInfoRegistry: undefined,
staticPages: [],
hasSsrAmpPages: false,
buildTraceContext,
Expand Down Expand Up @@ -1183,7 +1214,7 @@ export default async function build(
const appNormalizedPaths = new Map<string, string>()
const appDynamicParamPaths = new Set<string>()
const appDefaultConfigs = new Map<string, AppConfig>()
const pageInfos = new Map<string, PageInfo>()
const pageInfoRegistry = new PageInfoRegistry()
const pagesManifest = JSON.parse(
await fs.readFile(manifestPath, 'utf8')
) as PagesManifest
Expand Down Expand Up @@ -1337,7 +1368,7 @@ export default async function build(
minimalMode: ciEnvironment.hasNextSupport,
allowedRevalidateHeaderKeys:
config.experimental.allowedRevalidateHeaderKeys,
experimental: { ppr: config.experimental.ppr === true },
experimental: { ppr: nextConfigPPREnabled },
})

incrementalCacheIpcPort = cacheInitialization.ipcPort
Expand Down Expand Up @@ -1408,7 +1439,7 @@ export default async function build(
locales: config.i18n?.locales,
defaultLocale: config.i18n?.defaultLocale,
nextConfigOutput: config.output,
ppr: config.experimental.ppr === true,
nextConfigPPREnabled,
})
)

Expand Down Expand Up @@ -1620,7 +1651,7 @@ export default async function build(
maxMemoryCacheSize:
config.experimental.isrMemoryCacheSize,
nextConfigOutput: config.output,
ppr: config.experimental.ppr === true,
nextConfigPPREnabled,
})
}
)
Expand All @@ -1636,11 +1667,8 @@ export default async function build(
`Using edge runtime on a page currently disables static generation for that page`
)
} else {
// If this route can be partially pre-rendered, then
// mark it as such and mark it that it can be
// generated server-side.
if (workerResult.isPPR) {
isPPR = workerResult.isPPR
isPPR = true
isSSG = true
isStatic = true

Expand Down Expand Up @@ -1838,7 +1866,7 @@ export default async function build(
}
}

pageInfos.set(page, {
pageInfoRegistry.set(page, {
size,
totalSize,
isStatic,
Expand Down Expand Up @@ -1923,7 +1951,7 @@ export default async function build(
dir,
config,
distDir,
pageInfos: Object.entries(pageInfos),
pageInfoRegistry,
staticPages: [...staticPages],
nextBuildSpan,
hasSsrAmpPages,
Expand Down Expand Up @@ -2164,7 +2192,7 @@ export default async function build(
})

// Ensure we don't generate explicit app prefetches while in PPR.
if (config.experimental.ppr && appPrefetchPaths.size > 0) {
if (nextConfigPPREnabled && appPrefetchPaths.size > 0) {
throw new Error(
"Invariant: explicit app prefetches shouldn't generated with PPR"
)
Expand Down Expand Up @@ -2258,24 +2286,25 @@ export default async function build(
appConfig.revalidate === 0 ||
exportResult.byPath.get(page)?.revalidate === 0

if (hasDynamicData && pageInfos.get(page)?.isStatic) {
const { isStatic, isPPR } = pageInfoRegistry.get(page, true)
if (hasDynamicData && isStatic) {
// if the page was marked as being static, but it contains dynamic data
// (ie, in the case of a static generation bailout), then it should be marked dynamic
pageInfos.set(page, {
...(pageInfos.get(page) as PageInfo),
pageInfoRegistry.patch(page, {
isStatic: false,
isSSG: false,
})
}

const isRouteHandler = isAppRouteRoute(originalAppPath)

// When this is an app page and PPR is enabled, the route supports
// partial pre-rendering.
const experimentalPPR =
!isRouteHandler && config.experimental.ppr === true
? true
: undefined
/**
* If this page is not an app route and PPR is enabled, then it
* could support PPR.
*/
const supportsPPR = !isRouteHandler && nextConfigPPREnabled

const experimentalPPR = isPPR ? true : undefined
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're now using the information yielded from the static analysis to determine if the page is static or not rather than duplicating the logic here.


// this flag is used to selectively bypass the static cache and invoke the lambda directly
// to enable server actions on static routes
Expand All @@ -2299,35 +2328,22 @@ export default async function build(
hasPostponed,
} = exportResult.byPath.get(route) ?? {}

pageInfos.set(route, {
...(pageInfos.get(route) as PageInfo),
hasPostponed,
hasEmptyPrelude,
})

// update the page (eg /blog/[slug]) to also have the postpone metadata
pageInfos.set(page, {
...(pageInfos.get(page) as PageInfo),
const pageInfo = pageInfoRegistry.patch(page, {
hasPostponed,
hasEmptyPrelude,
})

if (revalidate !== 0) {
const normalizedRoute = normalizePagePath(route)

let dataRoute: string | null
if (isRouteHandler) {
dataRoute = null
} else {
dataRoute = path.posix.join(`${normalizedRoute}${RSC_SUFFIX}`)
}
pageInfoRegistry.set(route, pageInfo)

let prefetchDataRoute: string | null | undefined
if (experimentalPPR) {
prefetchDataRoute = path.posix.join(
`${normalizedRoute}${RSC_PREFETCH_SUFFIX}`
)
}
if (revalidate !== 0) {
const { dataRoute, prefetchDataRoute } = createAppDataRouteInfo(
route,
{
supportsPPR,
isRouteHandler,
}
)

const routeMeta: Partial<SsgRoute> = {}

Expand Down Expand Up @@ -2373,33 +2389,27 @@ export default async function build(
hasDynamicData = true
// we might have determined during prerendering that this page
// used dynamic data
pageInfos.set(route, {
...(pageInfos.get(route) as PageInfo),
pageInfoRegistry.patch(route, {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This .patch method checks if the underlying page exists first, otherwise it throws. This ensures that we don't put the registry into an invalid state.

isSSG: false,
isStatic: false,
})
}
})

if (!hasDynamicData && isDynamicRoute(originalAppPath)) {
const normalizedRoute = normalizePagePath(page)
const dataRoute = path.posix.join(
`${normalizedRoute}${RSC_SUFFIX}`
const { dataRoute, prefetchDataRoute } = createAppDataRouteInfo(
page,
{
supportsPPR,
isRouteHandler,
}
)

let prefetchDataRoute: string | null | undefined
if (experimentalPPR) {
prefetchDataRoute = path.posix.join(
`${normalizedRoute}${RSC_PREFETCH_SUFFIX}`
)
}

pageInfos.set(page, {
...(pageInfos.get(page) as PageInfo),
pageInfoRegistry.patch(page, {
isDynamicAppRoute: true,
// if PPR is turned on and the route contains a dynamic segment,
// we assume it'll be partially prerendered
hasPostponed: experimentalPPR,
hasPostponed: supportsPPR,
})

// TODO: create a separate manifest to allow enforcing
Expand All @@ -2410,33 +2420,32 @@ export default async function build(
routeRegex: normalizeRouteRegex(
getNamedRouteRegex(page, false).re.source
),
dataRoute,
// if dynamicParams are enabled treat as fallback:
// 'blocking' if not it's fallback: false
fallback: appDynamicParamPaths.has(originalAppPath)
? null
: false,
dataRouteRegex: isRouteHandler
? null
: normalizeRouteRegex(
dataRoute,
dataRouteRegex: dataRoute
? normalizeRouteRegex(
getNamedRouteRegex(
dataRoute.replace(/\.rsc$/, ''),
false
).re.source.replace(/\(\?:\\\/\)\?\$$/, '\\.rsc$')
),
)
: null,
prefetchDataRoute,
prefetchDataRouteRegex:
isRouteHandler || !prefetchDataRoute
? undefined
: normalizeRouteRegex(
getNamedRouteRegex(
prefetchDataRoute.replace(/\.prefetch\.rsc$/, ''),
false
).re.source.replace(
/\(\?:\\\/\)\?\$$/,
'\\.prefetch\\.rsc$'
)
),
prefetchDataRouteRegex: prefetchDataRoute
? normalizeRouteRegex(
getNamedRouteRegex(
prefetchDataRoute.replace(/\.prefetch\.rsc$/, ''),
false
).re.source.replace(
/\(\?:\\\/\)\?\$$/,
'\\.prefetch\\.rsc$'
)
)
: undefined,
}
}
}
Expand Down Expand Up @@ -2601,7 +2610,7 @@ export default async function build(
const hasAmp = hybridAmpPages.has(page)
const file = normalizePagePath(page)

const pageInfo = pageInfos.get(page)
const pageInfo = pageInfoRegistry.get(page)
const durationInfo = exportResult.byPage.get(page)
if (pageInfo && durationInfo) {
// Set Build Duration
Expand Down Expand Up @@ -3083,7 +3092,7 @@ export default async function build(
console.log()

await nextBuildSpan.traceChild('print-tree-view').traceAsyncFn(() =>
printTreeView(pageKeys, pageInfos, {
printTreeView(pageKeys, pageInfoRegistry, {
distPath: distDir,
buildId: buildId,
pagesDir,
Expand Down
Loading