Fix global-error for nested routes (#60539)

## What

This fixes when the deep nested routes throws a client side error, it
can still be caught by the `global-error.js`

## How

We should always resolve global-error from root app directory instead of
current route's layout. Also fixed a bad test before where the
gloabl-error.js is not located correctly


Fixes #53756
Closes NEXT-1760
This commit is contained in:
Jiachi Liu 2024-01-11 23:28:17 +01:00 committed by GitHub
parent e07161a563
commit 98b99e408b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 47 additions and 10 deletions

View file

@ -198,7 +198,7 @@ async function createTreeCodeFromPath(
const pages: string[] = []
let rootLayout: string | undefined
let globalError: string = defaultGlobalErrorPath
let globalError: string | undefined
async function resolveAdjacentParallelSegments(
segmentPath: string
@ -356,18 +356,18 @@ async function createTreeCodeFromPath(
)?.[1]
rootLayout = layoutPath
if (isDefaultNotFound && !layoutPath) {
if (isDefaultNotFound && !layoutPath && !rootLayout) {
rootLayout = defaultLayoutPath
definedFilePaths.push(['layout', rootLayout])
}
}
if (layoutPath) {
const resolvedGlobalErrorPath = await resolver(
`${path.dirname(layoutPath)}/${GLOBAL_ERROR_FILE_TYPE}`
)
if (resolvedGlobalErrorPath) {
globalError = resolvedGlobalErrorPath
}
if (!globalError) {
const resolvedGlobalErrorPath = await resolver(
`${appDirPrefix}/${GLOBAL_ERROR_FILE_TYPE}`
)
if (resolvedGlobalErrorPath) {
globalError = resolvedGlobalErrorPath
}
}
@ -468,7 +468,7 @@ async function createTreeCodeFromPath(
treeCode: `${treeCode}.children;`,
pages: `${JSON.stringify(pages)};`,
rootLayout,
globalError,
globalError: globalError ?? defaultGlobalErrorPath,
}
}

View file

@ -12,3 +12,6 @@ export default function GlobalError({ error }) {
</html>
)
}
// for inspecting purpose
GlobalError.displayName = 'GlobalError'

View file

@ -0,0 +1,3 @@
export default function NestedLayout({ children }) {
return <div>{children}</div>
}

View file

@ -0,0 +1,19 @@
'use client'
import { useEffect, useState } from 'react'
export default function ClientPage() {
const [bad, setBad] = useState(false)
useEffect(() => {
setTimeout(() => {
setBad(true)
})
}, [])
if (bad) {
throw Error('nested error')
}
return <p>client page</p>
}

View file

@ -79,5 +79,17 @@ createNextDescribe(
)
}
})
it('should catch the client error thrown in the nested routes', async () => {
const browser = await next.browser('/nested/nested')
if (isNextDev) {
await testDev(browser, /Error: nested error/)
} else {
expect(await browser.elementByCss('h1').text()).toBe('Global Error')
expect(await browser.elementByCss('#error').text()).toBe(
'Global error: nested error'
)
}
})
}
)