fix(core): ensure core error boundary is able to render theme layout (#9852)

This commit is contained in:
Sébastien Lorber 2024-02-15 17:25:17 +01:00 committed by GitHub
parent 60d9346965
commit b26e262981
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -8,12 +8,13 @@
// Should we translate theme-fallback? // Should we translate theme-fallback?
/* eslint-disable @docusaurus/no-untranslated-text */ /* eslint-disable @docusaurus/no-untranslated-text */
import React from 'react'; import React, {type ReactNode} from 'react';
import Head from '@docusaurus/Head'; import Head from '@docusaurus/Head';
import ErrorBoundary from '@docusaurus/ErrorBoundary'; import ErrorBoundary from '@docusaurus/ErrorBoundary';
import {getErrorCausalChain} from '@docusaurus/utils-common'; import {getErrorCausalChain} from '@docusaurus/utils-common';
import Layout from '@theme/Layout'; import Layout from '@theme/Layout';
import type {Props} from '@theme/Error'; import type {Props} from '@theme/Error';
import {RouteContextProvider} from '../../routeContext';
function ErrorDisplay({error, tryAgain}: Props): JSX.Element { function ErrorDisplay({error, tryAgain}: Props): JSX.Element {
return ( return (
@ -54,21 +55,38 @@ function ErrorBoundaryError({error}: {error: Error}): JSX.Element {
return <p style={{whiteSpace: 'pre-wrap'}}>{fullMessage}</p>; return <p style={{whiteSpace: 'pre-wrap'}}>{fullMessage}</p>;
} }
// A bit hacky: we need to add an artificial RouteContextProvider here
// The goal is to be able to render the error inside the theme layout
// Without this, our theme classic would crash due to lack of route context
// See also https://github.com/facebook/docusaurus/pull/9852
function ErrorRouteContextProvider({children}: {children: ReactNode}) {
return (
<RouteContextProvider
value={{
plugin: {name: 'docusaurus-core-error-boundary', id: 'default'},
}}>
{children}
</RouteContextProvider>
);
}
export default function Error({error, tryAgain}: Props): JSX.Element { export default function Error({error, tryAgain}: Props): JSX.Element {
// We wrap the error in its own error boundary because the layout can actually // We wrap the error in its own error boundary because the layout can actually
// throw too... Only the ErrorDisplay component is simple enough to be // throw too... Only the ErrorDisplay component is simple enough to be
// considered safe to never throw // considered safe to never throw
return ( return (
<ErrorBoundary <ErrorRouteContextProvider>
// Note: we display the original error here, not the error that we <ErrorBoundary
// captured in this extra error boundary // Note: we display the original error here, not the error that we
fallback={() => <ErrorDisplay error={error} tryAgain={tryAgain} />}> // captured in this extra error boundary
<Head> fallback={() => <ErrorDisplay error={error} tryAgain={tryAgain} />}>
<title>Page Error</title> <Head>
</Head> <title>Page Error</title>
<Layout> </Head>
<ErrorDisplay error={error} tryAgain={tryAgain} /> <Layout>
</Layout> <ErrorDisplay error={error} tryAgain={tryAgain} />
</ErrorBoundary> </Layout>
</ErrorBoundary>
</ErrorRouteContextProvider>
); );
} }