@tdb/web
Version:
Common condiguration for serving a web-site and testing web-based UI components.
458 lines (377 loc) • 14.6 kB
JavaScript
;
var _interopRequireWildcard = require("@babel/runtime-corejs2/helpers/interopRequireWildcard");
var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.render = render;
exports.renderError = renderError;
exports.default = exports.emitter = exports.ErrorComponent = exports.router = void 0;
var _objectSpread2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/objectSpread"));
var _regenerator = _interopRequireDefault(require("@babel/runtime-corejs2/regenerator"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/asyncToGenerator"));
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/slicedToArray"));
var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));
var _react = _interopRequireDefault(require("react"));
var _reactDom = _interopRequireDefault(require("react-dom"));
var _headManager = _interopRequireDefault(require("./head-manager"));
var _router2 = require("../lib/router");
var _EventEmitter = _interopRequireDefault(require("../lib/EventEmitter"));
var _utils = require("../lib/utils");
var _pageLoader = _interopRequireDefault(require("../lib/page-loader"));
var asset = _interopRequireWildcard(require("../lib/asset"));
var envConfig = _interopRequireWildcard(require("../lib/runtime-config"));
var _errorBoundary = _interopRequireDefault(require("./error-boundary"));
var _loadable = _interopRequireDefault(require("../lib/loadable"));
// Polyfill Promise globally
// This is needed because Webpack's dynamic loading(common chunks) code
// depends on Promise.
// So, we need to polyfill it.
// See: https://webpack.js.org/guides/code-splitting/#dynamic-imports
if (!window.Promise) {
window.Promise = _promise.default;
}
var _window = window,
_window$__NEXT_DATA__ = _window.__NEXT_DATA__,
props = _window$__NEXT_DATA__.props,
err = _window$__NEXT_DATA__.err,
page = _window$__NEXT_DATA__.page,
query = _window$__NEXT_DATA__.query,
buildId = _window$__NEXT_DATA__.buildId,
assetPrefix = _window$__NEXT_DATA__.assetPrefix,
runtimeConfig = _window$__NEXT_DATA__.runtimeConfig,
dynamicIds = _window$__NEXT_DATA__.dynamicIds;
var prefix = assetPrefix || ''; // With dynamic assetPrefix it's no longer possible to set assetPrefix at the build time
// So, this is how we do it in the client side at runtime
__webpack_public_path__ = "".concat(prefix, "/_next/"); //eslint-disable-line
// Initialize next/asset with the assetPrefix
asset.setAssetPrefix(prefix); // Initialize next/config with the environment configuration
envConfig.setConfig({
serverRuntimeConfig: {},
publicRuntimeConfig: runtimeConfig
});
var asPath = (0, _utils.getURL)();
var pageLoader = new _pageLoader.default(buildId, prefix);
window.__NEXT_LOADED_PAGES__.forEach(function (_ref) {
var _ref2 = (0, _slicedToArray2.default)(_ref, 2),
r = _ref2[0],
f = _ref2[1];
pageLoader.registerPage(r, f);
});
delete window.__NEXT_LOADED_PAGES__;
window.__NEXT_REGISTER_PAGE = pageLoader.registerPage.bind(pageLoader);
var headManager = new _headManager.default();
var appContainer = document.getElementById('__next');
var lastAppProps;
var webpackHMR;
var router;
exports.router = router;
var ErrorComponent;
exports.ErrorComponent = ErrorComponent;
var Component;
var App;
var emitter = new _EventEmitter.default();
exports.emitter = emitter;
var _default =
/*#__PURE__*/
(0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee() {
var _ref4,
passedWebpackHMR,
initialErr,
_args = arguments;
return _regenerator.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_ref4 = _args.length > 0 && _args[0] !== undefined ? _args[0] : {}, passedWebpackHMR = _ref4.webpackHMR;
// This makes sure this specific line is removed in production
if (process.env.NODE_ENV === 'development') {
webpackHMR = passedWebpackHMR;
}
_context.next = 4;
return pageLoader.loadPage('/_error');
case 4:
exports.ErrorComponent = ErrorComponent = _context.sent;
_context.next = 7;
return pageLoader.loadPage('/_app');
case 7:
App = _context.sent;
initialErr = err;
_context.prev = 9;
_context.next = 12;
return pageLoader.loadPage(page);
case 12:
Component = _context.sent;
if (!(typeof Component !== 'function')) {
_context.next = 15;
break;
}
throw new Error("The default export is not a React Component in page: \"".concat(page, "\""));
case 15:
_context.next = 20;
break;
case 17:
_context.prev = 17;
_context.t0 = _context["catch"](9);
// This catches errors like throwing in the top level of a module
initialErr = _context.t0;
case 20:
_context.next = 22;
return _loadable.default.preloadReady(dynamicIds || []);
case 22:
exports.router = router = (0, _router2.createRouter)(page, query, asPath, {
initialProps: props,
pageLoader: pageLoader,
App: App,
Component: Component,
ErrorComponent: ErrorComponent,
err: initialErr
});
router.subscribe(function (_ref5) {
var App = _ref5.App,
Component = _ref5.Component,
props = _ref5.props,
err = _ref5.err;
render({
App: App,
Component: Component,
props: props,
err: err,
emitter: emitter
});
});
render({
App: App,
Component: Component,
props: props,
err: initialErr,
emitter: emitter
});
return _context.abrupt("return", emitter);
case 26:
case "end":
return _context.stop();
}
}
}, _callee, this, [[9, 17]]);
}));
exports.default = _default;
function render(_x) {
return _render.apply(this, arguments);
} // This method handles all runtime and debug errors.
// 404 and 500 errors are special kind of errors
// and they are still handle via the main render method.
function _render() {
_render = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee2(props) {
return _regenerator.default.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
if (!props.err) {
_context2.next = 4;
break;
}
_context2.next = 3;
return renderError(props);
case 3:
return _context2.abrupt("return");
case 4:
_context2.prev = 4;
_context2.next = 7;
return doRender(props);
case 7:
_context2.next = 13;
break;
case 9:
_context2.prev = 9;
_context2.t0 = _context2["catch"](4);
_context2.next = 13;
return renderError((0, _objectSpread2.default)({}, props, {
err: _context2.t0
}));
case 13:
case "end":
return _context2.stop();
}
}
}, _callee2, this, [[4, 9]]);
}));
return _render.apply(this, arguments);
}
function renderError(_x2) {
return _renderError.apply(this, arguments);
}
function _renderError() {
_renderError = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee3(props) {
var App, err, initProps;
return _regenerator.default.wrap(function _callee3$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
App = props.App, err = props.err;
if (!(process.env.NODE_ENV !== 'production')) {
_context3.next = 3;
break;
}
throw webpackHMR.prepareError(err);
case 3:
// Make sure we log the error to the console, otherwise users can't track down issues.
console.error(err); // In production we do a normal render with the `ErrorComponent` as component.
// If we've gotten here upon initial render, we can use the props from the server.
// Otherwise, we need to call `getInitialProps` on `App` before mounting.
if (!props.props) {
_context3.next = 8;
break;
}
_context3.t0 = props.props;
_context3.next = 11;
break;
case 8:
_context3.next = 10;
return (0, _utils.loadGetInitialProps)(App, {
Component: ErrorComponent,
router: router,
ctx: {
err: err,
pathname: page,
query: query,
asPath: asPath
}
});
case 10:
_context3.t0 = _context3.sent;
case 11:
initProps = _context3.t0;
_context3.next = 14;
return doRender((0, _objectSpread2.default)({}, props, {
err: err,
Component: ErrorComponent,
props: initProps
}));
case 14:
case "end":
return _context3.stop();
}
}
}, _callee3, this);
}));
return _renderError.apply(this, arguments);
}
var isInitialRender = true;
function renderReactElement(reactEl, domEl) {
// The check for `.hydrate` is there to support React alternatives like preact
if (isInitialRender && typeof _reactDom.default.hydrate === 'function') {
_reactDom.default.hydrate(reactEl, domEl);
isInitialRender = false;
} else {
_reactDom.default.render(reactEl, domEl);
}
}
function doRender(_x3) {
return _doRender.apply(this, arguments);
}
function _doRender() {
_doRender = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee5(_ref6) {
var App, Component, props, err, _ref6$emitter, emitterProp, _router, pathname, _query, _asPath, appProps, onError;
return _regenerator.default.wrap(function _callee5$(_context5) {
while (1) {
switch (_context5.prev = _context5.next) {
case 0:
App = _ref6.App, Component = _ref6.Component, props = _ref6.props, err = _ref6.err, _ref6$emitter = _ref6.emitter, emitterProp = _ref6$emitter === void 0 ? emitter : _ref6$emitter;
if (!(!props && Component && Component !== ErrorComponent && lastAppProps.Component === ErrorComponent)) {
_context5.next = 6;
break;
}
_router = router, pathname = _router.pathname, _query = _router.query, _asPath = _router.asPath;
_context5.next = 5;
return (0, _utils.loadGetInitialProps)(App, {
Component: Component,
router: router,
ctx: {
err: err,
pathname: pathname,
query: _query,
asPath: _asPath
}
});
case 5:
props = _context5.sent;
case 6:
Component = Component || lastAppProps.Component;
props = props || lastAppProps.props;
appProps = (0, _objectSpread2.default)({
Component: Component,
err: err,
router: router,
headManager: headManager
}, props); // lastAppProps has to be set before ReactDom.render to account for ReactDom throwing an error.
lastAppProps = appProps;
emitterProp.emit('before-reactdom-render', {
Component: Component,
ErrorComponent: ErrorComponent,
appProps: appProps
}); // In development runtime errors are caught by react-error-overlay.
if (process.env.NODE_ENV === 'development') {
renderReactElement(_react.default.createElement(App, appProps), appContainer);
} else {
// In production we catch runtime errors using componentDidCatch which will trigger renderError.
onError =
/*#__PURE__*/
function () {
var _ref7 = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee4(error) {
return _regenerator.default.wrap(function _callee4$(_context4) {
while (1) {
switch (_context4.prev = _context4.next) {
case 0:
_context4.prev = 0;
_context4.next = 3;
return renderError({
App: App,
err: error
});
case 3:
_context4.next = 8;
break;
case 5:
_context4.prev = 5;
_context4.t0 = _context4["catch"](0);
console.error('Error while rendering error page: ', _context4.t0);
case 8:
case "end":
return _context4.stop();
}
}
}, _callee4, this, [[0, 5]]);
}));
return function onError(_x4) {
return _ref7.apply(this, arguments);
};
}();
renderReactElement(_react.default.createElement(_errorBoundary.default, {
onError: onError
}, _react.default.createElement(App, appProps)), appContainer);
}
emitterProp.emit('after-reactdom-render', {
Component: Component,
ErrorComponent: ErrorComponent,
appProps: appProps
});
case 13:
case "end":
return _context5.stop();
}
}
}, _callee5, this);
}));
return _doRender.apply(this, arguments);
}