Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
@skava/modules / ___dist / SSR / async-component / asyncComponent.js
Size: Mime:
"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

var _react = _interopRequireDefault(require("react"));

var _exotic = require("../../exotic");

var _propTypes = _interopRequireDefault(require("prop-types"));

var _jsxFileName = "SSR/async-component/asyncComponent.js";

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }

const validSSRModes = ['resolve', 'defer', 'boundary']; // eslint-disable-next-line

function asyncComponent(config) {
  const name = config.name,
        resolve = config.resolve,
        _config$autoResolveES = config.autoResolveES2015Default,
        autoResolveES2015Default = _config$autoResolveES === void 0 ? true : _config$autoResolveES,
        _config$serverMode = config.serverMode,
        serverMode = _config$serverMode === void 0 ? 'resolve' : _config$serverMode,
        LoadingComponent = config.LoadingComponent,
        ErrorComponent = config.ErrorComponent;

  if (validSSRModes.indexOf(serverMode) === -1) {
    throw new Error('Invalid serverMode provided to asyncComponent');
  }

  const env = ['node', 'browser'].indexOf(config.env) > -1 ? config.env : typeof window === 'undefined' ? 'node' : 'browser';
  const sharedState = {
    // A unique id we will assign to our async component which is especially
    // useful when rehydrating server side rendered async components.
    id: null,
    // This will be use to hold the resolved module allowing sharing across
    // instances.
    // NOTE: When using React Hot Loader this reference will become null.
    module: null,
    // If an error occurred during a resolution it will be stored here.
    error: null,
    // Allows us to share the resolver promise across instances.
    resolver: null // Takes the given module and if it has a ".default" the ".default" will
    // be returned. i.e. handy when you could be dealing with es6 imports.

  };

  const es6Resolve = x => autoResolveES2015Default && (0, _exotic.isObj)(x) && x.default ? x.default : x;

  const getResolver = () => {
    if (sharedState.resolver == null) {
      try {
        // Wrap whatever the user returns in Promise.resolve to ensure a Promise
        // is always returned.
        const resolver = resolve();
        sharedState.resolver = Promise.resolve(resolver);
      } catch (resolverException) {
        sharedState.resolver = Promise.reject(resolverException);
      }
    }

    return sharedState.resolver;
  };

  let AsyncComponent = class AsyncComponent extends _react.default.Component {
    constructor(props, context) {
      super(props, context); // We have to set the id in the constructor because a RHL seems
      // to recycle the module and therefore the id closure will be null.
      // We can't put it in componentWillMount as RHL hot swaps the new code
      // so the mount call will not happen (but the ctor does).

      if (this.context.asyncComponents && !sharedState.id) {
        sharedState.id = this.context.asyncComponents.getNextId();
      }
    } // @see react-async-bootstrapper


    asyncBootstrap() {
      const _context = this.context,
            asyncComponents = _context.asyncComponents,
            asyncComponentsAncestor = _context.asyncComponentsAncestor;
      const shouldRehydrate = asyncComponents.shouldRehydrate;

      const doResolve = () => this.resolveModule().then(module => module !== undefined);

      if (env === 'browser') {
        return shouldRehydrate(sharedState.id) ? doResolve() : false;
      } // node


      const isChildOfBoundary = asyncComponentsAncestor && asyncComponentsAncestor.isBoundary;
      return serverMode === 'defer' || isChildOfBoundary ? false : doResolve();
    }

    getChildContext() {
      if (!this.context.asyncComponents) {
        return undefined;
      }

      return {
        asyncComponentsAncestor: {
          isBoundary: serverMode === 'boundary'
        }
      };
    }

    componentWillMount() {
      this.setState({
        module: sharedState.module
      });

      if (sharedState.error) {
        this.registerErrorState(sharedState.error);
      }
    }

    componentDidMount() {
      if (!this.state.module) {
        this.resolveModule();
      }
    }

    resolveModule() {
      this.resolving = true;
      return getResolver().then(module => {
        if (this.unmounted) {
          return undefined;
        }

        if (this.context.asyncComponents) {
          this.context.asyncComponents.resolved(sharedState.id);
        }

        sharedState.module = module;

        if (env === 'browser') {
          this.setState({
            module
          });
        }

        this.resolving = false;
        return module;
      }).catch(error => {
        if (this.unmounted) {
          return undefined;
        }

        if (env === 'node' || env === 'browser' && !ErrorComponent) {
          // We will at least log the error so that user isn't completely
          // unaware of an error occurring.
          // eslint-disable-next-line no-console
          console.warn('Failed to resolve asyncComponent'); // eslint-disable-next-line no-console

          console.warn(error);
        }

        sharedState.error = error;
        this.registerErrorState(error);
        this.resolving = false;
        return undefined;
      });
    }

    componentWillUnmount() {
      this.unmounted = true;
    }

    registerErrorState(error) {
      if (env === 'browser') {
        setTimeout(() => {
          if (!this.unmounted) {
            this.setState({
              error
            });
          }
        }, 16);
      }
    }

    render() {
      const _state = this.state,
            module = _state.module,
            error = _state.error; // This is as workaround for React Hot Loader support.  When using
      // RHL the local component reference will be killed by any change
      // to the component, this will be our signal to know that we need to
      // re-resolve it.

      if (sharedState.module == null && !this.resolving && typeof window !== 'undefined') {
        this.resolveModule();
      }

      if (error) {
        return ErrorComponent ? _react.default.createElement(ErrorComponent, _extends({}, this.props, {
          error: error,
          __source: {
            fileName: _jsxFileName,
            lineNumber: 197
          },
          __self: this
        })) : null;
      }

      const Component = es6Resolve(module);
      return Component ? _react.default.createElement(Component, _extends({}, this.props, {
        __source: {
          fileName: _jsxFileName,
          lineNumber: 203
        },
        __self: this
      })) : LoadingComponent ? _react.default.createElement(LoadingComponent, _extends({}, this.props, {
        __source: {
          fileName: _jsxFileName,
          lineNumber: 204
        },
        __self: this
      })) : null;
    }

  };
  AsyncComponent.displayName = name || 'AsyncComponent';
  AsyncComponent.contextTypes = {
    asyncComponentsAncestor: _propTypes.default.shape({
      isBoundary: _propTypes.default.bool
    }),
    asyncComponents: _propTypes.default.shape({
      getNextId: _propTypes.default.func.isRequired,
      resolved: _propTypes.default.func.isRequired,
      shouldRehydrate: _propTypes.default.func.isRequired
    })
  };
  AsyncComponent.childContextTypes = {
    asyncComponentsAncestor: _propTypes.default.shape({
      isBoundary: _propTypes.default.bool
    })
  };
  return AsyncComponent;
}

var _default = asyncComponent;
exports.default = _default;