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

feat(core): Add React ErrorBoundary component + theme default boundaries #3104

Merged
merged 26 commits into from
Nov 4, 2021

Conversation

spyke01
Copy link
Contributor

@spyke01 spyke01 commented Jul 23, 2020

Motivation

Close #2889

Added a configurable error boundary at the App component to wrap it and contain most errors without the need to add the error boundary at the clientEntry and serverEntry level.

Have you read the Contributing Guidelines on pull requests?

Yes

Test Plan

Yarn start and then create a breaking issue in lower level component to test for ErrorBoundary containing the error. For example, we take advantage of the known error (#5555) to test the error boundary.

Note: this is not intended to be a fix for that issue. We should wrap the live codeblock in this error boundary once we merge this.

Before:

Test

After:

Test2

@spyke01 spyke01 requested a review from yangshun as a code owner July 23, 2020 15:42
@facebook-github-bot facebook-github-bot added the CLA Signed Signed Facebook CLA label Jul 23, 2020
@docusaurus-bot
Copy link
Contributor

docusaurus-bot commented Jul 23, 2020

✔️ [V2]

🔨 Explore the source changes: de5c9b3

🔍 Inspect the deploy log: https://app.netlify.com/sites/docusaurus-2/deploys/6183f0c5bdfabd0008639cc0

😎 Browse the preview: https://deploy-preview-3104--docusaurus-2.netlify.app

@slorber
Copy link
Collaborator

slorber commented Jul 23, 2020

Thanks, will review it soon.

Important note: if rendering fails on the server, we need to fail fast, and not catch the rendering errors. We don't want to output static html files with errors in it without noticing :)

Also, we should apply one error boundary at the app level for maximum security, but I think we should also integrate this in our classic theme. As it's generally the "inner content" of a page that crashes, I think our theme Layout component should add another error boundary around its children props, so that if the inner content crashes, user can still see the navbar and navigate away from this error.

As we encourage users to implement their own themes, we could provide a helper comp. Here's how I see it used in theme layout:

export default function MyThemeLayout({ children }) {
  return (
    <div>
      <Navbar />
      <main>
        <DocusaurusErrorBoundary
          renderError={({ error, tryAgain }) => {
            return (
              <div>
                <h1>Hey, the app crashed: {error.message}</h1>
                <button onClick={() => tryAgain()}>Try again (attempt to re-render)</button>
              </div>
            );
          }}
        >
          {children}
        </DocusaurusErrorBoundary>
      </main>
    </div>
  );
}

This comp will only catch client-side errors, and give a hook to attempt a new re-render (sometimes it can fix the issue)

What do you think?

@spyke01
Copy link
Contributor Author

spyke01 commented Jul 23, 2020

I like that execution for the theme layout error boundary. It also lets us reuse that same design in the Docusaurus theme Layout component.

For resolving the server rendering issue, does the server render sent the mode as production? If so I can create another flat gon the boundary that disables the catching on production at the App level.

@slorber
Copy link
Collaborator

slorber commented Jul 23, 2020

There is ExecutionEnvironment.canUseDOM. If it can't use dom, we should just not call setState({error}) and the error will bubble up and crash the build, as we want.

This feature needs 2 components:

  • DocusaurusErrorBoundary, that we'll allow theme to implement (in client/exports folder)
  • Error, the "default" unthemed error screen, in client/theme-fallback)

The "Error" component would render a basic error screen with rough styles, but will let the themes like the classic theme override it to provide a better-looking error screen.

@spyke01
Copy link
Contributor Author

spyke01 commented Jul 23, 2020

Thanks for the feedback, I will work on these changes and push them back for review after testing.

@spyke01 spyke01 requested a review from lex111 as a code owner July 24, 2020 20:30
@spyke01
Copy link
Contributor Author

spyke01 commented Jul 24, 2020

I've pushed commits to try and address these issues. My typescript is rusty so I wasn't able to specify a function typing on therederError or tryAgain functions.

For DocusaurusErrorBoundary I tried to make it so that if renderError wasn't passed it would fallback to the theme and use the tryAgain param to handle the try again button. That way whatever section is being wrapped could have it's own try again passed in.

Let me know your thoughts or any tweaks you would recommend.

Copy link
Collaborator

@slorber slorber left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, that looks nice.

Changes needed:

  • DocusaurusErrorBoundary should not receive tryAgain as props. Instead, it should provides it to renderError)
  • TS: tryAgain?: () => void;
  • We need a beautiful themed way to display errors in the classic theme (theme/Error/index.tsx in theme classic to override the theme-fallback ugly default Error
  • Documentation doc DocusaurusErrorBoundary + Error

@slorber slorber marked this pull request as draft July 29, 2020 17:19
@slorber slorber changed the title refactor: add configurable error boundary around App component contents. feat(v2): error boundaries Jul 29, 2020
@slorber
Copy link
Collaborator

slorber commented Aug 20, 2020

Hi @spyke01

Do you plan to finish this PR? Or I can finish it for you?

@spyke01
Copy link
Contributor Author

spyke01 commented Aug 20, 2020 via email

@slorber
Copy link
Collaborator

slorber commented Aug 20, 2020

Thanks for letting me know, we'll figure out a way to get this code merged

@github-actions
Copy link

github-actions bot commented Oct 29, 2021

⚡️ Lighthouse report for the changes in this PR:

Category Score
🟢 Performance 95
🟢 Accessibility 98
🟢 Best practices 100
🟢 SEO 100
🟢 PWA 95

Lighthouse ran on https://deploy-preview-3104--docusaurus-2.netlify.app/

@Josh-Cena Josh-Cena changed the title feat(v2): error boundaries feat(core): error boundary Oct 29, 2021
@Josh-Cena Josh-Cena added the pr: new feature This PR adds a new API or behavior. label Oct 29, 2021
@Josh-Cena Josh-Cena marked this pull request as ready for review October 29, 2021 06:30
@Josh-Cena
Copy link
Collaborator

Josh-Cena commented Oct 29, 2021

@slorber I've resurrected this PR. Do things look good?

(Afaik componentDidCatch would only fire in the browser, so server build errors should always be reported, but I don't know how to test that)

@Josh-Cena
Copy link
Collaborator

/ping @slorber Ready for review

@slorber
Copy link
Collaborator

slorber commented Nov 4, 2021

Thanks, made some little changes, LGTM 👍

@Josh-Cena
Copy link
Collaborator

LGTM

There's a slight inconsistency between theme-fallback/Error and theme-classic/ErrorPageContent (center vs left aligned) but it looks fine

@slorber
Copy link
Collaborator

slorber commented Nov 4, 2021

There's a slight inconsistency between theme-fallback/Error and theme-classic/ErrorPageContent (center vs left aligned) but it looks fine

Yes, that doesn't seem like a big deal to me, the goal is not necessarily that those look the same, as we should hope that the inner boundary will catch most errors. Layout errors are expected but if you have one you likely have an important issue to fix 😆

@slorber slorber changed the title feat(core): error boundary feat(core): Add React ErrorBoundary component + theme default boundaries Nov 4, 2021
@slorber slorber merged commit fa6d15b into facebook:main Nov 4, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed Signed Facebook CLA pr: new feature This PR adds a new API or behavior.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Error boundaries
7 participants