Skip to content

Commit

Permalink
Merge branch 'canary' into next-build-params
Browse files Browse the repository at this point in the history
  • Loading branch information
Brooooooklyn committed Mar 8, 2023
2 parents 04a40cb + bfc3849 commit 1e0bcb4
Show file tree
Hide file tree
Showing 15 changed files with 645 additions and 90 deletions.
5 changes: 5 additions & 0 deletions packages/next/src/build/index.ts
Expand Up @@ -1472,6 +1472,11 @@ export default async function build(
edgeInfo,
pageType,
hasServerComponents: !!appDir,
incrementalCacheHandlerPath:
config.experimental.incrementalCacheHandlerPath,
isrFlushToDisk: config.experimental.isrFlushToDisk,
maxMemoryCacheSize:
config.experimental.isrMemoryCacheSize,
})
}
)
Expand Down
237 changes: 168 additions & 69 deletions packages/next/src/build/utils.ts
Expand Up @@ -55,6 +55,10 @@ import {
overrideBuiltInReactPackages,
} from './webpack/require-hook'
import { isClientReference } from './is-client-reference'
import { StaticGenerationAsyncStorageWrapper } from '../server/async-storage/static-generation-async-storage-wrapper'
import { IncrementalCache } from '../server/lib/incremental-cache'
import { patchFetch } from '../server/lib/patch-fetch'
import { nodeFs } from '../server/lib/node-fs-methods'

loadRequireHook()
if (process.env.NEXT_PREBUNDLED_REACT) {
Expand Down Expand Up @@ -998,6 +1002,15 @@ export async function buildStaticPaths({
(repeat && !Array.isArray(paramValue)) ||
(!repeat && typeof paramValue !== 'string')
) {
// If from appDir and not all params were provided from
// generateStaticParams we can just filter this entry out
// as it's meant to be generated at runtime
if (appDir) {
builtPage = ''
encodedBuiltPage = ''
return
}

throw new Error(
`A required parameter (${validParamKey}) was not provided as ${
repeat ? 'an array' : 'a string'
Expand Down Expand Up @@ -1031,6 +1044,10 @@ export async function buildStaticPaths({
.replace(/(?!^)\/$/, '')
})

if (!builtPage && !encodedBuiltPage) {
return
}

if (entry.locale && !locales?.includes(entry.locale)) {
throw new Error(
`Invalid locale returned from getStaticPaths for ${page}, the locale ${entry.locale} is not specified in ${configFileName}`
Expand Down Expand Up @@ -1143,89 +1160,155 @@ export const collectGenerateParams = async (

export async function buildAppStaticPaths({
page,
distDir,
configFileName,
generateParams,
isrFlushToDisk,
incrementalCacheHandlerPath,
requestHeaders,
maxMemoryCacheSize,
fetchCacheKeyPrefix,
staticGenerationAsyncStorage,
serverHooks,
}: {
page: string
configFileName: string
generateParams: GenerateParams
incrementalCacheHandlerPath?: string
distDir: string
isrFlushToDisk?: boolean
fetchCacheKeyPrefix?: string
maxMemoryCacheSize?: number
requestHeaders: IncrementalCache['requestHeaders']
staticGenerationAsyncStorage: Parameters<
typeof patchFetch
>[0]['staticGenerationAsyncStorage']
serverHooks: Parameters<typeof patchFetch>[0]['serverHooks']
}) {
const pageEntry = generateParams[generateParams.length - 1]

// if the page has legacy getStaticPaths we call it like normal
if (typeof pageEntry?.getStaticPaths === 'function') {
return buildStaticPaths({
page,
configFileName,
getStaticPaths: pageEntry.getStaticPaths,
})
} else {
// if generateStaticParams is being used we iterate over them
// collecting them from each level
type Params = Array<Record<string, string | string[]>>
let hadGenerateParams = false

const buildParams = async (
paramsItems: Params = [{}],
idx = 0
): Promise<Params> => {
const curGenerate = generateParams[idx]

if (idx === generateParams.length) {
return paramsItems
}
if (
typeof curGenerate.generateStaticParams !== 'function' &&
idx < generateParams.length
) {
return buildParams(paramsItems, idx + 1)
}
hadGenerateParams = true
patchFetch({
staticGenerationAsyncStorage,
serverHooks,
})
let CacheHandler: any

if (incrementalCacheHandlerPath) {
CacheHandler = require(incrementalCacheHandlerPath)
CacheHandler = CacheHandler.default || CacheHandler
}

const incrementalCache = new IncrementalCache({
fs: nodeFs,
dev: true,
appDir: true,
flushToDisk: isrFlushToDisk,
serverDistDir: path.join(distDir, 'server'),
fetchCacheKeyPrefix,
maxMemoryCacheSize,
getPrerenderManifest: () => ({
version: -1 as any, // letting us know this doesn't conform to spec
routes: {},
dynamicRoutes: {},
notFoundRoutes: [],
preview: null as any, // `preview` is special case read in next-dev-server
}),
CurCacheHandler: CacheHandler,
requestHeaders,
})

const wrapper = new StaticGenerationAsyncStorageWrapper()

return wrapper.wrap(
staticGenerationAsyncStorage,
{
pathname: page,
renderOpts: {
incrementalCache,
supportsDynamicHTML: true,
isRevalidate: false,
isBot: false,
},
},
async () => {
const pageEntry = generateParams[generateParams.length - 1]

// if the page has legacy getStaticPaths we call it like normal
if (typeof pageEntry?.getStaticPaths === 'function') {
return buildStaticPaths({
page,
configFileName,
getStaticPaths: pageEntry.getStaticPaths,
})
} else {
// if generateStaticParams is being used we iterate over them
// collecting them from each level
type Params = Array<Record<string, string | string[]>>
let hadGenerateParams = false

const buildParams = async (
paramsItems: Params = [{}],
idx = 0
): Promise<Params> => {
const curGenerate = generateParams[idx]

if (idx === generateParams.length) {
return paramsItems
}
if (
typeof curGenerate.generateStaticParams !== 'function' &&
idx < generateParams.length
) {
return buildParams(paramsItems, idx + 1)
}
hadGenerateParams = true

const newParams = []

const newParams = []
for (const params of paramsItems) {
const result = await curGenerate.generateStaticParams({ params })
// TODO: validate the result is valid here or wait for
// buildStaticPaths to validate?
for (const item of result) {
newParams.push({ ...params, ...item })
}
}

for (const params of paramsItems) {
const result = await curGenerate.generateStaticParams({ params })
// TODO: validate the result is valid here or wait for
// buildStaticPaths to validate?
for (const item of result) {
newParams.push({ ...params, ...item })
if (idx < generateParams.length) {
return buildParams(newParams, idx + 1)
}
return newParams
}
}
const builtParams = await buildParams()
const fallback = !generateParams.some(
// TODO: dynamic params should be allowed
// to be granular per segment but we need
// additional information stored/leveraged in
// the prerender-manifest to allow this behavior
(generate) => generate.config?.dynamicParams === false
)

if (idx < generateParams.length) {
return buildParams(newParams, idx + 1)
}
return newParams
}
const builtParams = await buildParams()
const fallback = !generateParams.some(
// TODO: check complementary configs that can impact
// dynamicParams behavior
(generate) => generate.config?.dynamicParams === false
)
if (!hadGenerateParams) {
return {
paths: undefined,
fallback:
process.env.NODE_ENV === 'production' && isDynamicRoute(page)
? true
: undefined,
encodedPaths: undefined,
}
}

if (!hadGenerateParams) {
return {
paths: undefined,
fallback:
process.env.NODE_ENV === 'production' && isDynamicRoute(page)
? true
: undefined,
encodedPaths: undefined,
return buildStaticPaths({
staticPathsResult: {
fallback,
paths: builtParams.map((params) => ({ params })),
},
page,
configFileName,
appDir: true,
})
}
}

return buildStaticPaths({
staticPathsResult: {
fallback,
paths: builtParams.map((params) => ({ params })),
},
page,
configFileName,
appDir: true,
})
}
)
}

export async function isPageStatic({
Expand All @@ -1243,6 +1326,9 @@ export async function isPageStatic({
pageType,
hasServerComponents,
originalAppPath,
isrFlushToDisk,
maxMemoryCacheSize,
incrementalCacheHandlerPath,
}: {
page: string
distDir: string
Expand All @@ -1258,6 +1344,9 @@ export async function isPageStatic({
pageRuntime?: ServerRuntime
hasServerComponents?: boolean
originalAppPath?: string
isrFlushToDisk?: boolean
maxMemoryCacheSize?: number
incrementalCacheHandlerPath?: string
}): Promise<{
isStatic?: boolean
isAmpOnly?: boolean
Expand Down Expand Up @@ -1335,6 +1424,9 @@ export async function isPageStatic({
isClientComponent = isClientReference(componentsResult.ComponentMod)
const tree = componentsResult.ComponentMod.tree
const handlers = componentsResult.ComponentMod.handlers
const staticGenerationAsyncStorage =
componentsResult.ComponentMod.staticGenerationAsyncStorage
const serverHooks = componentsResult.ComponentMod.serverHooks

const generateParams: GenerateParams = handlers
? [
Expand Down Expand Up @@ -1399,8 +1491,15 @@ export async function isPageStatic({
encodedPaths: encodedPrerenderRoutes,
} = await buildAppStaticPaths({
page,
serverHooks,
staticGenerationAsyncStorage,
configFileName,
generateParams,
distDir,
requestHeaders: {},
isrFlushToDisk,
maxMemoryCacheSize,
incrementalCacheHandlerPath,
}))
}
} else {
Expand Down
3 changes: 2 additions & 1 deletion packages/next/src/lib/worker.ts
Expand Up @@ -49,7 +49,8 @@ export class Worker {
_child: ChildProcess
}[]) {
worker._child.on('exit', (code, signal) => {
if (code || signal) {
// log unexpected exit if .end() wasn't called
if ((code || signal) && this._worker) {
console.error(
`Static worker unexpectedly exited with code: ${code} and signal: ${signal}`
)
Expand Down
7 changes: 6 additions & 1 deletion packages/next/src/server/base-server.ts
Expand Up @@ -1096,6 +1096,7 @@ export default abstract class Server<ServerOptions extends Options = Options> {
pathname,
}: {
pathname: string
requestHeaders: import('./lib/incremental-cache').IncrementalCache['requestHeaders']
originalAppPath?: string
}): Promise<{
staticPaths?: string[]
Expand Down Expand Up @@ -1162,6 +1163,7 @@ export default abstract class Server<ServerOptions extends Options = Options> {
const pathsResult = await this.getStaticPaths({
pathname,
originalAppPath: components.pathname,
requestHeaders: req.headers,
})

staticPaths = pathsResult.staticPaths
Expand Down Expand Up @@ -1607,7 +1609,10 @@ export default abstract class Server<ServerOptions extends Options = Options> {

if (!staticPaths) {
;({ staticPaths, fallbackMode } = hasStaticPaths
? await this.getStaticPaths({ pathname })
? await this.getStaticPaths({
pathname,
requestHeaders: req.headers,
})
: { staticPaths: undefined, fallbackMode: false })
}

Expand Down
9 changes: 9 additions & 0 deletions packages/next/src/server/dev/next-dev-server.ts
Expand Up @@ -97,6 +97,7 @@ import { DefaultFileReader } from '../future/route-matcher-providers/dev/helpers
import { NextBuildContext } from '../../build/build-context'
import { logAppDirError } from './log-app-dir-error'
import { createClientRouterFilter } from '../../lib/create-client-router-filter'
import { IncrementalCache } from '../lib/incremental-cache'

// Load ReactDevOverlay only when needed
let ReactDevOverlayImpl: FunctionComponent
Expand Down Expand Up @@ -1511,9 +1512,11 @@ export default class DevServer extends Server {
protected async getStaticPaths({
pathname,
originalAppPath,
requestHeaders,
}: {
pathname: string
originalAppPath?: string
requestHeaders: IncrementalCache['requestHeaders']
}): Promise<{
staticPaths?: string[]
fallbackMode?: false | 'static' | 'blocking'
Expand Down Expand Up @@ -1545,6 +1548,12 @@ export default class DevServer extends Server {
defaultLocale,
originalAppPath,
isAppPath: !!originalAppPath,
requestHeaders,
incrementalCacheHandlerPath:
this.nextConfig.experimental.incrementalCacheHandlerPath,
fetchCacheKeyPrefix: this.nextConfig.experimental.fetchCacheKeyPrefix,
isrFlushToDisk: this.nextConfig.experimental.isrFlushToDisk,
maxMemoryCacheSize: this.nextConfig.experimental.isrMemoryCacheSize,
})
return pathsResult
}
Expand Down

0 comments on commit 1e0bcb4

Please sign in to comment.