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

Ability to Disable SSG Fallback #10701

Merged
merged 14 commits into from Feb 27, 2020
5 changes: 5 additions & 0 deletions packages/next/build/index.ts
Expand Up @@ -478,6 +478,7 @@ export default async function build(dir: string, conf = null): Promise<void> {
let isStatic = false
let isHybridAmp = false
let ssgPageRoutes: string[] | null = null
let hasSsgFallback: boolean = false

pagesManifest[page] = bundleRelative.replace(/\\/g, '/')

Expand Down Expand Up @@ -533,6 +534,9 @@ export default async function build(dir: string, conf = null): Promise<void> {
additionalSsgPaths.set(page, result.prerenderRoutes)
ssgPageRoutes = result.prerenderRoutes
}
if (result.prerenderFallback) {
hasSsgFallback = true
}
} else if (result.hasServerProps) {
serverPropsPages.add(page)
} else if (result.isStatic && customAppGetInitialProps === false) {
Expand Down Expand Up @@ -564,6 +568,7 @@ export default async function build(dir: string, conf = null): Promise<void> {
isSsg,
isHybridAmp,
ssgPageRoutes,
hasSsgFallback,
})
})
)
Expand Down
27 changes: 19 additions & 8 deletions packages/next/build/utils.ts
Expand Up @@ -42,6 +42,7 @@ export interface PageInfo {
static: boolean
isSsg: boolean
ssgPageRoutes: string[] | null
hasSsgFallback: boolean
serverBundle: string
}

Expand Down Expand Up @@ -500,7 +501,7 @@ export async function getPageSizeInKb(
export async function buildStaticPaths(
page: string,
unstable_getStaticPaths: Unstable_getStaticPaths
): Promise<Array<string>> {
): Promise<{ paths: string[]; fallback: boolean }> {
const prerenderPaths = new Set<string>()
const _routeRegex = getRouteRegex(page)
const _routeMatcher = getRouteMatcher(_routeRegex)
Expand All @@ -511,7 +512,7 @@ export async function buildStaticPaths(
const staticPathsResult = await unstable_getStaticPaths()

const expectedReturnVal =
`Expected: { paths: [] }\n` +
`Expected: { paths: [], fallback: boolean }\n` +
`See here for more info: https://err.sh/zeit/next.js/invalid-getstaticpaths-value`
Timer marked this conversation as resolved.
Show resolved Hide resolved

if (
Expand All @@ -525,7 +526,7 @@ export async function buildStaticPaths(
}

const invalidStaticPathKeys = Object.keys(staticPathsResult).filter(
key => key !== 'paths'
key => !(key === 'paths' || key === 'fallback')
)

if (invalidStaticPathKeys.length > 0) {
Expand All @@ -536,6 +537,13 @@ export async function buildStaticPaths(
)
}

if (typeof staticPathsResult.fallback !== 'boolean') {
throw new Error(
`The \`fallback\` key must be returned from unstable_getStaticProps in ${page}.\n` +
Timer marked this conversation as resolved.
Show resolved Hide resolved
expectedReturnVal
)
}

const toPrerender = staticPathsResult.paths

if (!Array.isArray(toPrerender)) {
Expand Down Expand Up @@ -601,7 +609,7 @@ export async function buildStaticPaths(
}
})

return [...prerenderPaths]
return { paths: [...prerenderPaths], fallback: staticPathsResult.fallback }
}

export async function isPageStatic(
Expand All @@ -614,6 +622,7 @@ export async function isPageStatic(
hasServerProps?: boolean
hasStaticProps?: boolean
prerenderRoutes?: string[] | undefined
prerenderFallback?: boolean | undefined
}> {
try {
require('../next-server/lib/runtime-config').setConfig(runtimeEnvConfig)
Expand Down Expand Up @@ -667,18 +676,20 @@ export async function isPageStatic(
}

let prerenderRoutes: Array<string> | undefined
let prerenderFallback: boolean | undefined
if (hasStaticProps && hasStaticPaths) {
prerenderRoutes = await buildStaticPaths(
page,
mod.unstable_getStaticPaths
)
;({
paths: prerenderRoutes,
fallback: prerenderFallback,
} = await buildStaticPaths(page, mod.unstable_getStaticPaths))
}

const config = mod.config || {}
return {
isStatic: !hasStaticProps && !hasGetInitialProps && !hasServerProps,
isHybridAmp: config.amp === 'hybrid',
prerenderRoutes,
prerenderFallback,
hasStaticProps,
hasServerProps,
}
Expand Down
1 change: 1 addition & 0 deletions packages/next/next-server/server/load-components.ts
Expand Up @@ -36,6 +36,7 @@ type Unstable_getStaticProps = (ctx: {

export type Unstable_getStaticPaths = () => Promise<{
paths: Array<string | { params: ParsedUrlQuery }>
fallback: boolean
}>

type Unstable_getServerProps = (context: {
Expand Down
30 changes: 22 additions & 8 deletions packages/next/next-server/server/next-server.ts
Expand Up @@ -870,7 +870,7 @@ export default class Server {
pathname: string,
{ components, query }: FindComponentsResult,
opts: any
): Promise<string | null> {
): Promise<string | false | null> {
// we need to ensure the status code if /404 is visited directly
if (pathname === '/404') {
res.statusCode = 404
Expand Down Expand Up @@ -1029,6 +1029,7 @@ export default class Server {
// we lazy load the staticPaths to prevent the user
// from waiting on them for the page to load in dev mode
let staticPaths: string[] | undefined
let hasStaticFallback = false
Timer marked this conversation as resolved.
Show resolved Hide resolved

if (!isProduction && hasStaticPaths) {
const __getStaticPaths = async () => {
Expand All @@ -1040,13 +1041,12 @@ export default class Server {
)
return paths
}

staticPaths = (
;({ paths: staticPaths, fallback: hasStaticFallback } = (
await withCoalescedInvoke(__getStaticPaths)(
`staticPaths-${pathname}`,
[]
)
).value
).value)
}

// const isForcedBlocking =
Expand Down Expand Up @@ -1074,6 +1074,10 @@ export default class Server {
// `getStaticPaths`
(isProduction || !staticPaths || !staticPaths.includes(urlPathname))
) {
if (!hasStaticFallback) {
return false
}

let html: string

// Production already emitted the fallback as static HTML.
Expand Down Expand Up @@ -1137,13 +1141,16 @@ export default class Server {
try {
const result = await this.findPageComponents(pathname, query)
if (result) {
return await this.renderToHTMLWithComponents(
const result2 = await this.renderToHTMLWithComponents(
req,
res,
pathname,
result,
{ ...this.renderOpts, amphtml, hasAmp }
)
if (result2 !== false) {
return result2
}
}

if (this.dynamicRoutes) {
Expand All @@ -1159,7 +1166,7 @@ export default class Server {
params
)
if (result) {
return await this.renderToHTMLWithComponents(
const result2 = await this.renderToHTMLWithComponents(
req,
res,
dynamicRoute.page,
Expand All @@ -1171,6 +1178,9 @@ export default class Server {
hasAmp,
}
)
if (result2 !== false) {
return result2
}
}
}
}
Expand Down Expand Up @@ -1224,9 +1234,9 @@ export default class Server {
result = await this.findPageComponents('/_error', query)
}

let html
let html: string | null
try {
html = await this.renderToHTMLWithComponents(
const result2 = await this.renderToHTMLWithComponents(
req,
res,
using404Page ? '/404' : '/_error',
Expand All @@ -1236,6 +1246,10 @@ export default class Server {
err,
}
)
if (result2 === false) {
throw new Error('invariant: failed to render error page')
}
html = result2
} catch (err) {
console.error(err)
res.statusCode = 500
Expand Down