react-universal-component
Version:
A higher order component for loading components with promises
366 lines (287 loc) • 13.2 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.setHasBabelPlugin = exports.ReportChunks = exports.MODULE_IDS = exports.CHUNK_NAMES = undefined;
var _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; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _requireUniversalModule = require('./requireUniversalModule');
Object.defineProperty(exports, 'CHUNK_NAMES', {
enumerable: true,
get: function get() {
return _requireUniversalModule.CHUNK_NAMES;
}
});
Object.defineProperty(exports, 'MODULE_IDS', {
enumerable: true,
get: function get() {
return _requireUniversalModule.MODULE_IDS;
}
});
var _reportChunks = require('./report-chunks');
Object.defineProperty(exports, 'ReportChunks', {
enumerable: true,
get: function get() {
return _interopRequireDefault(_reportChunks).default;
}
});
exports.default = universal;
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _propTypes = require('prop-types');
var _propTypes2 = _interopRequireDefault(_propTypes);
var _hoistNonReactStatics = require('hoist-non-react-statics');
var _hoistNonReactStatics2 = _interopRequireDefault(_hoistNonReactStatics);
var _requireUniversalModule2 = _interopRequireDefault(_requireUniversalModule);
var _context = require('./context');
var _context2 = _interopRequireDefault(_context);
var _utils = require('./utils');
var _helpers = require('./helpers');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
var hasBabelPlugin = false;
var isHMR = function isHMR() {
return (
// $FlowIgnore
module.hot && (module.hot.data || module.hot.status() === 'apply')
);
};
var setHasBabelPlugin = exports.setHasBabelPlugin = function setHasBabelPlugin() {
hasBabelPlugin = true;
};
function universal(asyncModule) {
var _class, _temp;
var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var userRender = opts.render,
_opts$loading = opts.loading,
Loading = _opts$loading === undefined ? _utils.DefaultLoading : _opts$loading,
_opts$error = opts.error,
Err = _opts$error === undefined ? _utils.DefaultError : _opts$error,
_opts$minDelay = opts.minDelay,
minDelay = _opts$minDelay === undefined ? 0 : _opts$minDelay,
_opts$alwaysDelay = opts.alwaysDelay,
alwaysDelay = _opts$alwaysDelay === undefined ? false : _opts$alwaysDelay,
_opts$testBabelPlugin = opts.testBabelPlugin,
testBabelPlugin = _opts$testBabelPlugin === undefined ? false : _opts$testBabelPlugin,
_opts$loadingTransiti = opts.loadingTransition,
loadingTransition = _opts$loadingTransiti === undefined ? true : _opts$loadingTransiti,
options = _objectWithoutProperties(opts, ['render', 'loading', 'error', 'minDelay', 'alwaysDelay', 'testBabelPlugin', 'loadingTransition']);
var renderFunc = userRender || (0, _utils.createDefaultRender)(Loading, Err);
var isDynamic = hasBabelPlugin || testBabelPlugin;
options.isDynamic = isDynamic;
options.usesBabelPlugin = hasBabelPlugin;
options.modCache = {};
options.promCache = {};
return _temp = _class = function (_React$Component) {
_inherits(UniversalComponent, _React$Component);
_createClass(UniversalComponent, [{
key: 'requireAsyncInner',
value: function requireAsyncInner(requireAsync, props, state, isMount) {
var _this2 = this;
if (!state.mod && loadingTransition) {
this.update({ mod: null, props: props }); // display `loading` during componentWillReceiveProps
}
var time = new Date();
requireAsync(props).then(function (mod) {
var state = { mod: mod, props: props };
var timeLapsed = new Date() - time;
if (timeLapsed < minDelay) {
var extraDelay = minDelay - timeLapsed;
return setTimeout(function () {
return _this2.update(state, isMount);
}, extraDelay);
}
_this2.update(state, isMount);
}).catch(function (error) {
return _this2.update({ error: error, props: props });
});
}
}, {
key: 'handleBefore',
value: function handleBefore(isMount, isSync) {
var isServer = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
if (this.props.onBefore) {
var onBefore = this.props.onBefore;
var info = { isMount: isMount, isSync: isSync, isServer: isServer };
onBefore(info);
}
}
}, {
key: 'handleAfter',
value: function handleAfter(state, isMount, isSync, isServer) {
var mod = state.mod,
error = state.error;
if (mod && !error) {
(0, _hoistNonReactStatics2.default)(UniversalComponent, mod, {
preload: true,
preloadWeak: true
});
if (this.props.onAfter) {
var onAfter = this.props.onAfter;
var info = { isMount: isMount, isSync: isSync, isServer: isServer };
onAfter(info, mod);
}
} else if (error && this.props.onError) {
this.props.onError(error);
}
this.setState(state);
}
// $FlowFixMe
}, {
key: 'init',
value: function init(props) {
var _req = (0, _requireUniversalModule2.default)(asyncModule, options, props),
addModule = _req.addModule,
requireSync = _req.requireSync,
requireAsync = _req.requireAsync,
asyncOnly = _req.asyncOnly;
var mod = void 0;
try {
mod = requireSync(props);
} catch (error) {
return (0, _helpers.__update)(props, { error: error, props: props }, this._initialized);
}
this._asyncOnly = asyncOnly;
var chunkName = addModule(props); // record the module for SSR flushing :)
if (this.context && this.context.report) {
this.context.report(chunkName);
}
if (mod || _utils.isServer) {
this.handleBefore(true, true, _utils.isServer);
return (0, _helpers.__update)(props, { asyncOnly: asyncOnly, props: props, mod: mod }, this._initialized, true, true, _utils.isServer);
}
this.handleBefore(true, false);
this.requireAsyncInner(requireAsync, props, { props: props, asyncOnly: asyncOnly, mod: mod }, true);
return { mod: mod, asyncOnly: asyncOnly, props: props };
}
}], [{
key: 'preload',
value: function preload(props) {
props = props || {};
var _req2 = (0, _requireUniversalModule2.default)(asyncModule, options, props),
requireAsync = _req2.requireAsync,
requireSync = _req2.requireSync;
var mod = void 0;
try {
mod = requireSync(props);
} catch (error) {
return Promise.reject(error);
}
return Promise.resolve().then(function () {
if (mod) return mod;
return requireAsync(props);
}).then(function (mod) {
(0, _hoistNonReactStatics2.default)(UniversalComponent, mod, {
preload: true,
preloadWeak: true
});
return mod;
});
}
/* eslint-enable react/sort-comp */
/* eslint-disable react/sort-comp */
}, {
key: 'preloadWeak',
value: function preloadWeak(props) {
props = props || {};
var _req3 = (0, _requireUniversalModule2.default)(asyncModule, options, props),
requireSync = _req3.requireSync;
var mod = requireSync(props);
if (mod) {
(0, _hoistNonReactStatics2.default)(UniversalComponent, mod, {
preload: true,
preloadWeak: true
});
}
return mod;
}
}]);
function UniversalComponent(props, context) {
_classCallCheck(this, UniversalComponent);
var _this = _possibleConstructorReturn(this, (UniversalComponent.__proto__ || Object.getPrototypeOf(UniversalComponent)).call(this, props, context));
_this.update = function (state) {
var isMount = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
var isSync = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
var isServer = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
if (!_this._initialized) return;
if (!state.error) state.error = null;
_this.handleAfter(state, isMount, isSync, isServer);
};
_this.state = _this.init(_this.props);
// $FlowFixMe
_this.state.error = null;
return _this;
}
_createClass(UniversalComponent, [{
key: 'componentDidMount',
value: function componentDidMount() {
this._initialized = true;
}
}, {
key: 'componentDidUpdate',
value: function componentDidUpdate(prevProps) {
var _this3 = this;
if (isDynamic || this._asyncOnly) {
var _req4 = (0, _requireUniversalModule2.default)(asyncModule, options, this.props, prevProps),
requireSync = _req4.requireSync,
requireAsync = _req4.requireAsync,
shouldUpdate = _req4.shouldUpdate;
if (shouldUpdate(this.props, prevProps)) {
var mod = void 0;
try {
mod = requireSync(this.props);
} catch (error) {
return this.update({ error: error });
}
this.handleBefore(false, !!mod);
if (!mod) {
return this.requireAsyncInner(requireAsync, this.props, { mod: mod });
}
var state = { mod: mod };
if (alwaysDelay) {
if (loadingTransition) this.update({ mod: null }); // display `loading` during componentWillReceiveProps
setTimeout(function () {
return _this3.update(state, false, true);
}, minDelay);
return;
}
this.update(state, false, true);
}
}
}
}, {
key: 'componentWillUnmount',
value: function componentWillUnmount() {
this._initialized = false;
}
}, {
key: 'render',
value: function render() {
var _props = this.props,
isLoading = _props.isLoading,
userError = _props.error,
props = _objectWithoutProperties(_props, ['isLoading', 'error']);
var _state = this.state,
mod = _state.mod,
error = _state.error;
return renderFunc(props, mod, isLoading, userError || error);
}
}], [{
key: 'getDerivedStateFromProps',
value: function getDerivedStateFromProps(nextProps, currentState) {
var _req5 = (0, _requireUniversalModule2.default)(asyncModule, options, nextProps, currentState.props),
requireSync = _req5.requireSync,
shouldUpdate = _req5.shouldUpdate;
if (isHMR() && shouldUpdate(currentState.props, nextProps)) {
var mod = requireSync(nextProps);
return _extends({}, currentState, { mod: mod });
}
return null;
}
}]);
return UniversalComponent;
}(_react2.default.Component), _class.contextType = _context2.default, _temp;
}
;