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

Update error handling during app static generation #40823

Merged
merged 3 commits into from Sep 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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