content: import React from 'react';
  import PropTypes from 'prop-types';
  
  const emptyComponent = () => null;
  const noop = () => { };
  
  class Bundle extends React.Component {
  
    static propTypes = {
      fetchComponent: PropTypes.func.isRequired,
      loading: PropTypes.func,
      error: PropTypes.func,
      children: PropTypes.func.isRequired,
      renderDelay: PropTypes.number,
      onFetch: PropTypes.func,
      onFetchSuccess: PropTypes.func,
      onFetchFail: PropTypes.func,
    }
  
    static defaultProps = {
      loading: emptyComponent,
      error: emptyComponent,
      renderDelay: 0,
      onFetch: noop,
      onFetchSuccess: noop,
      onFetchFail: noop,
    }
  
    static cache = {}
  
    state = {
      mod: undefined,
      forceRender: false,
    }
  
    componentWillMount() {
      this.load(this.props);
    }
  
    componentWillReceiveProps(nextProps) {
      if (nextProps.fetchComponent !== this.props.fetchComponent) {
        this.load(nextProps);
      }
    }
  
    componentWillUnmount () {
      if (this.timeout) {
        clearTimeout(this.timeout);
      }
    }
  
    load = (props) => {
      const { fetchComponent, onFetch, onFetchSuccess, onFetchFail, renderDelay } = props || this.props;
  
      onFetch();
  
      if (Bundle.cache[fetchComponent.name]) {
        const mod = Bundle.cache[fetchComponent.name];
  
        this.setState({ mod: mod.default });
        onFetchSuccess();
        return Promise.resolve();
      }
  
      this.setState({ mod: undefined });
  
      if (renderDelay !== 0) {
        this.timestamp = new Date();
        this.timeout = setTimeout(() => this.setState({ forceRender: true }), renderDelay);
      }
  
      return fetchComponent()
        .then((mod) => {
          Bundle.cache[fetchComponent.name] = mod;
          this.setState({ mod: mod.default });
          onFetchSuccess();
        })
        .catch((error) => {
          this.setState({ mod: null });
          onFetchFail(error);
        });
    }
  
    render() {
      const { loading: Loading, error: Error, children, renderDelay } = this.props;
      const { mod, forceRender } = this.state;
      const elapsed = this.timestamp ? (new Date() - this.timestamp) : renderDelay;
  
      if (mod === undefined) {
        return (elapsed >= renderDelay || forceRender) ? <Loading /> : null;
      }
  
      if (mod === null) {
        return <Error onRetry={this.load} />;
      }
  
      return children(mod);
    }
  
  }
  
  export default Bundle;
  