diff --git a/packages/next/client/page-loader.js b/packages/next/client/page-loader.js index d6d6712ce044504c7da71c111885b99d072ce680..c8d3b1197d97aa7428167e0ac592e74a9bbf27be 100644 --- a/packages/next/client/page-loader.js +++ b/packages/next/client/page-loader.js @@ -1,12 +1,12 @@ import mitt from '../next-server/lib/mitt' +import { addBasePath, markLoadingError } from '../next-server/lib/router/router' +import escapePathDelimiters from '../next-server/lib/router/utils/escape-path-delimiters' +import getAssetPathFromRoute from './../next-server/lib/router/utils/get-asset-path-from-route' import { isDynamicRoute } from './../next-server/lib/router/utils/is-dynamic' +import { parseRelativeUrl } from './../next-server/lib/router/utils/parse-relative-url' +import { searchParamsToUrlQuery } from './../next-server/lib/router/utils/querystring' import { getRouteMatcher } from './../next-server/lib/router/utils/route-matcher' import { getRouteRegex } from './../next-server/lib/router/utils/route-regex' -import { searchParamsToUrlQuery } from './../next-server/lib/router/utils/querystring' -import { parseRelativeUrl } from './../next-server/lib/router/utils/parse-relative-url' -import escapePathDelimiters from '../next-server/lib/router/utils/escape-path-delimiters' -import getAssetPathFromRoute from './../next-server/lib/router/utils/get-asset-path-from-route' -import { addBasePath } from '../next-server/lib/router/router' function hasRel(rel, link) { try { @@ -16,9 +16,7 @@ function hasRel(rel, link) { } function pageLoadError(route) { - const error = new Error(`Error loading ${route}`) - error.code = 'PAGE_LOAD_ERROR' - return error + return markLoadingError(new Error(`Error loading ${route}`)) } const relPrefetch = diff --git a/packages/next/next-server/lib/router/router.ts b/packages/next/next-server/lib/router/router.ts index 825c85c79de7ffe41de9dbd57712644897f63d2b..ae75e2ed9a0d20df887f6e5fe05129077fa448fc 100644 --- a/packages/next/next-server/lib/router/router.ts +++ b/packages/next/next-server/lib/router/router.ts @@ -98,6 +98,11 @@ export function resolveHref(currentPath: string, href: Url): string { } } +const PAGE_LOAD_ERROR = Symbol('PAGE_LOAD_ERROR') +export function markLoadingError(err: Error): Error { + return Object.defineProperty(err, PAGE_LOAD_ERROR, {}) +} + function prepareUrlAs(router: NextRouter, url: Url, as: Url) { // If url and as provided as an object representation, // we'll format them into the string version here. @@ -205,7 +210,7 @@ function fetchNextData(dataHref: string, isServerRender: boolean) { // on a client-side transition. Otherwise, we'd get into an infinite // loop. if (!isServerRender) { - ;(err as any).code = 'PAGE_LOAD_ERROR' + markLoadingError(err) } throw err }) @@ -641,7 +646,7 @@ export default class Router implements BaseRouter { throw err } - if (err.code === 'PAGE_LOAD_ERROR' || loadErrorFail) { + if (PAGE_LOAD_ERROR in err || loadErrorFail) { Router.events.emit('routeChangeError', err, as) // If we can't load the page it could be one of following reasons diff --git a/test/integration/production/next.config.js b/test/integration/production/next.config.js index 4c11e179b1e04b1feebd49f4a8aaa54086be80a7..6570ba14b26d63afd22830f29969dccc22af7a7e 100644 --- a/test/integration/production/next.config.js +++ b/test/integration/production/next.config.js @@ -10,6 +10,16 @@ module.exports = { destination: '/:lang/about', permanent: false, }, + { + source: '/nonexistent', + destination: '/about', + permanent: false, + }, + { + source: '/shadowed-page', + destination: '/about', + permanent: false, + }, ] }, } diff --git a/test/integration/production/pages/shadowed-page.js b/test/integration/production/pages/shadowed-page.js new file mode 100644 index 0000000000000000000000000000000000000000..1fde3b29aee2db472e4c8c06ac6c0536017a0f6d --- /dev/null +++ b/test/integration/production/pages/shadowed-page.js @@ -0,0 +1,7 @@ +export function getServerSideProps() { + throw new Error('oops!') +} + +export default function ShadowedPage() { + return