Skip to content

Commit

Permalink
Update error handling during app static generation (#40823)
Browse files Browse the repository at this point in the history
This updates to ensure we properly error during static generation when a
non-dynamic SSR error is thrown so that unexpected errors are not
tolerated. This also fixes the static generation async storage not being
shared correctly due to different instances being created during
bundling.
  • Loading branch information
ijjk committed Sep 23, 2022
1 parent 1bbd264 commit ce77607
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 18 deletions.
2 changes: 2 additions & 0 deletions packages/next/build/webpack/loaders/next-app-loader.ts
Expand Up @@ -192,6 +192,8 @@ const nextAppLoader: webpack.LoaderDefinitionFunction<{
: 'null'
}
export const staticGenerationAsyncStorage = require('next/dist/client/components/static-generation-async-storage.js').staticGenerationAsyncStorage
export const serverHooks = require('next/dist/client/components/hooks-server-context.js')
export const renderToReadableStream = require('next/dist/compiled/react-server-dom-webpack/writer.browser.server').renderToReadableStream
Expand Down
8 changes: 4 additions & 4 deletions packages/next/client/components/redirect.ts
Expand Up @@ -17,8 +17,8 @@ export function redirect(url: string) {
use(createInfinitePromise())
}
// eslint-disable-next-line no-throw-literal
throw {
url,
code: REDIRECT_ERROR_CODE,
}
const error = new Error(REDIRECT_ERROR_CODE)
;(error as any).url = url
;(error as any).code = REDIRECT_ERROR_CODE
throw error
}
52 changes: 38 additions & 14 deletions packages/next/server/app-render.tsx
Expand Up @@ -75,31 +75,27 @@ function createErrorHandler(
/**
* Used for debugging
*/
_source: string
_source: string,
capturedErrors: Error[]
) {
return (err: any) => {
if (
// Use error message instead of type because HTML renderer uses Flight data which is serialized so it's not the same object instance.
err.message &&
!err.message.includes('Dynamic server usage') &&
// TODO-APP: Handle redirect throw
err.code !== REDIRECT_ERROR_CODE
err.code !== REDIRECT_ERROR_CODE &&
err.message !== REDIRECT_ERROR_CODE
) {
// Used for debugging error source
// console.error(_source, err)
console.error(err)
capturedErrors.push(err)
}

return null
}
}

const serverComponentsErrorHandler = createErrorHandler(
'serverComponentsRenderer'
)
const flightDataRendererErrorHandler = createErrorHandler('flightDataRenderer')
const htmlRendererErrorHandler = createErrorHandler('htmlRenderer')

let isFetchPatched = false

// we patch fetch to collect cache information used for
Expand All @@ -111,8 +107,7 @@ function patchFetch(ComponentMod: any) {
const { DynamicServerError } =
ComponentMod.serverHooks as typeof import('../client/components/hooks-server-context')

const { staticGenerationAsyncStorage } =
require('../client/components/static-generation-async-storage') as typeof import('../client/components/static-generation-async-storage')
const staticGenerationAsyncStorage = ComponentMod.staticGenerationAsyncStorage

const origFetch = (global as any).fetch

Expand Down Expand Up @@ -244,6 +239,7 @@ function createServerComponentRenderer(
>
rscChunks: Uint8Array[]
},
serverComponentsErrorHandler: ReturnType<typeof createErrorHandler>,
nonce?: string
): () => JSX.Element {
// We need to expose the `__webpack_require__` API globally for
Expand Down Expand Up @@ -518,6 +514,21 @@ export async function renderToHTMLOrFlight(
isPagesDir: boolean,
isStaticGeneration: boolean = false
): Promise<RenderResult | null> {
const capturedErrors: Error[] = []

const serverComponentsErrorHandler = createErrorHandler(
'serverComponentsRenderer',
capturedErrors
)
const flightDataRendererErrorHandler = createErrorHandler(
'flightDataRenderer',
capturedErrors
)
const htmlRendererErrorHandler = createErrorHandler(
'htmlRenderer',
capturedErrors
)

const {
buildManifest,
subresourceIntegrityManifest,
Expand All @@ -529,8 +540,7 @@ export async function renderToHTMLOrFlight(

patchFetch(ComponentMod)

const { staticGenerationAsyncStorage } =
require('../client/components/static-generation-async-storage') as typeof import('../client/components/static-generation-async-storage')
const staticGenerationAsyncStorage = ComponentMod.staticGenerationAsyncStorage

if (
!('getStore' in staticGenerationAsyncStorage) &&
Expand Down Expand Up @@ -771,6 +781,13 @@ export async function renderToHTMLOrFlight(

if (layoutOrPageMod?.config) {
defaultRevalidate = layoutOrPageMod.config.revalidate

if (isStaticGeneration && defaultRevalidate === 0) {
const { DynamicServerError } =
ComponentMod.serverHooks as typeof import('../client/components/hooks-server-context')

throw new DynamicServerError(`revalidate: 0 configured ${segment}`)
}
}
/**
* Checks if the current segment is a root layout.
Expand Down Expand Up @@ -1145,6 +1162,7 @@ export async function renderToHTMLOrFlight(
},
ComponentMod,
serverComponentsRenderOpts,
serverComponentsErrorHandler,
nonce
)

Expand Down Expand Up @@ -1248,6 +1266,12 @@ export async function renderToHTMLOrFlight(
(await readable.getReader().read()).value || ''
).toString()

// if we encountered any unexpected errors during build
// we fail the prerendering phase and the build
if (capturedErrors.length > 0) {
throw capturedErrors[0]
}

;(renderOpts as any).pageData = Buffer.concat(
serverComponentsRenderOpts.rscChunks
).toString()
Expand Down Expand Up @@ -1286,7 +1310,7 @@ export async function renderToHTMLOrFlight(
return new Promise<UnwrapPromise<ReturnType<typeof renderToHTMLOrFlight>>>(
(resolve, reject) => {
staticGenerationAsyncStorage.run(initialStaticGenerationStore, () => {
wrappedRender().then(resolve).catch(reject)
return wrappedRender().then(resolve).catch(reject)
})
}
)
Expand Down
3 changes: 3 additions & 0 deletions test/e2e/app-dir/app/app/old-router/page.js
@@ -1,6 +1,9 @@
import { useCookies } from 'next/dist/client/components/hooks-server'
import Router from './router'

export default function Page() {
useCookies()

return (
<div id="old-router">
<Router />
Expand Down
File renamed without changes.

0 comments on commit ce77607

Please sign in to comment.