diff --git a/packages/app-desktop/gui/ErrorBoundary.tsx b/packages/app-desktop/gui/ErrorBoundary.tsx index cfd6879e6..d9f7c12cd 100644 --- a/packages/app-desktop/gui/ErrorBoundary.tsx +++ b/packages/app-desktop/gui/ErrorBoundary.tsx @@ -23,13 +23,17 @@ interface State { pluginInfos: PluginInfo[]; } -interface Props {} +interface Props { + message?: string; +} export default class ErrorBoundary extends React.Component { public state: State = { error: null, errorInfo: null, pluginInfos: [] }; - componentDidCatch(error: Error, errorInfo: ErrorInfo) { + componentDidCatch(error: any, errorInfo: ErrorInfo) { + if (typeof error === 'string') error = { message: error }; + const pluginInfos: PluginInfo[] = []; try { const service = PluginService.instance(); @@ -61,6 +65,11 @@ export default class ErrorBoundary extends React.Component { ipcRenderer.on('appClose', onAppClose); } + renderMessage() { + const message = this.props.message || 'Joplin encountered a fatal error and could not continue.'; + return

{message}

; + } + render() { if (this.state.error) { const safeMode_click = async () => { @@ -118,8 +127,9 @@ export default class ErrorBoundary extends React.Component { return (

Error

-

Joplin encountered a fatal error and could not continue. To report the error, please copy the *entire content* of this page and post it on Joplin forum or GitHub.

-

To continue you may close the app. Alternatively, if the error persists you may try to restart in safe mode, which will temporarily disable all plugins.

+ {this.renderMessage()} +

To report the error, please copy the *entire content* of this page and post it on Joplin forum or GitHub.

+

If the error persists you may try to restart in safe mode, which will temporarily disable all plugins.

{output}
); diff --git a/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/CodeMirror.tsx b/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/CodeMirror.tsx index 8e43e7dbc..ee245c302 100644 --- a/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/CodeMirror.tsx +++ b/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/CodeMirror.tsx @@ -32,6 +32,7 @@ const shared = require('@joplin/lib/components/shared/note-screen-shared.js'); const Menu = bridge().Menu; const MenuItem = bridge().MenuItem; import { reg } from '@joplin/lib/registry'; +import ErrorBoundary from '../../../ErrorBoundary'; const menuUtils = new MenuUtils(CommandService.instance()); @@ -599,7 +600,16 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) { pluginAssets: renderedBody.pluginAssets, downloadResources: Setting.value('sync.resourceDownloadMode'), }; - webviewRef.current.wrappedInstance.send('setHtml', renderedBody.html, options); + + // It seems when there's an error immediately when the component is + // mounted, webviewReady might be true, but webviewRef.current will be + // undefined. Maybe due to the error boundary that unmount components. + // Since we can't do much about it we just print an error. + if (webviewRef.current && webviewRef.current.wrappedInstance) { + webviewRef.current.wrappedInstance.send('setHtml', renderedBody.html, options); + } else { + console.error('Trying to set HTML on an undefined webview ref'); + } }, [renderedBody, webviewReady]); useEffect(() => { @@ -791,16 +801,18 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) { } return ( -
-
- - {props.noteToolbar} + +
+
+ + {props.noteToolbar} +
+
+ {renderEditor()} + {renderViewer()} +
-
- {renderEditor()} - {renderViewer()} -
-
+ ); } diff --git a/packages/app-desktop/gui/NoteEditor/NoteEditor.tsx b/packages/app-desktop/gui/NoteEditor/NoteEditor.tsx index c90021a5e..854895bac 100644 --- a/packages/app-desktop/gui/NoteEditor/NoteEditor.tsx +++ b/packages/app-desktop/gui/NoteEditor/NoteEditor.tsx @@ -545,7 +545,7 @@ function NoteEditor(props: NoteEditorProps) { onTitleChange={onTitleChange} /> {renderSearchInfo()} -
+
{editor}