diff --git a/app/plugins.js b/app/plugins.js index b251d192..d87a2dae 100644 --- a/app/plugins.js +++ b/app/plugins.js @@ -258,7 +258,11 @@ function requirePlugins() { exports.onApp = app_ => { modules.forEach(plugin => { if (plugin.onApp) { - plugin.onApp(app_); + try { + plugin.onApp(app_); + } catch (e) { + notify('Plugin error!', `"${plugin._name}" has encountered an error. Check Developer Tools for details.`); + } } }); }; @@ -266,7 +270,11 @@ exports.onApp = app_ => { exports.onWindow = win => { modules.forEach(plugin => { if (plugin.onWindow) { - plugin.onWindow(win); + try { + plugin.onWindow(win); + } catch (e) { + notify('Plugin error!', `"${plugin._name}" has encountered an error. Check Developer Tools for details.`); + } } }); }; @@ -277,7 +285,13 @@ function decorateObject(base, key) { let decorated = base; modules.forEach(plugin => { if (plugin[key]) { - const res = plugin[key](decorated); + let res; + try { + res = plugin[key](decorated); + } catch (e) { + notify('Plugin error!', `"${plugin._name}" has encountered an error. Check Developer Tools for details.`); + return; + } if (res && typeof res === 'object') { decorated = res; } else { @@ -292,7 +306,14 @@ function decorateObject(base, key) { exports.extendKeymaps = () => { modules.forEach(plugin => { if (plugin.extendKeymaps) { - const keys = _keys.extend(plugin.extendKeymaps()); + let pluginKeymap; + try { + pluginKeymap = plugin.extendKeymaps(); + } catch (e) { + notify('Plugin error!', `"${plugin._name}" has encountered an error. Check Developer Tools for details.`); + return; + } + const keys = _keys.extend(pluginKeymap); config.extendKeymaps(keys); } }); @@ -306,7 +327,13 @@ exports.getDeprecatedConfig = () => { return; } // We need to clone config in case of plugin modifies config directly. - const configTmp = plugin.decorateConfig(JSON.parse(JSON.stringify(baseConfig))); + let configTmp; + try { + configTmp = plugin.decorateConfig(JSON.parse(JSON.stringify(baseConfig))); + } catch (e) { + notify('Plugin error!', `"${plugin._name}" has encountered an error. Check Developer Tools for details.`); + return; + } const pluginCSSDeprecated = config.getDeprecatedCSS(configTmp); if (pluginCSSDeprecated.length === 0) { return; diff --git a/lib/utils/plugins.js b/lib/utils/plugins.js index b0445c9a..a86555ad 100644 --- a/lib/utils/plugins.js +++ b/lib/utils/plugins.js @@ -431,7 +431,11 @@ function exposeDecorated(Component_) { } onRef(decorated_) { if (this.props.onDecorated) { - this.props.onDecorated(decorated_); + try { + this.props.onDecorated(decorated_); + } catch (e) { + notify('Plugin error', `Error occurred. Check Developer Tools for details`); + } } } render() { @@ -487,9 +491,21 @@ function getDecorated(parent, name) { // that wraps with the higher-order components // exposed by plugins export function decorate(Component_, name) { - return class DecoratedCompenent extends React.Component { + return class DecoratedComponent extends React.Component { + constructor(props) { + super(props); + this.state = {has_error: false}; + } + componentDidCatch() { + this.setState({hasError: true}); + // No need to detail this error because React print those informations. + notify( + 'Plugin error', + `Plugins decorating ${name} has been disabled because of a plugin crash. Check Developer Tools for details.` + ); + } render() { - const Sub = getDecorated(Component_, name); + const Sub = this.state.hasError ? Component_ : getDecorated(Component_, name); return React.createElement(Sub, this.props); } };