Make Hyper more robust against plugins

* Add some try/catch
* Support React@16 error boundaries for render decorated components
This commit is contained in:
CHaBou 2017-09-13 22:55:54 +02:00
parent 3e632577e5
commit 9bd410f1e4
No known key found for this signature in database
GPG key ID: EF8D073B729A0B33
2 changed files with 51 additions and 8 deletions

View file

@ -258,7 +258,11 @@ function requirePlugins() {
exports.onApp = app_ => {
modules.forEach(plugin => {
if (plugin.onApp) {
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) {
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;

View file

@ -431,7 +431,11 @@ function exposeDecorated(Component_) {
}
onRef(decorated_) {
if (this.props.onDecorated) {
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);
}
};