slate icon indicating copy to clipboard operation
slate copied to clipboard

Slate errors cannot be caught by error boundaries and crash the whole app

Open helios1138 opened this issue 4 years ago • 4 comments

For some reason, currently, slate errors crash the whole app and cannot be caught by https://reactjs.org/docs/error-boundaries.html

helios1138 avatar Oct 28 '20 13:10 helios1138

Need a minimum reproduction. Also, please fill out the template, it's there for a reason.

cameracker avatar Oct 29 '20 16:10 cameracker

I think this occurs because React error boundaries will only catch errors that occur in the render cycle and not errors in event-handlers? We have experienced this issue too. It would be nice to use a React error boundary to catch all Slate errors, but I'm not sure it's possible.

Unfortunately, may have to wrap each Slate call in a try/catch, which is super cumbersome, unless you have another suggestion @helios1138? Really, I am not so sure that Slate should be throwing so many errors in the codebase. It may be a bit of an anti-pattern and the code might benefit from returning null vs. throwing errors in a number of locations. But that requires some more thought/discussion...

BrentFarese avatar Oct 30 '20 14:10 BrentFarese

Unfortunately, may have to wrap each Slate call in a try/catch

I actually just created a plugin to do this. It was surprisingly simple.

import { logError } from '~/utils/logError';

const tryCatchCallback =
  (callback) =>
  (...args) => {
    try {
      return callback(...args);
    } catch (error) {
      logError(error);
      throw error;
    }
  };

export const withErrorReporting = (editor) => {
  Object.entries(editor).forEach(([key, value]) => {
    if (typeof value === 'function') {
      editor[key] = tryCatchCallback(value);
    }
  });

  return editor;
};

You just need to make sure it's the outermost plugin, so that it runs first. Works like a charm.

Edit: See any problems with a solution like this?

guldenmw avatar Jan 26 '23 15:01 guldenmw

@guldenmw thanks alot for sharing your simple yet very helpful Slate error-handling plugin. works great, while React ErrorBoundary utilizing componentDidCatch did not

I am calling editor.undo() in case of error. I yet have to test it in real-life conditions for undesired side-effects.

import { Editor } from 'slate'

// tries to invoke editorFunc. in case of error, it undoes the last action and captures exception
const tryCatchCallback =
  (editorFunc: any, editor: Editor) =>
  (...editorFuncArgs: any) => {
    try {
      return editorFunc(...editorFuncArgs)
    } catch (error) {
      captureException(error as Error)
      editor.undo()
    }
  }

// wraps all editor functions with our tryCatchCallback
export const withErrorReporting = (editor: any): Editor => {
  Object.entries(editor).forEach(([key, value]) => {
    if (typeof value === 'function') {
      editor[key] = tryCatchCallback(value, editor)
    }
  })

  return editor as Editor
}

philicious avatar Nov 18 '23 14:11 philicious