diff --git a/app/javascript/mastodon/components/error_boundary.js b/app/javascript/mastodon/components/error_boundary.js new file mode 100644 index 000000000..d1ca5bf75 --- /dev/null +++ b/app/javascript/mastodon/components/error_boundary.js @@ -0,0 +1,39 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import illustration from '../../images/elephant_ui_disappointed.svg'; + +export default class ErrorBoundary extends React.PureComponent { + + static propTypes = { + children: PropTypes.node, + }; + + state = { + hasError: false, + stackTrace: undefined, + componentStack: undefined, + } + + componentDidCatch(error, info) { + this.setState({ + hasError: true, + stackTrace: error.stack, + componentStack: info && info.componentStack, + }); + } + + render() { + const { hasError } = this.state; + + if (!hasError) { + return this.props.children; + } + + return ( +
+ +
+ ); + } + +} diff --git a/app/javascript/mastodon/containers/mastodon.js b/app/javascript/mastodon/containers/mastodon.js index 2912540a0..542b68282 100644 --- a/app/javascript/mastodon/containers/mastodon.js +++ b/app/javascript/mastodon/containers/mastodon.js @@ -13,6 +13,7 @@ import { connectUserStream } from '../actions/streaming'; import { IntlProvider, addLocaleData } from 'react-intl'; import { getLocale } from '../locales'; import initialState from '../initial_state'; +import ErrorBoundary from '../components/error_boundary'; const { localeData, messages } = getLocale(); addLocaleData(localeData); @@ -75,7 +76,9 @@ export default class Mastodon extends React.PureComponent { return ( - + + + ); diff --git a/app/javascript/mastodon/features/ui/components/bundle.js b/app/javascript/mastodon/features/ui/components/bundle.js index e7d935251..a60ace35b 100644 --- a/app/javascript/mastodon/features/ui/components/bundle.js +++ b/app/javascript/mastodon/features/ui/components/bundle.js @@ -53,6 +53,11 @@ class Bundle extends React.PureComponent { const { fetchComponent, onFetch, onFetchSuccess, onFetchFail, renderDelay } = props || this.props; const cachedMod = Bundle.cache.get(fetchComponent); + if (fetchComponent === undefined) { + this.setState({ mod: null }); + return Promise.resolve(); + } + onFetch(); if (cachedMod) {