vercel / next.js

The React Framework
https://nextjs.org
MIT License
125.09k stars 26.72k forks source link

Implement granular chunks #7696

Closed atcastle closed 5 years ago

atcastle commented 5 years ago

This PR implements the new Webpack SplitChunksPlugin configuration described in #7631 behind a new experimental flag called "granularChunks".

This also refactors the various SplitChunksPlugin configs out of the main config object, as it was getting unwieldy with the introduction of the large new config. However, without enabling the granularChunks flag, this change should have no effect at all on the build.

github-actions[bot] commented 5 years ago

Stats from current PR

Click to expand stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 13.4s | 13.3s | -118ms | | `node_modules` Size | 45.9 MB | 45.9 MB | ⚠️ +8.45 kB | | Total Bundle (main, webpack, commons) Size | 206 kB | 206 kB | -105 B | | Total Bundle (main, webpack, commons) gzip Size | 67.9 kB | 67.8 kB | -61 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `main` Size | 15.6 kB | 15.2 kB | -438 B | | Client `main` gzip Size | 5.39 kB | 5.35 kB | -47 B | | Client `commons` Size | 188 kB | 188 kB | ⚠️ +333 B | | Client `commons` gzip Size | 61.1 kB | 61.1 kB | -14 B | | Client `webpack` Size | 1.49 kB | 1.49 kB | ✓ | | Client `webpack` gzip Size | 770 B | 770 B | ✓ | | Base Rendered Size | 1.35 kB | 1.35 kB | ✓ | | Build Dir Size | 703 kB | 705 kB | ⚠️ +1.45 kB |
Click to expand serverless stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 14.6s | 14.5s | -62ms | | `node_modules` Size | 45.9 MB | 45.9 MB | ⚠️ +8.45 kB | | Total Bundle (main, webpack, commons) Size | 206 kB | 206 kB | -105 B | | Total Bundle (main, webpack, commons) gzip Size | 67.9 kB | 67.8 kB | -62 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | -1 B | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 300 B | -1 B | | Client `main` Size | 15.6 kB | 15.2 kB | -438 B | | Client `main` gzip Size | 5.39 kB | 5.35 kB | -47 B | | Client `commons` Size | 188 kB | 188 kB | ⚠️ +333 B | | Client `commons` gzip Size | 61.1 kB | 61.1 kB | -14 B | | Client `webpack` Size | 1.49 kB | 1.49 kB | ✓ | | Client `webpack` gzip Size | 770 B | 770 B | ✓ | | Serverless `pages/link` Size | 252 kB | 252 kB | ⚠️ +625 B | | Serverless `pages/link` gzip Size | 67.9 kB | 68 kB | ⚠️ +19 B | | Serverless `pages/index` Size | 244 kB | 245 kB | ⚠️ +625 B | | Serverless `pages/index` gzip Size | 65.8 kB | 65.8 kB | ⚠️ +8 B | | Serverless `pages/_error` Size | 244 kB | 244 kB | ⚠️ +625 B | | Serverless `pages/_error` gzip Size | 65.5 kB | 65.5 kB | ⚠️ +24 B | | Serverless `pages/routerDirect` Size | 245 kB | 246 kB | ⚠️ +625 B | | Serverless `pages/routerDirect` gzip Size | 65.7 kB | 65.7 kB | ⚠️ +16 B | | Serverless `pages/withRouter` Size | 245 kB | 245 kB | ⚠️ +625 B | | Serverless `pages/withRouter` gzip Size | 65.8 kB | 65.9 kB | ⚠️ +13 B | | Build Dir Size | 1.89 MB | 1.9 MB | ⚠️ +4.65 kB |
Diff for commons.js ```diff @@ -420,6 +420,36 @@ var objectKeys = Object.keys || function (obj) { /***/ }), +/***/ "4Vye": +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var _interopRequireDefault = __webpack_require__("KI45"); + +var _defineProperty = _interopRequireDefault(__webpack_require__("hfKm")); + +var __importStar = void 0 && (void 0).__importStar || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) { + if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; + } + result["default"] = mod; + return result; +}; + +(0, _defineProperty["default"])(exports, "__esModule", { + value: true +}); + +var React = __importStar(__webpack_require__("q1tI")); + +exports.RequestContext = React.createContext(null); + +/***/ }), + /***/ "4jyI": /***/ (function(module, exports, __webpack_require__) { @@ -3018,7 +3048,6 @@ function () { var initialProps = _ref.initialProps, pageLoader = _ref.pageLoader, App = _ref.App, - wrapApp = _ref.wrapApp, Component = _ref.Component, err = _ref.err, subscription = _ref.subscription; @@ -3096,7 +3125,6 @@ function () { this.asPath = as; this.sub = subscription; this.clc = null; - this._wrapApp = wrapApp; if (true) { // in order for `e.state` to work on the `onpopstate` event @@ -3583,7 +3611,6 @@ function () { App = this.components['/_app'].Component; _context2.next = 6; return utils_1.loadGetInitialProps(App, { - AppTree: this._wrapApp(App), Component: Component, router: this, ctx: ctx @@ -6655,6 +6682,7 @@ var _interopRequireDefault = __webpack_require__("KI45"); exports.__esModule = true; exports.useRouter = useRouter; +exports.useRequest = useRequest; exports.makePublicRouterInstance = makePublicRouterInstance; exports.createRouter = exports.withRouter = exports["default"] = void 0; @@ -6671,6 +6699,8 @@ exports.NextRouter = _router2.NextRouter; var _routerContext = __webpack_require__("9EOK"); +var _requestContext = __webpack_require__("4Vye"); + var _withRouter = _interopRequireDefault(__webpack_require__("0Bsm")); exports.withRouter = _withRouter["default"]; @@ -6756,6 +6786,10 @@ exports["default"] = _default; function useRouter() { return _react["default"].useContext(_routerContext.RouterContext); +} + +function useRequest() { + return _react["default"].useContext(_requestContext.RequestContext); } // INTERNAL APIS // ------------- // (do not use following exports inside the app) ```
Diff for main.js ```diff @@ -1,20 +1,5 @@ (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), - /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,28 +54,6 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; - -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); - - -/***/ }), - /***/ "BMP1": /***/ (function(module, exports, __webpack_require__) { @@ -569,7 +532,6 @@ function () { pageLoader: pageLoader, App: App, Component: Component, - wrapApp: wrapApp, err: initialErr, subscription: function subscription(_ref3, App) { var Component = _ref3.Component, @@ -670,7 +632,7 @@ function _renderError() { _renderError = (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee3(props) { - var App, err, appCtx, initProps; + var App, err, initProps; return _regenerator["default"].wrap(function _callee3$(_context3) { while (1) { switch (_context3.prev = _context3.next) { @@ -693,47 +655,42 @@ function _renderError() { case 6: exports.ErrorComponent = ErrorComponent = _context3.sent; - // 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. - appCtx = { - AppTree: wrapApp(App), - Component: ErrorComponent, - router: router, - ctx: { - err: err, - pathname: page, - query: query, - asPath: asPath - } - }; if (!props.props) { - _context3.next = 12; + _context3.next = 11; break; } _context3.t0 = props.props; - _context3.next = 15; + _context3.next = 14; break; - case 12: - _context3.next = 14; - return (0, _utils.loadGetInitialProps)(App, appCtx); + case 11: + _context3.next = 13; + return (0, _utils.loadGetInitialProps)(App, { + Component: ErrorComponent, + router: router, + ctx: { + err: err, + pathname: page, + query: query, + asPath: asPath + } + }); - case 14: + case 13: _context3.t0 = _context3.sent; - case 15: + case 14: initProps = _context3.t0; - _context3.next = 18; + _context3.next = 17; return doRender((0, _extends2["default"])({}, props, { err: err, Component: ErrorComponent, props: initProps })); - case 18: + case 17: case "end": return _context3.stop(); } @@ -778,17 +735,6 @@ function AppContainer(_ref4) { }, children))))); } -var wrapApp = function wrapApp(App) { - return function (props) { - var appProps = (0, _extends2["default"])({}, props, { - Component: Component, - err: err, - router: router - }); - return _react["default"].createElement(AppContainer, null, _react["default"].createElement(App, appProps)); - }; -}; - function doRender(_x4) { return _doRender.apply(this, arguments); } @@ -797,7 +743,7 @@ function _doRender() { _doRender = (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee4(_ref5) { - var App, Component, props, err, _router2, pathname, _query, _asPath, appCtx, appProps; + var App, Component, props, err, _router2, pathname, _query, _asPath, appProps; return _regenerator["default"].wrap(function _callee4$(_context4) { while (1) { @@ -807,37 +753,35 @@ function _doRender() { // this is for when ErrorComponent gets replaced by Component by HMR if (!(!props && Component && Component !== ErrorComponent && lastAppProps.Component === ErrorComponent)) { - _context4.next = 7; + _context4.next = 6; break; } _router2 = router, pathname = _router2.pathname, _query = _router2.query, _asPath = _router2.asPath; - appCtx = { + _context4.next = 5; + return (0, _utils.loadGetInitialProps)(App, { + Component: Component, router: router, - AppTree: wrapApp(App), - Component: ErrorComponent, ctx: { err: err, pathname: pathname, query: _query, asPath: _asPath } - }; - _context4.next = 6; - return (0, _utils.loadGetInitialProps)(App, appCtx); + }); - case 6: + case 5: props = _context4.sent; - case 7: + case 6: Component = Component || lastAppProps.Component; props = props || lastAppProps.props; - appProps = (0, _extends2["default"])({}, props, { + appProps = (0, _extends2["default"])({ Component: Component, err: err, - router: router // lastAppProps has to be set before ReactDom.render to account for ReactDom throwing an error. + router: router + }, props); // lastAppProps has to be set before ReactDom.render to account for ReactDom throwing an error. - }); lastAppProps = appProps; emitter.emit('before-reactdom-render', { Component: Component, @@ -852,7 +796,7 @@ function _doRender() { appProps: appProps }); - case 14: + case 13: case "end": return _context4.stop(); } @@ -894,15 +838,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -970,17 +905,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -1058,22 +982,6 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { @@ -1097,28 +1005,41 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ -// smaller version of https://gist.github.com/igrigorik/a02f2359f3bc50ca7a9c - +/* global document, window */ -function supportsPreload(list) { - if (!list || !list.supports) { - return false; - } +function supportsPreload(el) { try { - return list.supports('preload'); - } catch (e) { + return el.relList.supports('preload'); + } catch (_unused) { return false; } } -var hasPreload = supportsPreload(document.createElement('link').relList); +var hasPreload = supportsPreload(document.createElement('link')); + +function createPreloadLink(url) { + var link = document.createElement('link'); + link.rel = 'preload'; + link.crossOrigin = undefined; + link.href = url; + link.as = 'script'; + document.head.appendChild(link); +} // Retrieve a list of dependencies for a given route from the build manifest + + +function getDependencies(route, _m) { + if ((_m = window.__BUILD_MANIFEST) && (_m = _m[route])) { + return _m.map(function (url) { + return "/_next/" + url; + }); + } + + return []; +} var PageLoader = /*#__PURE__*/ @@ -1128,7 +1049,6 @@ function () { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set["default"](); this.pageRegisterEvents = (0, _mitt["default"])(); this.loadingRoutes = {}; this.promisedBuildId = _promise["default"].resolve(); @@ -1184,11 +1104,16 @@ function () { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!_this3.loadingRoutes[route]) { - _this3.loadScript(route); + getDependencies(route).forEach(function (d) { + if (!document.querySelector("script[src^=\"" + d + "\"]")) { + _this3.loadScript(d, route); + } + }); + + _this3.loadRoute(route); _this3.loadingRoutes[route] = true; } @@ -1220,14 +1145,14 @@ function () { }); } }, { - key: "loadScript", - value: function loadScript(route) { + key: "loadRoute", + value: function loadRoute(route) { var _this = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee() { - var scriptRoute, script, url; + var scriptRoute, url; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { @@ -1238,38 +1163,46 @@ function () { case 2: route = _this.normalizeRoute(route); scriptRoute = route === '/' ? '/index.js' : route + ".js"; - script = document.createElement('script'); - - if (false) {} - url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = undefined; - script.src = url; - - script.onerror = function () { - var error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; - _this.pageRegisterEvents.emit(route, { - error: error - }); - }; + _this.loadScript(url, route); - document.body.appendChild(script); - - case 11: + case 6: case "end": return _context.stop(); } } }, _callee); }))(); + } + }, { + key: "loadScript", + value: function loadScript(url, route) { + var _this5 = this; + + var script = document.createElement('script'); + + if (false) {} + + script.crossOrigin = undefined; + script.src = url; + + script.onerror = function () { + var error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + + _this5.pageRegisterEvents.emit(route, { + error: error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. }, { key: "registerPage", value: function registerPage(route, regFn) { - var _this5 = this; + var _this6 = this; var register = function register() { try { @@ -1277,21 +1210,21 @@ function () { error = _regFn.error, page = _regFn.page; - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error, page: page }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error, page: page }); } catch (error) { - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error }); } @@ -1303,73 +1236,84 @@ function () { } }, { key: "prefetch", - value: function prefetch(route) { + value: function prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee2() { - var scriptRoute, link; + var scriptRoute, url; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: + _context2.next = 2; + return _this2.promisedBuildId; + + case 2: route = _this2.normalizeRoute(route); scriptRoute = (route === '/' ? '/index' : route) + ".js"; if (false) {} - if (!(_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route))) { - _context2.next = 5; + url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. + + if (!(document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route))) { + _context2.next = 8; break; } return _context2.abrupt("return"); - case 5: - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE - // Don't prefetch if the user is on 2G / Don't prefetch if Save-Data is enabled - - + case 8: if (!('connection' in navigator)) { - _context2.next = 9; + _context2.next = 11; break; } if (!((navigator.connection.effectiveType || '').indexOf('2g') !== -1 || navigator.connection.saveData)) { - _context2.next = 9; + _context2.next = 11; break; } return _context2.abrupt("return"); - case 9: + case 11: + if (!isDependency) { + getDependencies(route).forEach(function (url) { + _this2.prefetch(url, true); + }); + } // Feature detection is used to see if preload is supported + // If not fall back to loading script tags before the page is loaded + // https://caniuse.com/#feat=link-rel-preload + + if (!hasPreload) { - _context2.next = 19; + _context2.next = 15; break; } - _context2.next = 12; - return _this2.promisedBuildId; + createPreloadLink(url); + return _context2.abrupt("return"); + + case 15: + if (!isDependency) { + _context2.next = 17; + break; + } - case 12: - link = document.createElement('link'); - link.rel = 'preload'; - link.crossOrigin = undefined; - link.href = _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; - link.as = 'script'; - document.head.appendChild(link); return _context2.abrupt("return"); - case 19: + case 17: if (!(document.readyState === 'complete')) { - _context2.next = 23; + _context2.next = 21; break; } return _context2.abrupt("return", _this2.loadPage(route)["catch"](function () {})); - case 23: + case 21: return _context2.abrupt("return", new _promise["default"](function (resolve) { window.addEventListener('load', function () { _this2.loadPage(route).then(function () { @@ -1380,7 +1324,7 @@ function () { }); })); - case 24: + case 22: case "end": return _context2.stop(); } ```
github-actions[bot] commented 5 years ago

Stats from current PR

Click to expand stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 12.2s | 12s | -136ms | | `node_modules` Size | 45.9 MB | 45.9 MB | ⚠️ +9.43 kB | | Total Bundle (main, webpack, commons) Size | 206 kB | 206 kB | -220 B | | Total Bundle (main, webpack, commons) gzip Size | 67.9 kB | 67.9 kB | ⚠️ +22 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `main` Size | 15.6 kB | 15.4 kB | -220 B | | Client `main` gzip Size | 5.39 kB | 5.42 kB | ⚠️ +22 B | | Client `commons` Size | 188 kB | 188 kB | ✓ | | Client `commons` gzip Size | 61.1 kB | 61.1 kB | ✓ | | Client `webpack` Size | 1.49 kB | 1.49 kB | ✓ | | Client `webpack` gzip Size | 770 B | 770 B | ✓ | | Base Rendered Size | 1.35 kB | 1.35 kB | ✓ | | Build Dir Size | 703 kB | 704 kB | ⚠️ +298 B |
Click to expand serverless stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 13.1s | 13.4s | ⚠️ +370ms | | `node_modules` Size | 45.9 MB | 45.9 MB | ⚠️ +9.43 kB | | Total Bundle (main, webpack, commons) Size | 206 kB | 206 kB | -220 B | | Total Bundle (main, webpack, commons) gzip Size | 67.9 kB | 67.9 kB | ⚠️ +22 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `main` Size | 15.6 kB | 15.4 kB | -220 B | | Client `main` gzip Size | 5.39 kB | 5.42 kB | ⚠️ +22 B | | Client `commons` Size | 188 kB | 188 kB | ✓ | | Client `commons` gzip Size | 61.1 kB | 61.1 kB | ✓ | | Client `webpack` Size | 1.49 kB | 1.49 kB | ✓ | | Client `webpack` gzip Size | 770 B | 770 B | ✓ | | Serverless `pages/link` Size | 252 kB | 252 kB | ✓ | | Serverless `pages/link` gzip Size | 67.9 kB | 67.9 kB | ⚠️ +3 B | | Serverless `pages/index` Size | 244 kB | 244 kB | ✓ | | Serverless `pages/index` gzip Size | 65.8 kB | 65.8 kB | ⚠️ +1 B | | Serverless `pages/_error` Size | 244 kB | 244 kB | ✓ | | Serverless `pages/_error` gzip Size | 65.5 kB | 65.5 kB | ⚠️ +1 B | | Serverless `pages/routerDirect` Size | 245 kB | 245 kB | ✓ | | Serverless `pages/routerDirect` gzip Size | 65.7 kB | 65.7 kB | ⚠️ +1 B | | Serverless `pages/withRouter` Size | 245 kB | 245 kB | ✓ | | Serverless `pages/withRouter` gzip Size | 65.8 kB | 65.8 kB | ⚠️ +1 B | | Build Dir Size | 1.89 MB | 1.89 MB | ⚠️ +298 B |
Diff for main.js ```diff @@ -1,20 +1,5 @@ (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), - /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,28 +54,6 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; - -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); - - -/***/ }), - /***/ "BMP1": /***/ (function(module, exports, __webpack_require__) { @@ -894,15 +857,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -970,17 +924,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -1058,22 +1001,6 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { @@ -1097,28 +1024,41 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ -// smaller version of https://gist.github.com/igrigorik/a02f2359f3bc50ca7a9c - +/* global document, window */ -function supportsPreload(list) { - if (!list || !list.supports) { - return false; - } +function supportsPreload(el) { try { - return list.supports('preload'); - } catch (e) { + return el.relList.supports('preload'); + } catch (_unused) { return false; } } -var hasPreload = supportsPreload(document.createElement('link').relList); +var hasPreload = supportsPreload(document.createElement('link')); + +function createPreloadLink(url) { + var link = document.createElement('link'); + link.rel = 'preload'; + link.crossOrigin = undefined; + link.href = url; + link.as = 'script'; + document.head.appendChild(link); +} // Retrieve a list of dependencies for a given route from the build manifest + + +function getDependencies(route, _m) { + if ((_m = window.__BUILD_MANIFEST) && (_m = _m[route])) { + return _m.map(function (url) { + return "/_next/" + url; + }); + } + + return []; +} var PageLoader = /*#__PURE__*/ @@ -1128,7 +1068,6 @@ function () { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set["default"](); this.pageRegisterEvents = (0, _mitt["default"])(); this.loadingRoutes = {}; this.promisedBuildId = _promise["default"].resolve(); @@ -1184,11 +1123,16 @@ function () { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!_this3.loadingRoutes[route]) { - _this3.loadScript(route); + getDependencies(route).forEach(function (d) { + if (!document.querySelector("script[src^=\"" + d + "\"]")) { + _this3.loadScript(d, route); + } + }); + + _this3.loadRoute(route); _this3.loadingRoutes[route] = true; } @@ -1220,14 +1164,14 @@ function () { }); } }, { - key: "loadScript", - value: function loadScript(route) { + key: "loadRoute", + value: function loadRoute(route) { var _this = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee() { - var scriptRoute, script, url; + var scriptRoute, url; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { @@ -1238,38 +1182,46 @@ function () { case 2: route = _this.normalizeRoute(route); scriptRoute = route === '/' ? '/index.js' : route + ".js"; - script = document.createElement('script'); - - if (false) {} - url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = undefined; - script.src = url; - - script.onerror = function () { - var error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; - _this.pageRegisterEvents.emit(route, { - error: error - }); - }; - - document.body.appendChild(script); + _this.loadScript(url, route); - case 11: + case 6: case "end": return _context.stop(); } } }, _callee); }))(); + } + }, { + key: "loadScript", + value: function loadScript(url, route) { + var _this5 = this; + + var script = document.createElement('script'); + + if (false) {} + + script.crossOrigin = undefined; + script.src = url; + + script.onerror = function () { + var error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + + _this5.pageRegisterEvents.emit(route, { + error: error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. }, { key: "registerPage", value: function registerPage(route, regFn) { - var _this5 = this; + var _this6 = this; var register = function register() { try { @@ -1277,21 +1229,21 @@ function () { error = _regFn.error, page = _regFn.page; - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error, page: page }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error, page: page }); } catch (error) { - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error }); } @@ -1303,73 +1255,84 @@ function () { } }, { key: "prefetch", - value: function prefetch(route) { + value: function prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee2() { - var scriptRoute, link; + var scriptRoute, url; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: + _context2.next = 2; + return _this2.promisedBuildId; + + case 2: route = _this2.normalizeRoute(route); scriptRoute = (route === '/' ? '/index' : route) + ".js"; if (false) {} - if (!(_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route))) { - _context2.next = 5; + url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. + + if (!(document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route))) { + _context2.next = 8; break; } return _context2.abrupt("return"); - case 5: - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE - // Don't prefetch if the user is on 2G / Don't prefetch if Save-Data is enabled - - + case 8: if (!('connection' in navigator)) { - _context2.next = 9; + _context2.next = 11; break; } if (!((navigator.connection.effectiveType || '').indexOf('2g') !== -1 || navigator.connection.saveData)) { - _context2.next = 9; + _context2.next = 11; break; } return _context2.abrupt("return"); - case 9: + case 11: + if (!isDependency) { + getDependencies(route).forEach(function (url) { + _this2.prefetch(url, true); + }); + } // Feature detection is used to see if preload is supported + // If not fall back to loading script tags before the page is loaded + // https://caniuse.com/#feat=link-rel-preload + + if (!hasPreload) { - _context2.next = 19; + _context2.next = 15; break; } - _context2.next = 12; - return _this2.promisedBuildId; + createPreloadLink(url); + return _context2.abrupt("return"); + + case 15: + if (!isDependency) { + _context2.next = 17; + break; + } - case 12: - link = document.createElement('link'); - link.rel = 'preload'; - link.crossOrigin = undefined; - link.href = _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; - link.as = 'script'; - document.head.appendChild(link); return _context2.abrupt("return"); - case 19: + case 17: if (!(document.readyState === 'complete')) { - _context2.next = 23; + _context2.next = 21; break; } return _context2.abrupt("return", _this2.loadPage(route)["catch"](function () {})); - case 23: + case 21: return _context2.abrupt("return", new _promise["default"](function (resolve) { window.addEventListener('load', function () { _this2.loadPage(route).then(function () { @@ -1380,7 +1343,7 @@ function () { }); })); - case 24: + case 22: case "end": return _context2.stop(); } ```
github-actions[bot] commented 5 years ago

Stats from current PR

Click to expand stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 13.4s | 13s | -468ms | | `node_modules` Size | 45.9 MB | 45.9 MB | ⚠️ +9.57 kB | | Total Bundle (main, webpack, commons) Size | 206 kB | 206 kB | -218 B | | Total Bundle (main, webpack, commons) gzip Size | 67.8 kB | 67.8 kB | ⚠️ +19 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `main` Size | 15.4 kB | 15.2 kB | -218 B | | Client `main` gzip Size | 5.35 kB | 5.37 kB | ⚠️ +19 B | | Client `commons` Size | 188 kB | 188 kB | ✓ | | Client `commons` gzip Size | 61.1 kB | 61.1 kB | ✓ | | Client `webpack` Size | 1.49 kB | 1.49 kB | ✓ | | Client `webpack` gzip Size | 770 B | 770 B | ✓ | | Base Rendered Size | 1.35 kB | 1.35 kB | ✓ | | Build Dir Size | 702 kB | 703 kB | ⚠️ +540 B |
Click to expand serverless stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 14.2s | 14.3s | ⚠️ +108ms | | `node_modules` Size | 45.9 MB | 45.9 MB | ⚠️ +9.57 kB | | Total Bundle (main, webpack, commons) Size | 206 kB | 206 kB | -218 B | | Total Bundle (main, webpack, commons) gzip Size | 67.8 kB | 67.8 kB | ⚠️ +19 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `main` Size | 15.4 kB | 15.2 kB | -218 B | | Client `main` gzip Size | 5.35 kB | 5.37 kB | ⚠️ +19 B | | Client `commons` Size | 188 kB | 188 kB | ✓ | | Client `commons` gzip Size | 61.1 kB | 61.1 kB | ✓ | | Client `webpack` Size | 1.49 kB | 1.49 kB | ✓ | | Client `webpack` gzip Size | 770 B | 770 B | ✓ | | Serverless `pages/link` Size | 252 kB | 252 kB | ✓ | | Serverless `pages/link` gzip Size | 67.9 kB | 67.9 kB | -4 B | | Serverless `pages/index` Size | 244 kB | 244 kB | ✓ | | Serverless `pages/index` gzip Size | 65.8 kB | 65.8 kB | -2 B | | Serverless `pages/_error` Size | 244 kB | 244 kB | ✓ | | Serverless `pages/_error` gzip Size | 65.5 kB | 65.5 kB | -2 B | | Serverless `pages/routerDirect` Size | 245 kB | 245 kB | ✓ | | Serverless `pages/routerDirect` gzip Size | 65.7 kB | 65.7 kB | -3 B | | Serverless `pages/withRouter` Size | 245 kB | 245 kB | ✓ | | Serverless `pages/withRouter` gzip Size | 65.9 kB | 65.8 kB | -3 B | | Build Dir Size | 1.89 MB | 1.89 MB | ⚠️ +540 B |
Diff for main.js ```diff @@ -1,20 +1,5 @@ (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), - /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,28 +54,6 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; - -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); - - -/***/ }), - /***/ "BMP1": /***/ (function(module, exports, __webpack_require__) { @@ -894,15 +857,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -970,17 +924,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -1058,22 +1001,6 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { @@ -1097,12 +1024,10 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ +/* global document, window */ function supportsPreload(el) { @@ -1122,6 +1047,17 @@ function preloadScript(url) { link.href = url; link.as = 'script'; document.head.appendChild(link); +} // Retrieve a list of dependencies for a given route from the build manifest + + +function getDependencies(route, _m) { + if ((_m = window.__BUILD_MANIFEST) && (_m = _m[route])) { + return _m.map(function (url) { + return "/_next/" + url; + }); + } + + return []; } var PageLoader = @@ -1132,7 +1068,6 @@ function () { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set["default"](); this.pageRegisterEvents = (0, _mitt["default"])(); this.loadingRoutes = {}; this.promisedBuildId = _promise["default"].resolve(); @@ -1188,11 +1123,16 @@ function () { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!_this3.loadingRoutes[route]) { - _this3.loadScript(route); + getDependencies(route).forEach(function (d) { + if (!document.querySelector("script[src^=\"" + d + "\"]")) { + _this3.loadScript(d, route); + } + }); + + _this3.loadRoute(route); _this3.loadingRoutes[route] = true; } @@ -1224,14 +1164,14 @@ function () { }); } }, { - key: "loadScript", - value: function loadScript(route) { + key: "loadRoute", + value: function loadRoute(route) { var _this = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee() { - var scriptRoute, script, url; + var scriptRoute, url; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { @@ -1242,38 +1182,46 @@ function () { case 2: route = _this.normalizeRoute(route); scriptRoute = route === '/' ? '/index.js' : route + ".js"; - script = document.createElement('script'); - - if (false) {} - url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = undefined; - script.src = url; - - script.onerror = function () { - var error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; - - _this.pageRegisterEvents.emit(route, { - error: error - }); - }; - document.body.appendChild(script); + _this.loadScript(url, route); - case 11: + case 6: case "end": return _context.stop(); } } }, _callee); }))(); + } + }, { + key: "loadScript", + value: function loadScript(url, route) { + var _this5 = this; + + var script = document.createElement('script'); + + if (false) {} + + script.crossOrigin = undefined; + script.src = url; + + script.onerror = function () { + var error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + + _this5.pageRegisterEvents.emit(route, { + error: error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. }, { key: "registerPage", value: function registerPage(route, regFn) { - var _this5 = this; + var _this6 = this; var register = function register() { try { @@ -1281,21 +1229,21 @@ function () { error = _regFn.error, page = _regFn.page; - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error, page: page }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error, page: page }); } catch (error) { - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error }); } @@ -1307,67 +1255,84 @@ function () { } }, { key: "prefetch", - value: function prefetch(route) { + value: function prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee2() { - var scriptRoute, cn; + var scriptRoute, url, cn; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: + _context2.next = 2; + return _this2.promisedBuildId; + + case 2: route = _this2.normalizeRoute(route); scriptRoute = (route === '/' ? '/index' : route) + ".js"; if (false) {} - if (!(_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route))) { - _context2.next = 5; + url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. + + if (!(document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route))) { + _context2.next = 8; break; } return _context2.abrupt("return"); - case 5: - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE - - + case 8: if (!(cn = navigator.connection)) { - _context2.next = 9; + _context2.next = 11; break; } if (!((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData)) { - _context2.next = 9; + _context2.next = 11; break; } return _context2.abrupt("return"); - case 9: + case 11: + if (!isDependency) { + getDependencies(route).forEach(function (url) { + _this2.prefetch(url, true); + }); + } // Feature detection is used to see if preload is supported + // If not fall back to loading script tags before the page is loaded + // https://caniuse.com/#feat=link-rel-preload + + if (!hasPreload) { - _context2.next = 14; + _context2.next = 15; break; } - _context2.next = 12; - return _this2.promisedBuildId; + preloadScript(url); + return _context2.abrupt("return"); + + case 15: + if (!isDependency) { + _context2.next = 17; + break; + } - case 12: - preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute); return _context2.abrupt("return"); - case 14: + case 17: if (!(document.readyState === 'complete')) { - _context2.next = 18; + _context2.next = 21; break; } return _context2.abrupt("return", _this2.loadPage(route)["catch"](function () {})); - case 18: + case 21: return _context2.abrupt("return", new _promise["default"](function (resolve) { window.addEventListener('load', function () { _this2.loadPage(route).then(function () { @@ -1378,7 +1343,7 @@ function () { }); })); - case 19: + case 22: case "end": return _context2.stop(); } ```
github-actions[bot] commented 5 years ago

Stats from current PR

Click to expand stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 13.7s | 13.5s | -138ms | | `node_modules` Size | 45.9 MB | 45.9 MB | ⚠️ +9.88 kB | | Total Bundle (main, webpack, commons) Size | 206 kB | 206 kB | -210 B | | Total Bundle (main, webpack, commons) gzip Size | 67.8 kB | 67.8 kB | ⚠️ +28 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `main` Size | 15.4 kB | 15.2 kB | -210 B | | Client `main` gzip Size | 5.35 kB | 5.38 kB | ⚠️ +28 B | | Client `commons` Size | 188 kB | 188 kB | ✓ | | Client `commons` gzip Size | 61.1 kB | 61.1 kB | ✓ | | Client `webpack` Size | 1.49 kB | 1.49 kB | ✓ | | Client `webpack` gzip Size | 770 B | 770 B | ✓ | | Base Rendered Size | 1.35 kB | 1.35 kB | ✓ | | Build Dir Size | 702 kB | 703 kB | ⚠️ +721 B |
Click to expand serverless stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 14.8s | 14.4s | -349ms | | `node_modules` Size | 45.9 MB | 45.9 MB | ⚠️ +9.88 kB | | Total Bundle (main, webpack, commons) Size | 206 kB | 206 kB | -210 B | | Total Bundle (main, webpack, commons) gzip Size | 67.8 kB | 67.8 kB | ⚠️ +29 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ⚠️ +1 B | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 300 B | 301 B | ⚠️ +1 B | | Client `main` Size | 15.4 kB | 15.2 kB | -210 B | | Client `main` gzip Size | 5.35 kB | 5.38 kB | ⚠️ +28 B | | Client `commons` Size | 188 kB | 188 kB | ✓ | | Client `commons` gzip Size | 61.1 kB | 61.1 kB | ✓ | | Client `webpack` Size | 1.49 kB | 1.49 kB | ✓ | | Client `webpack` gzip Size | 770 B | 770 B | ✓ | | Serverless `pages/link` Size | 252 kB | 252 kB | ✓ | | Serverless `pages/link` gzip Size | 67.9 kB | 67.9 kB | -1 B | | Serverless `pages/index` Size | 244 kB | 244 kB | ✓ | | Serverless `pages/index` gzip Size | 65.8 kB | 65.8 kB | ✓ | | Serverless `pages/_error` Size | 244 kB | 244 kB | ✓ | | Serverless `pages/_error` gzip Size | 65.5 kB | 65.5 kB | ✓ | | Serverless `pages/routerDirect` Size | 245 kB | 245 kB | ✓ | | Serverless `pages/routerDirect` gzip Size | 65.7 kB | 65.7 kB | ⚠️ +1 B | | Serverless `pages/withRouter` Size | 245 kB | 245 kB | ✓ | | Serverless `pages/withRouter` gzip Size | 65.8 kB | 65.8 kB | -1 B | | Build Dir Size | 1.89 MB | 1.89 MB | ⚠️ +721 B |
Diff for main.js ```diff @@ -1,20 +1,5 @@ (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), - /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,28 +54,6 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; - -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); - - -/***/ }), - /***/ "BMP1": /***/ (function(module, exports, __webpack_require__) { @@ -894,15 +857,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -970,17 +924,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -1058,22 +1001,6 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { @@ -1097,12 +1024,10 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ +/* global document, window */ function supportsPreload(el) { @@ -1122,6 +1047,17 @@ function preloadScript(url) { link.href = url; link.as = 'script'; document.head.appendChild(link); +} // Retrieve a list of dependencies for a given route from the build manifest + + +function getDependencies(route, _m) { + if ((_m = window.__BUILD_MANIFEST) && (_m = _m[route])) { + return _m.map(function (url) { + return "/_next/" + url; + }); + } + + return []; } var PageLoader = @@ -1132,7 +1068,6 @@ function () { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set["default"](); this.pageRegisterEvents = (0, _mitt["default"])(); this.loadingRoutes = {}; this.promisedBuildId = _promise["default"].resolve(); @@ -1188,11 +1123,16 @@ function () { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!_this3.loadingRoutes[route]) { - _this3.loadScript(route); + getDependencies(route).forEach(function (d) { + if (!document.querySelector("script[src^=\"" + d + "\"]")) { + _this3.loadScript(d, route, false); + } + }); + + _this3.loadRoute(route); _this3.loadingRoutes[route] = true; } @@ -1224,14 +1164,14 @@ function () { }); } }, { - key: "loadScript", - value: function loadScript(route) { + key: "loadRoute", + value: function loadRoute(route) { var _this = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee() { - var scriptRoute, script, url; + var scriptRoute, url; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { @@ -1242,38 +1182,46 @@ function () { case 2: route = _this.normalizeRoute(route); scriptRoute = route === '/' ? '/index.js' : route + ".js"; - script = document.createElement('script'); - - if (false) {} - url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = undefined; - script.src = url; - - script.onerror = function () { - var error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; - - _this.pageRegisterEvents.emit(route, { - error: error - }); - }; - document.body.appendChild(script); + _this.loadScript(url, route, true); - case 11: + case 6: case "end": return _context.stop(); } } }, _callee); }))(); + } + }, { + key: "loadScript", + value: function loadScript(url, route, isPage) { + var _this5 = this; + + var script = document.createElement('script'); + + if (false) {} + + script.crossOrigin = undefined; + script.src = url; + + script.onerror = function () { + var error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + + _this5.pageRegisterEvents.emit(route, { + error: error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. }, { key: "registerPage", value: function registerPage(route, regFn) { - var _this5 = this; + var _this6 = this; var register = function register() { try { @@ -1281,21 +1229,21 @@ function () { error = _regFn.error, page = _regFn.page; - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error, page: page }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error, page: page }); } catch (error) { - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error }); } @@ -1307,67 +1255,84 @@ function () { } }, { key: "prefetch", - value: function prefetch(route) { + value: function prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee2() { - var scriptRoute, cn; + var scriptRoute, url, cn; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: + _context2.next = 2; + return _this2.promisedBuildId; + + case 2: route = _this2.normalizeRoute(route); scriptRoute = (route === '/' ? '/index' : route) + ".js"; if (false) {} - if (!(_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route))) { - _context2.next = 5; + url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. + + if (!(document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route))) { + _context2.next = 8; break; } return _context2.abrupt("return"); - case 5: - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE - - + case 8: if (!(cn = navigator.connection)) { - _context2.next = 9; + _context2.next = 11; break; } if (!((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData)) { - _context2.next = 9; + _context2.next = 11; break; } return _context2.abrupt("return"); - case 9: + case 11: + if (!isDependency) { + getDependencies(route).forEach(function (url) { + _this2.prefetch(url, true); + }); + } // Feature detection is used to see if preload is supported + // If not fall back to loading script tags before the page is loaded + // https://caniuse.com/#feat=link-rel-preload + + if (!hasPreload) { - _context2.next = 14; + _context2.next = 15; break; } - _context2.next = 12; - return _this2.promisedBuildId; + preloadScript(url); + return _context2.abrupt("return"); + + case 15: + if (!isDependency) { + _context2.next = 17; + break; + } - case 12: - preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute); return _context2.abrupt("return"); - case 14: + case 17: if (!(document.readyState === 'complete')) { - _context2.next = 18; + _context2.next = 21; break; } return _context2.abrupt("return", _this2.loadPage(route)["catch"](function () {})); - case 18: + case 21: return _context2.abrupt("return", new _promise["default"](function (resolve) { window.addEventListener('load', function () { _this2.loadPage(route).then(function () { @@ -1378,7 +1343,7 @@ function () { }); })); - case 19: + case 22: case "end": return _context2.stop(); } ```
github-actions[bot] commented 5 years ago

Stats from current PR

Click to expand stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 12.9s | 12.7s | -185ms | | `node_modules` Size | 45.9 MB | 45.9 MB | ⚠️ +9.88 kB | | Total Bundle (main, webpack, commons) Size | 206 kB | 206 kB | -210 B | | Total Bundle (main, webpack, commons) gzip Size | 67.8 kB | 67.8 kB | ⚠️ +29 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ⚠️ +1 B | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 300 B | 301 B | ⚠️ +1 B | | Client `main` Size | 15.4 kB | 15.2 kB | -210 B | | Client `main` gzip Size | 5.35 kB | 5.38 kB | ⚠️ +28 B | | Client `commons` Size | 188 kB | 188 kB | ✓ | | Client `commons` gzip Size | 61.1 kB | 61.1 kB | ✓ | | Client `webpack` Size | 1.49 kB | 1.49 kB | ✓ | | Client `webpack` gzip Size | 770 B | 770 B | ✓ | | Base Rendered Size | 1.35 kB | 1.35 kB | ✓ | | Build Dir Size | 702 kB | 703 kB | ⚠️ +721 B |
Click to expand serverless stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 13.7s | 13.9s | ⚠️ +276ms | | `node_modules` Size | 45.9 MB | 45.9 MB | ⚠️ +9.88 kB | | Total Bundle (main, webpack, commons) Size | 206 kB | 206 kB | -210 B | | Total Bundle (main, webpack, commons) gzip Size | 67.8 kB | 67.8 kB | ⚠️ +28 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `main` Size | 15.4 kB | 15.2 kB | -210 B | | Client `main` gzip Size | 5.35 kB | 5.38 kB | ⚠️ +28 B | | Client `commons` Size | 188 kB | 188 kB | ✓ | | Client `commons` gzip Size | 61.1 kB | 61.1 kB | ✓ | | Client `webpack` Size | 1.49 kB | 1.49 kB | ✓ | | Client `webpack` gzip Size | 770 B | 770 B | ✓ | | Serverless `pages/link` Size | 252 kB | 252 kB | ✓ | | Serverless `pages/link` gzip Size | 67.9 kB | 67.9 kB | -1 B | | Serverless `pages/index` Size | 244 kB | 244 kB | ✓ | | Serverless `pages/index` gzip Size | 65.8 kB | 65.8 kB | -1 B | | Serverless `pages/_error` Size | 244 kB | 244 kB | ✓ | | Serverless `pages/_error` gzip Size | 65.5 kB | 65.5 kB | -2 B | | Serverless `pages/routerDirect` Size | 245 kB | 245 kB | ✓ | | Serverless `pages/routerDirect` gzip Size | 65.7 kB | 65.7 kB | -2 B | | Serverless `pages/withRouter` Size | 245 kB | 245 kB | ✓ | | Serverless `pages/withRouter` gzip Size | 65.9 kB | 65.9 kB | -1 B | | Build Dir Size | 1.89 MB | 1.89 MB | ⚠️ +721 B |
Diff for main.js ```diff @@ -1,20 +1,5 @@ (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), - /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,28 +54,6 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; - -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); - - -/***/ }), - /***/ "BMP1": /***/ (function(module, exports, __webpack_require__) { @@ -894,15 +857,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -970,17 +924,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -1058,22 +1001,6 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { @@ -1097,12 +1024,10 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ +/* global document, window */ function supportsPreload(el) { @@ -1122,6 +1047,17 @@ function preloadScript(url) { link.href = url; link.as = 'script'; document.head.appendChild(link); +} // Retrieve a list of dependencies for a given route from the build manifest + + +function getDependencies(route, _m) { + if ((_m = window.__BUILD_MANIFEST) && (_m = _m[route])) { + return _m.map(function (url) { + return "/_next/" + url; + }); + } + + return []; } var PageLoader = @@ -1132,7 +1068,6 @@ function () { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set["default"](); this.pageRegisterEvents = (0, _mitt["default"])(); this.loadingRoutes = {}; this.promisedBuildId = _promise["default"].resolve(); @@ -1188,11 +1123,16 @@ function () { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!_this3.loadingRoutes[route]) { - _this3.loadScript(route); + getDependencies(route).forEach(function (d) { + if (!document.querySelector("script[src^=\"" + d + "\"]")) { + _this3.loadScript(d, route, false); + } + }); + + _this3.loadRoute(route); _this3.loadingRoutes[route] = true; } @@ -1224,14 +1164,14 @@ function () { }); } }, { - key: "loadScript", - value: function loadScript(route) { + key: "loadRoute", + value: function loadRoute(route) { var _this = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee() { - var scriptRoute, script, url; + var scriptRoute, url; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { @@ -1242,38 +1182,46 @@ function () { case 2: route = _this.normalizeRoute(route); scriptRoute = route === '/' ? '/index.js' : route + ".js"; - script = document.createElement('script'); - - if (false) {} - url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = undefined; - script.src = url; - - script.onerror = function () { - var error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; - - _this.pageRegisterEvents.emit(route, { - error: error - }); - }; - document.body.appendChild(script); + _this.loadScript(url, route, true); - case 11: + case 6: case "end": return _context.stop(); } } }, _callee); }))(); + } + }, { + key: "loadScript", + value: function loadScript(url, route, isPage) { + var _this5 = this; + + var script = document.createElement('script'); + + if (false) {} + + script.crossOrigin = undefined; + script.src = url; + + script.onerror = function () { + var error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + + _this5.pageRegisterEvents.emit(route, { + error: error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. }, { key: "registerPage", value: function registerPage(route, regFn) { - var _this5 = this; + var _this6 = this; var register = function register() { try { @@ -1281,21 +1229,21 @@ function () { error = _regFn.error, page = _regFn.page; - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error, page: page }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error, page: page }); } catch (error) { - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error }); } @@ -1307,67 +1255,84 @@ function () { } }, { key: "prefetch", - value: function prefetch(route) { + value: function prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee2() { - var scriptRoute, cn; + var scriptRoute, url, cn; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: + _context2.next = 2; + return _this2.promisedBuildId; + + case 2: route = _this2.normalizeRoute(route); scriptRoute = (route === '/' ? '/index' : route) + ".js"; if (false) {} - if (!(_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route))) { - _context2.next = 5; + url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. + + if (!(document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route))) { + _context2.next = 8; break; } return _context2.abrupt("return"); - case 5: - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE - - + case 8: if (!(cn = navigator.connection)) { - _context2.next = 9; + _context2.next = 11; break; } if (!((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData)) { - _context2.next = 9; + _context2.next = 11; break; } return _context2.abrupt("return"); - case 9: + case 11: + if (!isDependency) { + getDependencies(route).forEach(function (url) { + _this2.prefetch(url, true); + }); + } // Feature detection is used to see if preload is supported + // If not fall back to loading script tags before the page is loaded + // https://caniuse.com/#feat=link-rel-preload + + if (!hasPreload) { - _context2.next = 14; + _context2.next = 15; break; } - _context2.next = 12; - return _this2.promisedBuildId; + preloadScript(url); + return _context2.abrupt("return"); + + case 15: + if (!isDependency) { + _context2.next = 17; + break; + } - case 12: - preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute); return _context2.abrupt("return"); - case 14: + case 17: if (!(document.readyState === 'complete')) { - _context2.next = 18; + _context2.next = 21; break; } return _context2.abrupt("return", _this2.loadPage(route)["catch"](function () {})); - case 18: + case 21: return _context2.abrupt("return", new _promise["default"](function (resolve) { window.addEventListener('load', function () { _this2.loadPage(route).then(function () { @@ -1378,7 +1343,7 @@ function () { }); })); - case 19: + case 22: case "end": return _context2.stop(); } ```
github-actions[bot] commented 5 years ago

Stats from current PR

Click to expand stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 13.5s | 13.2s | -304ms | | `node_modules` Size | 45.9 MB | 45.9 MB | ⚠️ +9.88 kB | | Total Bundle (main, webpack, commons) Size | 206 kB | 206 kB | -210 B | | Total Bundle (main, webpack, commons) gzip Size | 67.8 kB | 67.8 kB | ⚠️ +29 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ⚠️ +1 B | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 300 B | 301 B | ⚠️ +1 B | | Client `main` Size | 15.4 kB | 15.2 kB | -210 B | | Client `main` gzip Size | 5.35 kB | 5.38 kB | ⚠️ +28 B | | Client `commons` Size | 188 kB | 188 kB | ✓ | | Client `commons` gzip Size | 61.1 kB | 61.1 kB | ✓ | | Client `webpack` Size | 1.49 kB | 1.49 kB | ✓ | | Client `webpack` gzip Size | 770 B | 770 B | ✓ | | Base Rendered Size | 1.35 kB | 1.35 kB | ✓ | | Build Dir Size | 702 kB | 703 kB | ⚠️ +721 B |
Click to expand serverless stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 14.5s | 14.8s | ⚠️ +276ms | | `node_modules` Size | 45.9 MB | 45.9 MB | ⚠️ +9.88 kB | | Total Bundle (main, webpack, commons) Size | 206 kB | 206 kB | -210 B | | Total Bundle (main, webpack, commons) gzip Size | 67.8 kB | 67.8 kB | ⚠️ +28 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `main` Size | 15.4 kB | 15.2 kB | -210 B | | Client `main` gzip Size | 5.35 kB | 5.38 kB | ⚠️ +28 B | | Client `commons` Size | 188 kB | 188 kB | ✓ | | Client `commons` gzip Size | 61.1 kB | 61.1 kB | ✓ | | Client `webpack` Size | 1.49 kB | 1.49 kB | ✓ | | Client `webpack` gzip Size | 770 B | 770 B | ✓ | | Serverless `pages/link` Size | 252 kB | 252 kB | ✓ | | Serverless `pages/link` gzip Size | 67.9 kB | 67.9 kB | ⚠️ +2 B | | Serverless `pages/index` Size | 244 kB | 244 kB | ✓ | | Serverless `pages/index` gzip Size | 65.8 kB | 65.8 kB | ✓ | | Serverless `pages/_error` Size | 244 kB | 244 kB | ✓ | | Serverless `pages/_error` gzip Size | 65.5 kB | 65.5 kB | ✓ | | Serverless `pages/routerDirect` Size | 245 kB | 245 kB | ✓ | | Serverless `pages/routerDirect` gzip Size | 65.7 kB | 65.7 kB | ✓ | | Serverless `pages/withRouter` Size | 245 kB | 245 kB | ✓ | | Serverless `pages/withRouter` gzip Size | 65.8 kB | 65.8 kB | ✓ | | Build Dir Size | 1.89 MB | 1.89 MB | ⚠️ +721 B |
Diff for main.js ```diff @@ -1,20 +1,5 @@ (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), - /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,28 +54,6 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; - -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); - - -/***/ }), - /***/ "BMP1": /***/ (function(module, exports, __webpack_require__) { @@ -894,15 +857,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -970,17 +924,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -1058,22 +1001,6 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { @@ -1097,12 +1024,10 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ +/* global document, window */ function supportsPreload(el) { @@ -1122,6 +1047,17 @@ function preloadScript(url) { link.href = url; link.as = 'script'; document.head.appendChild(link); +} // Retrieve a list of dependencies for a given route from the build manifest + + +function getDependencies(route, _m) { + if ((_m = window.__BUILD_MANIFEST) && (_m = _m[route])) { + return _m.map(function (url) { + return "/_next/" + url; + }); + } + + return []; } var PageLoader = @@ -1132,7 +1068,6 @@ function () { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set["default"](); this.pageRegisterEvents = (0, _mitt["default"])(); this.loadingRoutes = {}; this.promisedBuildId = _promise["default"].resolve(); @@ -1188,11 +1123,16 @@ function () { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!_this3.loadingRoutes[route]) { - _this3.loadScript(route); + getDependencies(route).forEach(function (d) { + if (!document.querySelector("script[src^=\"" + d + "\"]")) { + _this3.loadScript(d, route, false); + } + }); + + _this3.loadRoute(route); _this3.loadingRoutes[route] = true; } @@ -1224,14 +1164,14 @@ function () { }); } }, { - key: "loadScript", - value: function loadScript(route) { + key: "loadRoute", + value: function loadRoute(route) { var _this = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee() { - var scriptRoute, script, url; + var scriptRoute, url; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { @@ -1242,38 +1182,46 @@ function () { case 2: route = _this.normalizeRoute(route); scriptRoute = route === '/' ? '/index.js' : route + ".js"; - script = document.createElement('script'); - - if (false) {} - url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = undefined; - script.src = url; - - script.onerror = function () { - var error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; - - _this.pageRegisterEvents.emit(route, { - error: error - }); - }; - document.body.appendChild(script); + _this.loadScript(url, route, true); - case 11: + case 6: case "end": return _context.stop(); } } }, _callee); }))(); + } + }, { + key: "loadScript", + value: function loadScript(url, route, isPage) { + var _this5 = this; + + var script = document.createElement('script'); + + if (false) {} + + script.crossOrigin = undefined; + script.src = url; + + script.onerror = function () { + var error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + + _this5.pageRegisterEvents.emit(route, { + error: error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. }, { key: "registerPage", value: function registerPage(route, regFn) { - var _this5 = this; + var _this6 = this; var register = function register() { try { @@ -1281,21 +1229,21 @@ function () { error = _regFn.error, page = _regFn.page; - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error, page: page }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error, page: page }); } catch (error) { - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error }); } @@ -1307,67 +1255,84 @@ function () { } }, { key: "prefetch", - value: function prefetch(route) { + value: function prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee2() { - var scriptRoute, cn; + var scriptRoute, url, cn; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: + _context2.next = 2; + return _this2.promisedBuildId; + + case 2: route = _this2.normalizeRoute(route); scriptRoute = (route === '/' ? '/index' : route) + ".js"; if (false) {} - if (!(_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route))) { - _context2.next = 5; + url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. + + if (!(document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route))) { + _context2.next = 8; break; } return _context2.abrupt("return"); - case 5: - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE - - + case 8: if (!(cn = navigator.connection)) { - _context2.next = 9; + _context2.next = 11; break; } if (!((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData)) { - _context2.next = 9; + _context2.next = 11; break; } return _context2.abrupt("return"); - case 9: + case 11: + if (!isDependency) { + getDependencies(route).forEach(function (url) { + _this2.prefetch(url, true); + }); + } // Feature detection is used to see if preload is supported + // If not fall back to loading script tags before the page is loaded + // https://caniuse.com/#feat=link-rel-preload + + if (!hasPreload) { - _context2.next = 14; + _context2.next = 15; break; } - _context2.next = 12; - return _this2.promisedBuildId; + preloadScript(url); + return _context2.abrupt("return"); + + case 15: + if (!isDependency) { + _context2.next = 17; + break; + } - case 12: - preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute); return _context2.abrupt("return"); - case 14: + case 17: if (!(document.readyState === 'complete')) { - _context2.next = 18; + _context2.next = 21; break; } return _context2.abrupt("return", _this2.loadPage(route)["catch"](function () {})); - case 18: + case 21: return _context2.abrupt("return", new _promise["default"](function (resolve) { window.addEventListener('load', function () { _this2.loadPage(route).then(function () { @@ -1378,7 +1343,7 @@ function () { }); })); - case 19: + case 22: case "end": return _context2.stop(); } ```
github-actions[bot] commented 5 years ago

Stats from current PR

Click to expand stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 13.3s | 12.8s | -488ms | | `node_modules` Size | 45.9 MB | 45.9 MB | ⚠️ +9.88 kB | | Total Bundle (main, webpack, commons) Size | 206 kB | 206 kB | -210 B | | Total Bundle (main, webpack, commons) gzip Size | 67.8 kB | 67.8 kB | ⚠️ +27 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | -1 B | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 300 B | -1 B | | Client `main` Size | 15.4 kB | 15.2 kB | -210 B | | Client `main` gzip Size | 5.35 kB | 5.38 kB | ⚠️ +28 B | | Client `commons` Size | 188 kB | 188 kB | ✓ | | Client `commons` gzip Size | 61.1 kB | 61.1 kB | ✓ | | Client `webpack` Size | 1.49 kB | 1.49 kB | ✓ | | Client `webpack` gzip Size | 770 B | 770 B | ✓ | | Base Rendered Size | 1.35 kB | 1.35 kB | ✓ | | Build Dir Size | 702 kB | 703 kB | ⚠️ +721 B |
Click to expand serverless stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 14.2s | 13.2s | -957ms | | `node_modules` Size | 45.9 MB | 45.9 MB | ⚠️ +9.88 kB | | Total Bundle (main, webpack, commons) Size | 206 kB | 206 kB | -210 B | | Total Bundle (main, webpack, commons) gzip Size | 67.8 kB | 67.8 kB | ⚠️ +28 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `main` Size | 15.4 kB | 15.2 kB | -210 B | | Client `main` gzip Size | 5.35 kB | 5.38 kB | ⚠️ +28 B | | Client `commons` Size | 188 kB | 188 kB | ✓ | | Client `commons` gzip Size | 61.1 kB | 61.1 kB | ✓ | | Client `webpack` Size | 1.49 kB | 1.49 kB | ✓ | | Client `webpack` gzip Size | 770 B | 770 B | ✓ | | Serverless `pages/link` Size | 252 kB | 252 kB | ✓ | | Serverless `pages/link` gzip Size | 67.9 kB | 67.9 kB | -1 B | | Serverless `pages/index` Size | 244 kB | 244 kB | ✓ | | Serverless `pages/index` gzip Size | 65.8 kB | 65.8 kB | -2 B | | Serverless `pages/_error` Size | 244 kB | 244 kB | ✓ | | Serverless `pages/_error` gzip Size | 65.5 kB | 65.5 kB | -1 B | | Serverless `pages/routerDirect` Size | 245 kB | 245 kB | ✓ | | Serverless `pages/routerDirect` gzip Size | 65.7 kB | 65.7 kB | -1 B | | Serverless `pages/withRouter` Size | 245 kB | 245 kB | ✓ | | Serverless `pages/withRouter` gzip Size | 65.9 kB | 65.8 kB | -1 B | | Build Dir Size | 1.89 MB | 1.89 MB | ⚠️ +721 B |
Diff for main.js ```diff @@ -1,20 +1,5 @@ (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), - /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,28 +54,6 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; - -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); - - -/***/ }), - /***/ "BMP1": /***/ (function(module, exports, __webpack_require__) { @@ -894,15 +857,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -970,17 +924,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -1058,22 +1001,6 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { @@ -1097,12 +1024,10 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ +/* global document, window */ function supportsPreload(el) { @@ -1122,6 +1047,17 @@ function preloadScript(url) { link.href = url; link.as = 'script'; document.head.appendChild(link); +} // Retrieve a list of dependencies for a given route from the build manifest + + +function getDependencies(route, _m) { + if ((_m = window.__BUILD_MANIFEST) && (_m = _m[route])) { + return _m.map(function (url) { + return "/_next/" + url; + }); + } + + return []; } var PageLoader = @@ -1132,7 +1068,6 @@ function () { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set["default"](); this.pageRegisterEvents = (0, _mitt["default"])(); this.loadingRoutes = {}; this.promisedBuildId = _promise["default"].resolve(); @@ -1188,11 +1123,16 @@ function () { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!_this3.loadingRoutes[route]) { - _this3.loadScript(route); + getDependencies(route).forEach(function (d) { + if (!document.querySelector("script[src^=\"" + d + "\"]")) { + _this3.loadScript(d, route, false); + } + }); + + _this3.loadRoute(route); _this3.loadingRoutes[route] = true; } @@ -1224,14 +1164,14 @@ function () { }); } }, { - key: "loadScript", - value: function loadScript(route) { + key: "loadRoute", + value: function loadRoute(route) { var _this = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee() { - var scriptRoute, script, url; + var scriptRoute, url; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { @@ -1242,38 +1182,46 @@ function () { case 2: route = _this.normalizeRoute(route); scriptRoute = route === '/' ? '/index.js' : route + ".js"; - script = document.createElement('script'); - - if (false) {} - url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = undefined; - script.src = url; - - script.onerror = function () { - var error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; - - _this.pageRegisterEvents.emit(route, { - error: error - }); - }; - document.body.appendChild(script); + _this.loadScript(url, route, true); - case 11: + case 6: case "end": return _context.stop(); } } }, _callee); }))(); + } + }, { + key: "loadScript", + value: function loadScript(url, route, isPage) { + var _this5 = this; + + var script = document.createElement('script'); + + if (false) {} + + script.crossOrigin = undefined; + script.src = url; + + script.onerror = function () { + var error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + + _this5.pageRegisterEvents.emit(route, { + error: error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. }, { key: "registerPage", value: function registerPage(route, regFn) { - var _this5 = this; + var _this6 = this; var register = function register() { try { @@ -1281,21 +1229,21 @@ function () { error = _regFn.error, page = _regFn.page; - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error, page: page }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error, page: page }); } catch (error) { - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error }); } @@ -1307,67 +1255,84 @@ function () { } }, { key: "prefetch", - value: function prefetch(route) { + value: function prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee2() { - var scriptRoute, cn; + var scriptRoute, url, cn; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: + _context2.next = 2; + return _this2.promisedBuildId; + + case 2: route = _this2.normalizeRoute(route); scriptRoute = (route === '/' ? '/index' : route) + ".js"; if (false) {} - if (!(_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route))) { - _context2.next = 5; + url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. + + if (!(document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route))) { + _context2.next = 8; break; } return _context2.abrupt("return"); - case 5: - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE - - + case 8: if (!(cn = navigator.connection)) { - _context2.next = 9; + _context2.next = 11; break; } if (!((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData)) { - _context2.next = 9; + _context2.next = 11; break; } return _context2.abrupt("return"); - case 9: + case 11: + if (!isDependency) { + getDependencies(route).forEach(function (url) { + _this2.prefetch(url, true); + }); + } // Feature detection is used to see if preload is supported + // If not fall back to loading script tags before the page is loaded + // https://caniuse.com/#feat=link-rel-preload + + if (!hasPreload) { - _context2.next = 14; + _context2.next = 15; break; } - _context2.next = 12; - return _this2.promisedBuildId; + preloadScript(url); + return _context2.abrupt("return"); + + case 15: + if (!isDependency) { + _context2.next = 17; + break; + } - case 12: - preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute); return _context2.abrupt("return"); - case 14: + case 17: if (!(document.readyState === 'complete')) { - _context2.next = 18; + _context2.next = 21; break; } return _context2.abrupt("return", _this2.loadPage(route)["catch"](function () {})); - case 18: + case 21: return _context2.abrupt("return", new _promise["default"](function (resolve) { window.addEventListener('load', function () { _this2.loadPage(route).then(function () { @@ -1378,7 +1343,7 @@ function () { }); })); - case 19: + case 22: case "end": return _context2.stop(); } ```
ijjk commented 5 years ago

Stats from current PR

Click to expand stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 13.9s | 13.3s | -548ms | | `node_modules` Size | 43.6 MB | 43.6 MB | ⚠️ +9.88 kB | | Total Bundle (main, webpack, commons) Size | 206 kB | 206 kB | -210 B | | Total Bundle (main, webpack, commons) gzip Size | 67.8 kB | 67.8 kB | ⚠️ +28 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `main` Size | 15.4 kB | 15.2 kB | -210 B | | Client `main` gzip Size | 5.35 kB | 5.38 kB | ⚠️ +28 B | | Client `commons` Size | 188 kB | 188 kB | ✓ | | Client `commons` gzip Size | 61.1 kB | 61.1 kB | ✓ | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Base Rendered Size | 1.35 kB | 1.35 kB | ✓ | | Build Dir Size | 702 kB | 703 kB | ⚠️ +721 B |
Click to expand serverless stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 14.7s | 14.6s | -145ms | | `node_modules` Size | 43.6 MB | 43.6 MB | ⚠️ +9.88 kB | | Total Bundle (main, webpack, commons) Size | 206 kB | 206 kB | -210 B | | Total Bundle (main, webpack, commons) gzip Size | 67.8 kB | 67.8 kB | ⚠️ +28 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `main` Size | 15.4 kB | 15.2 kB | -210 B | | Client `main` gzip Size | 5.35 kB | 5.38 kB | ⚠️ +28 B | | Client `commons` Size | 188 kB | 188 kB | ✓ | | Client `commons` gzip Size | 61.1 kB | 61.1 kB | ✓ | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Serverless `pages/link` Size | 251 kB | 251 kB | ✓ | | Serverless `pages/link` gzip Size | 67.8 kB | 67.8 kB | -1 B | | Serverless `pages/index` Size | 244 kB | 244 kB | ✓ | | Serverless `pages/index` gzip Size | 65.6 kB | 65.6 kB | -1 B | | Serverless `pages/_error` Size | 243 kB | 243 kB | ✓ | | Serverless `pages/_error` gzip Size | 65.4 kB | 65.4 kB | -2 B | | Serverless `pages/routerDirect` Size | 244 kB | 244 kB | ✓ | | Serverless `pages/routerDirect` gzip Size | 65.6 kB | 65.6 kB | -1 B | | Serverless `pages/withRouter` Size | 244 kB | 244 kB | ✓ | | Serverless `pages/withRouter` gzip Size | 65.7 kB | 65.7 kB | -1 B | | Build Dir Size | 1.89 MB | 1.89 MB | ⚠️ +721 B |
Diff for main.js ```diff @@ -1,20 +1,5 @@ (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), - /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,28 +54,6 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; - -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); - - -/***/ }), - /***/ "BMP1": /***/ (function(module, exports, __webpack_require__) { @@ -894,15 +857,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -970,17 +924,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -1058,22 +1001,6 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { @@ -1097,12 +1024,10 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ +/* global document, window */ function supportsPreload(el) { @@ -1122,6 +1047,17 @@ function preloadScript(url) { link.href = url; link.as = 'script'; document.head.appendChild(link); +} // Retrieve a list of dependencies for a given route from the build manifest + + +function getDependencies(route, _m) { + if ((_m = window.__BUILD_MANIFEST) && (_m = _m[route])) { + return _m.map(function (url) { + return "/_next/" + url; + }); + } + + return []; } var PageLoader = @@ -1132,7 +1068,6 @@ function () { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set["default"](); this.pageRegisterEvents = (0, _mitt["default"])(); this.loadingRoutes = {}; this.promisedBuildId = _promise["default"].resolve(); @@ -1188,11 +1123,16 @@ function () { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!_this3.loadingRoutes[route]) { - _this3.loadScript(route); + getDependencies(route).forEach(function (d) { + if (!document.querySelector("script[src^=\"" + d + "\"]")) { + _this3.loadScript(d, route, false); + } + }); + + _this3.loadRoute(route); _this3.loadingRoutes[route] = true; } @@ -1224,14 +1164,14 @@ function () { }); } }, { - key: "loadScript", - value: function loadScript(route) { + key: "loadRoute", + value: function loadRoute(route) { var _this = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee() { - var scriptRoute, script, url; + var scriptRoute, url; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { @@ -1242,38 +1182,46 @@ function () { case 2: route = _this.normalizeRoute(route); scriptRoute = route === '/' ? '/index.js' : route + ".js"; - script = document.createElement('script'); - - if (false) {} - url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = undefined; - script.src = url; - - script.onerror = function () { - var error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; - - _this.pageRegisterEvents.emit(route, { - error: error - }); - }; - document.body.appendChild(script); + _this.loadScript(url, route, true); - case 11: + case 6: case "end": return _context.stop(); } } }, _callee); }))(); + } + }, { + key: "loadScript", + value: function loadScript(url, route, isPage) { + var _this5 = this; + + var script = document.createElement('script'); + + if (false) {} + + script.crossOrigin = undefined; + script.src = url; + + script.onerror = function () { + var error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + + _this5.pageRegisterEvents.emit(route, { + error: error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. }, { key: "registerPage", value: function registerPage(route, regFn) { - var _this5 = this; + var _this6 = this; var register = function register() { try { @@ -1281,21 +1229,21 @@ function () { error = _regFn.error, page = _regFn.page; - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error, page: page }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error, page: page }); } catch (error) { - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error }); } @@ -1307,67 +1255,84 @@ function () { } }, { key: "prefetch", - value: function prefetch(route) { + value: function prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee2() { - var scriptRoute, cn; + var scriptRoute, url, cn; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: + _context2.next = 2; + return _this2.promisedBuildId; + + case 2: route = _this2.normalizeRoute(route); scriptRoute = (route === '/' ? '/index' : route) + ".js"; if (false) {} - if (!(_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route))) { - _context2.next = 5; + url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. + + if (!(document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route))) { + _context2.next = 8; break; } return _context2.abrupt("return"); - case 5: - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE - - + case 8: if (!(cn = navigator.connection)) { - _context2.next = 9; + _context2.next = 11; break; } if (!((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData)) { - _context2.next = 9; + _context2.next = 11; break; } return _context2.abrupt("return"); - case 9: + case 11: + if (!isDependency) { + getDependencies(route).forEach(function (url) { + _this2.prefetch(url, true); + }); + } // Feature detection is used to see if preload is supported + // If not fall back to loading script tags before the page is loaded + // https://caniuse.com/#feat=link-rel-preload + + if (!hasPreload) { - _context2.next = 14; + _context2.next = 15; break; } - _context2.next = 12; - return _this2.promisedBuildId; + preloadScript(url); + return _context2.abrupt("return"); + + case 15: + if (!isDependency) { + _context2.next = 17; + break; + } - case 12: - preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute); return _context2.abrupt("return"); - case 14: + case 17: if (!(document.readyState === 'complete')) { - _context2.next = 18; + _context2.next = 21; break; } return _context2.abrupt("return", _this2.loadPage(route)["catch"](function () {})); - case 18: + case 21: return _context2.abrupt("return", new _promise["default"](function (resolve) { window.addEventListener('load', function () { _this2.loadPage(route).then(function () { @@ -1378,7 +1343,7 @@ function () { }); })); - case 19: + case 22: case "end": return _context2.stop(); } ```
ijjk commented 5 years ago

Stats from current PR

Click to expand stats ⚠️ Total Bundle Size Increase ⚠️ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 13.4s | 13.2s | -233ms | | `node_modules` Size | 43.6 MB | 43.6 MB | ⚠️ +6.84 kB | | Total Bundle (main, webpack, commons) Size | 206 kB | 206 kB | ⚠️ +132 B | | Total Bundle (main, webpack, commons) gzip Size | 67.8 kB | 67.9 kB | ⚠️ +103 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `main` Size | 15.4 kB | 15.5 kB | ⚠️ +132 B | | Client `main` gzip Size | 5.35 kB | 5.46 kB | ⚠️ +103 B | | Client `commons` Size | 188 kB | 188 kB | ✓ | | Client `commons` gzip Size | 61.1 kB | 61.1 kB | ✓ | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Base Rendered Size | 1.35 kB | 1.35 kB | ✓ | | Build Dir Size | 702 kB | 704 kB | ⚠️ +1.9 kB |
Click to expand serverless stats ⚠️ Total Bundle Size Increase ⚠️ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 14.4s | 14.3s | -163ms | | `node_modules` Size | 43.6 MB | 43.6 MB | ⚠️ +6.84 kB | | Total Bundle (main, webpack, commons) Size | 206 kB | 206 kB | ⚠️ +132 B | | Total Bundle (main, webpack, commons) gzip Size | 67.8 kB | 67.9 kB | ⚠️ +104 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ⚠️ +1 B | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 300 B | 301 B | ⚠️ +1 B | | Client `main` Size | 15.4 kB | 15.5 kB | ⚠️ +132 B | | Client `main` gzip Size | 5.35 kB | 5.46 kB | ⚠️ +103 B | | Client `commons` Size | 188 kB | 188 kB | ✓ | | Client `commons` gzip Size | 61.1 kB | 61.1 kB | ✓ | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Serverless `pages/link` Size | 251 kB | 251 kB | ✓ | | Serverless `pages/link` gzip Size | 67.8 kB | 67.8 kB | ⚠️ +1 B | | Serverless `pages/index` Size | 244 kB | 244 kB | ✓ | | Serverless `pages/index` gzip Size | 65.6 kB | 65.6 kB | ⚠️ +1 B | | Serverless `pages/_error` Size | 243 kB | 243 kB | ✓ | | Serverless `pages/_error` gzip Size | 65.4 kB | 65.4 kB | ✓ | | Serverless `pages/routerDirect` Size | 244 kB | 244 kB | ✓ | | Serverless `pages/routerDirect` gzip Size | 65.6 kB | 65.6 kB | ⚠️ +1 B | | Serverless `pages/withRouter` Size | 244 kB | 244 kB | ✓ | | Serverless `pages/withRouter` gzip Size | 65.7 kB | 65.7 kB | ⚠️ +1 B | | Build Dir Size | 1.89 MB | 1.89 MB | ⚠️ +1.9 kB |
Diff for main.js ```diff @@ -1,20 +1,5 @@ (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), - /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,28 +54,6 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; - -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); - - -/***/ }), - /***/ "BMP1": /***/ (function(module, exports, __webpack_require__) { @@ -894,15 +857,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -970,17 +924,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -1058,22 +1001,6 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { @@ -1097,12 +1024,10 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ +/* global document, window */ function supportsPreload(el) { @@ -1132,13 +1057,31 @@ function () { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set["default"](); this.pageRegisterEvents = (0, _mitt["default"])(); this.loadingRoutes = {}; this.promisedBuildId = _promise["default"].resolve(); - } + this.promisedBuildManifest = new _promise["default"](function (resolve) { + if (window.__BUILD_MANIFEST) { + resolve(window.__BUILD_MANIFEST); + } else { + window.__BUILD_MANIFEST_CB = function () { + resolve(window.__BUILD_MANIFEST); + }; + } + }); + } // Returns a promise for the dependencies for a particular route + (0, _createClass2["default"])(PageLoader, [{ + key: "getDependencies", + value: function getDependencies(route) { + return this.promisedBuildManifest.then(function (man) { + return man[route] && man.map(function (url) { + return "/_next/" + url; + }) || []; + }); + } + }, { key: "normalizeRoute", value: function normalizeRoute(route) { if (route[0] !== '/') { @@ -1188,13 +1131,20 @@ function () { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!_this3.loadingRoutes[route]) { - _this3.loadScript(route); + _this3.getDependencies(route).then(function (deps) { + deps.forEach(function (d) { + if (!document.querySelector("script[src^=\"" + d + "\"]")) { + _this3.loadScript(d, route, false); + } + }); + + _this3.loadRoute(route); - _this3.loadingRoutes[route] = true; + _this3.loadingRoutes[route] = true; + }); } }); } @@ -1224,14 +1174,14 @@ function () { }); } }, { - key: "loadScript", - value: function loadScript(route) { + key: "loadRoute", + value: function loadRoute(route) { var _this = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee() { - var scriptRoute, script, url; + var scriptRoute, url; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { @@ -1242,38 +1192,46 @@ function () { case 2: route = _this.normalizeRoute(route); scriptRoute = route === '/' ? '/index.js' : route + ".js"; - script = document.createElement('script'); - - if (false) {} - url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = undefined; - script.src = url; - - script.onerror = function () { - var error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; - _this.pageRegisterEvents.emit(route, { - error: error - }); - }; + _this.loadScript(url, route, true); - document.body.appendChild(script); - - case 11: + case 6: case "end": return _context.stop(); } } }, _callee); }))(); + } + }, { + key: "loadScript", + value: function loadScript(url, route, isPage) { + var _this5 = this; + + var script = document.createElement('script'); + + if (false) {} + + script.crossOrigin = undefined; + script.src = url; + + script.onerror = function () { + var error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + + _this5.pageRegisterEvents.emit(route, { + error: error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. }, { key: "registerPage", value: function registerPage(route, regFn) { - var _this5 = this; + var _this6 = this; var register = function register() { try { @@ -1281,21 +1239,21 @@ function () { error = _regFn.error, page = _regFn.page; - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error, page: page }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error, page: page }); } catch (error) { - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error }); } @@ -1307,67 +1265,92 @@ function () { } }, { key: "prefetch", - value: function prefetch(route) { + value: function prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee2() { - var scriptRoute, cn; + var scriptRoute, url, cn; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: + _context2.next = 2; + return _this2.promisedBuildId; + + case 2: route = _this2.normalizeRoute(route); scriptRoute = (route === '/' ? '/index' : route) + ".js"; if (false) {} - if (!(_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route))) { - _context2.next = 5; + url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. + + if (!(document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route))) { + _context2.next = 8; break; } return _context2.abrupt("return"); - case 5: - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE - - + case 8: if (!(cn = navigator.connection)) { - _context2.next = 9; + _context2.next = 11; break; } if (!((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData)) { - _context2.next = 9; + _context2.next = 11; break; } return _context2.abrupt("return"); - case 9: + case 11: + if (isDependency) { + _context2.next = 17; + break; + } + + ; + _context2.next = 15; + return _this2.getDependencies(route); + + case 15: + _context2.t0 = function (url) { + _this2.prefetch(url, true); + }; + + _context2.sent.forEach(_context2.t0); + + case 17: if (!hasPreload) { - _context2.next = 14; + _context2.next = 20; break; } - _context2.next = 12; - return _this2.promisedBuildId; + preloadScript(url); + return _context2.abrupt("return"); + + case 20: + if (!isDependency) { + _context2.next = 22; + break; + } - case 12: - preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute); return _context2.abrupt("return"); - case 14: + case 22: if (!(document.readyState === 'complete')) { - _context2.next = 18; + _context2.next = 26; break; } return _context2.abrupt("return", _this2.loadPage(route)["catch"](function () {})); - case 18: + case 26: return _context2.abrupt("return", new _promise["default"](function (resolve) { window.addEventListener('load', function () { _this2.loadPage(route).then(function () { @@ -1378,7 +1361,7 @@ function () { }); })); - case 19: + case 27: case "end": return _context2.stop(); } ```
ijjk commented 5 years ago

Stats from current PR

Click to expand stats ⚠️ Total Bundle Size Increase ⚠️ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 14.5s | 13.7s | -797ms | | `node_modules` Size | 43.6 MB | 43.6 MB | ⚠️ +8.11 kB | | Total Bundle (main, webpack, commons) Size | 206 kB | 206 kB | ⚠️ +219 B | | Total Bundle (main, webpack, commons) gzip Size | 67.8 kB | 67.9 kB | ⚠️ +120 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `main` Size | 15.4 kB | 15.5 kB | ⚠️ +132 B | | Client `main` gzip Size | 5.35 kB | 5.46 kB | ⚠️ +103 B | | Client `commons` Size | 188 kB | 188 kB | ⚠️ +87 B | | Client `commons` gzip Size | 61.1 kB | 61.1 kB | ⚠️ +17 B | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Base Rendered Size | 1.35 kB | 1.35 kB | ✓ | | Build Dir Size | 700 kB | 704 kB | ⚠️ +3.85 kB |
Click to expand serverless stats ⚠️ Total Bundle Size Increase ⚠️ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 15.1s | 14.9s | -230ms | | `node_modules` Size | 43.6 MB | 43.6 MB | ⚠️ +8.11 kB | | Total Bundle (main, webpack, commons) Size | 206 kB | 206 kB | ⚠️ +219 B | | Total Bundle (main, webpack, commons) gzip Size | 67.8 kB | 67.9 kB | ⚠️ +121 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ⚠️ +1 B | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 300 B | 301 B | ⚠️ +1 B | | Client `main` Size | 15.4 kB | 15.5 kB | ⚠️ +132 B | | Client `main` gzip Size | 5.35 kB | 5.46 kB | ⚠️ +103 B | | Client `commons` Size | 188 kB | 188 kB | ⚠️ +87 B | | Client `commons` gzip Size | 61.1 kB | 61.1 kB | ⚠️ +17 B | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Serverless `pages/link` Size | 251 kB | 251 kB | ⚠️ +434 B | | Serverless `pages/link` gzip Size | 67.8 kB | 67.8 kB | ⚠️ +61 B | | Serverless `pages/index` Size | 243 kB | 244 kB | ⚠️ +434 B | | Serverless `pages/index` gzip Size | 65.6 kB | 65.6 kB | ⚠️ +59 B | | Serverless `pages/_error` Size | 243 kB | 243 kB | ⚠️ +434 B | | Serverless `pages/_error` gzip Size | 65.3 kB | 65.4 kB | ⚠️ +58 B | | Serverless `pages/routerDirect` Size | 244 kB | 244 kB | ⚠️ +434 B | | Serverless `pages/routerDirect` gzip Size | 65.5 kB | 65.6 kB | ⚠️ +57 B | | Serverless `pages/withRouter` Size | 244 kB | 244 kB | ⚠️ +434 B | | Serverless `pages/withRouter` gzip Size | 65.7 kB | 65.7 kB | ⚠️ +58 B | | Build Dir Size | 1.88 MB | 1.89 MB | ⚠️ +5.16 kB |
Diff for commons.js ```diff @@ -6684,7 +6684,8 @@ var singletonRouter = { } }; // Create public properties and methods of the router in the singletonRouter -var urlPropertyFields = ['pathname', 'route', 'query', 'asPath', 'components']; +var urlPropertyFields = ['pathname', 'route', 'query', 'asPath']; +var propertyFields = ['components']; var routerEvents = ['routeChangeStart', 'beforeHistoryChange', 'routeChangeComplete', 'routeChangeError', 'hashChangeStart', 'hashChangeComplete']; var coreMethodFields = ['push', 'replace', 'reload', 'back', 'prefetch', 'beforePopState']; // Events is a static property on the router, the router doesn't have to be initialized to use it @@ -6693,7 +6694,7 @@ var coreMethodFields = ['push', 'replace', 'reload', 'back', 'prefetch', 'before return _router2["default"].events; } }); -urlPropertyFields.forEach(function (field) { +propertyFields.concat(urlPropertyFields).forEach(function (field) { // Here we need to use Object.defineProperty because, we need to return // the property assigned to the actual router // The value might get changed as we change routes and this is the @@ -6792,6 +6793,17 @@ function makePublicRouterInstance(router) { instance.events = _router2["default"].events; + propertyFields.forEach(function (field) { + // Here we need to use Object.defineProperty because, we need to return + // the property assigned to the actual router + // The value might get changed as we change routes and this is the + // proper way to access it + (0, _defineProperty["default"])(instance, field, { + get: function get() { + return _router[field]; + } + }); + }); coreMethodFields.forEach(function (field) { instance[field] = function () { return _router[field].apply(_router, arguments); ```
Diff for main.js ```diff @@ -1,20 +1,5 @@ (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), - /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,28 +54,6 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; - -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); - - -/***/ }), - /***/ "BMP1": /***/ (function(module, exports, __webpack_require__) { @@ -894,15 +857,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -970,17 +924,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -1058,22 +1001,6 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { @@ -1097,12 +1024,10 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ +/* global document, window */ function supportsPreload(el) { @@ -1132,13 +1057,31 @@ function () { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set["default"](); this.pageRegisterEvents = (0, _mitt["default"])(); this.loadingRoutes = {}; this.promisedBuildId = _promise["default"].resolve(); - } + this.promisedBuildManifest = new _promise["default"](function (resolve) { + if (window.__BUILD_MANIFEST) { + resolve(window.__BUILD_MANIFEST); + } else { + window.__BUILD_MANIFEST_CB = function () { + resolve(window.__BUILD_MANIFEST); + }; + } + }); + } // Returns a promise for the dependencies for a particular route + (0, _createClass2["default"])(PageLoader, [{ + key: "getDependencies", + value: function getDependencies(route) { + return this.promisedBuildManifest.then(function (man) { + return man[route] && man.map(function (url) { + return "/_next/" + url; + }) || []; + }); + } + }, { key: "normalizeRoute", value: function normalizeRoute(route) { if (route[0] !== '/') { @@ -1188,13 +1131,20 @@ function () { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!_this3.loadingRoutes[route]) { - _this3.loadScript(route); + _this3.getDependencies(route).then(function (deps) { + deps.forEach(function (d) { + if (!document.querySelector("script[src^=\"" + d + "\"]")) { + _this3.loadScript(d, route, false); + } + }); + + _this3.loadRoute(route); - _this3.loadingRoutes[route] = true; + _this3.loadingRoutes[route] = true; + }); } }); } @@ -1224,14 +1174,14 @@ function () { }); } }, { - key: "loadScript", - value: function loadScript(route) { + key: "loadRoute", + value: function loadRoute(route) { var _this = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee() { - var scriptRoute, script, url; + var scriptRoute, url; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { @@ -1242,38 +1192,46 @@ function () { case 2: route = _this.normalizeRoute(route); scriptRoute = route === '/' ? '/index.js' : route + ".js"; - script = document.createElement('script'); - - if (false) {} - url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = undefined; - script.src = url; - - script.onerror = function () { - var error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; - _this.pageRegisterEvents.emit(route, { - error: error - }); - }; + _this.loadScript(url, route, true); - document.body.appendChild(script); - - case 11: + case 6: case "end": return _context.stop(); } } }, _callee); }))(); + } + }, { + key: "loadScript", + value: function loadScript(url, route, isPage) { + var _this5 = this; + + var script = document.createElement('script'); + + if (false) {} + + script.crossOrigin = undefined; + script.src = url; + + script.onerror = function () { + var error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + + _this5.pageRegisterEvents.emit(route, { + error: error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. }, { key: "registerPage", value: function registerPage(route, regFn) { - var _this5 = this; + var _this6 = this; var register = function register() { try { @@ -1281,21 +1239,21 @@ function () { error = _regFn.error, page = _regFn.page; - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error, page: page }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error, page: page }); } catch (error) { - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error }); } @@ -1307,67 +1265,92 @@ function () { } }, { key: "prefetch", - value: function prefetch(route) { + value: function prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee2() { - var scriptRoute, cn; + var scriptRoute, url, cn; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: + _context2.next = 2; + return _this2.promisedBuildId; + + case 2: route = _this2.normalizeRoute(route); scriptRoute = (route === '/' ? '/index' : route) + ".js"; if (false) {} - if (!(_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route))) { - _context2.next = 5; + url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. + + if (!(document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route))) { + _context2.next = 8; break; } return _context2.abrupt("return"); - case 5: - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE - - + case 8: if (!(cn = navigator.connection)) { - _context2.next = 9; + _context2.next = 11; break; } if (!((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData)) { - _context2.next = 9; + _context2.next = 11; break; } return _context2.abrupt("return"); - case 9: + case 11: + if (isDependency) { + _context2.next = 17; + break; + } + + ; + _context2.next = 15; + return _this2.getDependencies(route); + + case 15: + _context2.t0 = function (url) { + _this2.prefetch(url, true); + }; + + _context2.sent.forEach(_context2.t0); + + case 17: if (!hasPreload) { - _context2.next = 14; + _context2.next = 20; break; } - _context2.next = 12; - return _this2.promisedBuildId; + preloadScript(url); + return _context2.abrupt("return"); + + case 20: + if (!isDependency) { + _context2.next = 22; + break; + } - case 12: - preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute); return _context2.abrupt("return"); - case 14: + case 22: if (!(document.readyState === 'complete')) { - _context2.next = 18; + _context2.next = 26; break; } return _context2.abrupt("return", _this2.loadPage(route)["catch"](function () {})); - case 18: + case 26: return _context2.abrupt("return", new _promise["default"](function (resolve) { window.addEventListener('load', function () { _this2.loadPage(route).then(function () { @@ -1378,7 +1361,7 @@ function () { }); })); - case 19: + case 27: case "end": return _context2.stop(); } ```
ijjk commented 5 years ago

Stats from current PR

Click to expand stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 13.8s | 13.8s | ⚠️ +19ms | | `node_modules` Size | 43.6 MB | 43.6 MB | ⚠️ +7.01 kB | | Total Bundle (main, webpack, commons) Size | 206 kB | 206 kB | -123 B | | Total Bundle (main, webpack, commons) gzip Size | 67.8 kB | 67.8 kB | ⚠️ +45 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `main` Size | 15.4 kB | 15.2 kB | -210 B | | Client `main` gzip Size | 5.35 kB | 5.38 kB | ⚠️ +28 B | | Client `commons` Size | 188 kB | 188 kB | ⚠️ +87 B | | Client `commons` gzip Size | 61.1 kB | 61.1 kB | ⚠️ +17 B | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Base Rendered Size | 1.35 kB | 1.35 kB | ✓ | | Build Dir Size | 700 kB | 703 kB | ⚠️ +2.68 kB |
Click to expand serverless stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 14.5s | 14s | -516ms | | `node_modules` Size | 43.6 MB | 43.6 MB | ⚠️ +7.01 kB | | Total Bundle (main, webpack, commons) Size | 206 kB | 206 kB | -123 B | | Total Bundle (main, webpack, commons) gzip Size | 67.8 kB | 67.8 kB | ⚠️ +45 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `main` Size | 15.4 kB | 15.2 kB | -210 B | | Client `main` gzip Size | 5.35 kB | 5.38 kB | ⚠️ +28 B | | Client `commons` Size | 188 kB | 188 kB | ⚠️ +87 B | | Client `commons` gzip Size | 61.1 kB | 61.1 kB | ⚠️ +17 B | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Serverless `pages/link` Size | 251 kB | 251 kB | ⚠️ +434 B | | Serverless `pages/link` gzip Size | 67.8 kB | 67.8 kB | ⚠️ +61 B | | Serverless `pages/index` Size | 243 kB | 244 kB | ⚠️ +434 B | | Serverless `pages/index` gzip Size | 65.6 kB | 65.6 kB | ⚠️ +60 B | | Serverless `pages/_error` Size | 243 kB | 243 kB | ⚠️ +434 B | | Serverless `pages/_error` gzip Size | 65.3 kB | 65.4 kB | ⚠️ +58 B | | Serverless `pages/routerDirect` Size | 244 kB | 244 kB | ⚠️ +434 B | | Serverless `pages/routerDirect` gzip Size | 65.5 kB | 65.6 kB | ⚠️ +58 B | | Serverless `pages/withRouter` Size | 244 kB | 244 kB | ⚠️ +434 B | | Serverless `pages/withRouter` gzip Size | 65.7 kB | 65.7 kB | ⚠️ +58 B | | Build Dir Size | 1.88 MB | 1.89 MB | ⚠️ +3.98 kB |
Diff for commons.js ```diff @@ -6684,7 +6684,8 @@ var singletonRouter = { } }; // Create public properties and methods of the router in the singletonRouter -var urlPropertyFields = ['pathname', 'route', 'query', 'asPath', 'components']; +var urlPropertyFields = ['pathname', 'route', 'query', 'asPath']; +var propertyFields = ['components']; var routerEvents = ['routeChangeStart', 'beforeHistoryChange', 'routeChangeComplete', 'routeChangeError', 'hashChangeStart', 'hashChangeComplete']; var coreMethodFields = ['push', 'replace', 'reload', 'back', 'prefetch', 'beforePopState']; // Events is a static property on the router, the router doesn't have to be initialized to use it @@ -6693,7 +6694,7 @@ var coreMethodFields = ['push', 'replace', 'reload', 'back', 'prefetch', 'before return _router2["default"].events; } }); -urlPropertyFields.forEach(function (field) { +propertyFields.concat(urlPropertyFields).forEach(function (field) { // Here we need to use Object.defineProperty because, we need to return // the property assigned to the actual router // The value might get changed as we change routes and this is the @@ -6792,6 +6793,17 @@ function makePublicRouterInstance(router) { instance.events = _router2["default"].events; + propertyFields.forEach(function (field) { + // Here we need to use Object.defineProperty because, we need to return + // the property assigned to the actual router + // The value might get changed as we change routes and this is the + // proper way to access it + (0, _defineProperty["default"])(instance, field, { + get: function get() { + return _router[field]; + } + }); + }); coreMethodFields.forEach(function (field) { instance[field] = function () { return _router[field].apply(_router, arguments); ```
Diff for main.js ```diff @@ -1,19 +1,4 @@ -(window["webpackJsonp"] = window["webpackJsonp"] || []).push([[2],{ - -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), +(window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,28 +54,6 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; - -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); - - -/***/ }), - /***/ "BMP1": /***/ (function(module, exports, __webpack_require__) { @@ -894,15 +857,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -970,17 +924,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -1058,22 +1001,6 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { @@ -1097,12 +1024,10 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ +/* global document, window */ function supportsPreload(el) { @@ -1122,6 +1047,17 @@ function preloadScript(url) { link.href = url; link.as = 'script'; document.head.appendChild(link); +} // Retrieve a list of dependencies for a given route from the build manifest + + +function getDependencies(route, _m) { + if ((_m = window.__BUILD_MANIFEST) && (_m = _m[route])) { + return _m.map(function (url) { + return "/_next/" + url; + }); + } + + return []; } var PageLoader = @@ -1132,7 +1068,6 @@ function () { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set["default"](); this.pageRegisterEvents = (0, _mitt["default"])(); this.loadingRoutes = {}; this.promisedBuildId = _promise["default"].resolve(); @@ -1188,11 +1123,16 @@ function () { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!_this3.loadingRoutes[route]) { - _this3.loadScript(route); + getDependencies(route).forEach(function (d) { + if (!document.querySelector("script[src^=\"" + d + "\"]")) { + _this3.loadScript(d, route, false); + } + }); + + _this3.loadRoute(route); _this3.loadingRoutes[route] = true; } @@ -1224,14 +1164,14 @@ function () { }); } }, { - key: "loadScript", - value: function loadScript(route) { + key: "loadRoute", + value: function loadRoute(route) { var _this = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee() { - var scriptRoute, script, url; + var scriptRoute, url; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { @@ -1242,38 +1182,46 @@ function () { case 2: route = _this.normalizeRoute(route); scriptRoute = route === '/' ? '/index.js' : route + ".js"; - script = document.createElement('script'); - - if (false) {} - url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = undefined; - script.src = url; - - script.onerror = function () { - var error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; - - _this.pageRegisterEvents.emit(route, { - error: error - }); - }; - document.body.appendChild(script); + _this.loadScript(url, route, true); - case 11: + case 6: case "end": return _context.stop(); } } }, _callee); }))(); + } + }, { + key: "loadScript", + value: function loadScript(url, route, isPage) { + var _this5 = this; + + var script = document.createElement('script'); + + if (false) {} + + script.crossOrigin = undefined; + script.src = url; + + script.onerror = function () { + var error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + + _this5.pageRegisterEvents.emit(route, { + error: error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. }, { key: "registerPage", value: function registerPage(route, regFn) { - var _this5 = this; + var _this6 = this; var register = function register() { try { @@ -1281,21 +1229,21 @@ function () { error = _regFn.error, page = _regFn.page; - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error, page: page }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error, page: page }); } catch (error) { - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error }); } @@ -1307,67 +1255,84 @@ function () { } }, { key: "prefetch", - value: function prefetch(route) { + value: function prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee2() { - var scriptRoute, cn; + var scriptRoute, url, cn; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: + _context2.next = 2; + return _this2.promisedBuildId; + + case 2: route = _this2.normalizeRoute(route); scriptRoute = (route === '/' ? '/index' : route) + ".js"; if (false) {} - if (!(_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route))) { - _context2.next = 5; + url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. + + if (!(document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route))) { + _context2.next = 8; break; } return _context2.abrupt("return"); - case 5: - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE - - + case 8: if (!(cn = navigator.connection)) { - _context2.next = 9; + _context2.next = 11; break; } if (!((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData)) { - _context2.next = 9; + _context2.next = 11; break; } return _context2.abrupt("return"); - case 9: + case 11: + if (!isDependency) { + getDependencies(route).forEach(function (url) { + _this2.prefetch(url, true); + }); + } // Feature detection is used to see if preload is supported + // If not fall back to loading script tags before the page is loaded + // https://caniuse.com/#feat=link-rel-preload + + if (!hasPreload) { - _context2.next = 14; + _context2.next = 15; break; } - _context2.next = 12; - return _this2.promisedBuildId; + preloadScript(url); + return _context2.abrupt("return"); + + case 15: + if (!isDependency) { + _context2.next = 17; + break; + } - case 12: - preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute); return _context2.abrupt("return"); - case 14: + case 17: if (!(document.readyState === 'complete')) { - _context2.next = 18; + _context2.next = 21; break; } return _context2.abrupt("return", _this2.loadPage(route)["catch"](function () {})); - case 18: + case 21: return _context2.abrupt("return", new _promise["default"](function (resolve) { window.addEventListener('load', function () { _this2.loadPage(route).then(function () { @@ -1378,7 +1343,7 @@ function () { }); })); - case 19: + case 22: case "end": return _context2.stop(); } ```
ijjk commented 5 years ago

Stats from current PR

Click to expand stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 13.5s | 13.3s | -151ms | | `node_modules` Size | 43.6 MB | 43.6 MB | ⚠️ +7.01 kB | | Total Bundle (main, webpack, commons) Size | 206 kB | 206 kB | -123 B | | Total Bundle (main, webpack, commons) gzip Size | 67.8 kB | 67.8 kB | ⚠️ +45 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `main` Size | 15.4 kB | 15.2 kB | -210 B | | Client `main` gzip Size | 5.35 kB | 5.38 kB | ⚠️ +28 B | | Client `commons` Size | 188 kB | 188 kB | ⚠️ +87 B | | Client `commons` gzip Size | 61.1 kB | 61.1 kB | ⚠️ +17 B | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Base Rendered Size | 1.35 kB | 1.35 kB | ✓ | | Build Dir Size | 700 kB | 703 kB | ⚠️ +2.68 kB |
Click to expand serverless stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 14.6s | 14.8s | ⚠️ +184ms | | `node_modules` Size | 43.6 MB | 43.6 MB | ⚠️ +7.01 kB | | Total Bundle (main, webpack, commons) Size | 206 kB | 206 kB | -123 B | | Total Bundle (main, webpack, commons) gzip Size | 67.8 kB | 67.8 kB | ⚠️ +45 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `main` Size | 15.4 kB | 15.2 kB | -210 B | | Client `main` gzip Size | 5.35 kB | 5.38 kB | ⚠️ +28 B | | Client `commons` Size | 188 kB | 188 kB | ⚠️ +87 B | | Client `commons` gzip Size | 61.1 kB | 61.1 kB | ⚠️ +17 B | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Serverless `pages/link` Size | 251 kB | 251 kB | ⚠️ +434 B | | Serverless `pages/link` gzip Size | 67.8 kB | 67.8 kB | ⚠️ +60 B | | Serverless `pages/index` Size | 243 kB | 244 kB | ⚠️ +434 B | | Serverless `pages/index` gzip Size | 65.6 kB | 65.6 kB | ⚠️ +58 B | | Serverless `pages/_error` Size | 243 kB | 243 kB | ⚠️ +434 B | | Serverless `pages/_error` gzip Size | 65.3 kB | 65.4 kB | ⚠️ +56 B | | Serverless `pages/routerDirect` Size | 244 kB | 244 kB | ⚠️ +434 B | | Serverless `pages/routerDirect` gzip Size | 65.5 kB | 65.6 kB | ⚠️ +56 B | | Serverless `pages/withRouter` Size | 244 kB | 244 kB | ⚠️ +434 B | | Serverless `pages/withRouter` gzip Size | 65.7 kB | 65.7 kB | ⚠️ +56 B | | Build Dir Size | 1.88 MB | 1.89 MB | ⚠️ +3.98 kB |
Diff for commons.js ```diff @@ -6684,7 +6684,8 @@ var singletonRouter = { } }; // Create public properties and methods of the router in the singletonRouter -var urlPropertyFields = ['pathname', 'route', 'query', 'asPath', 'components']; +var urlPropertyFields = ['pathname', 'route', 'query', 'asPath']; +var propertyFields = ['components']; var routerEvents = ['routeChangeStart', 'beforeHistoryChange', 'routeChangeComplete', 'routeChangeError', 'hashChangeStart', 'hashChangeComplete']; var coreMethodFields = ['push', 'replace', 'reload', 'back', 'prefetch', 'beforePopState']; // Events is a static property on the router, the router doesn't have to be initialized to use it @@ -6693,7 +6694,7 @@ var coreMethodFields = ['push', 'replace', 'reload', 'back', 'prefetch', 'before return _router2["default"].events; } }); -urlPropertyFields.forEach(function (field) { +propertyFields.concat(urlPropertyFields).forEach(function (field) { // Here we need to use Object.defineProperty because, we need to return // the property assigned to the actual router // The value might get changed as we change routes and this is the @@ -6792,6 +6793,17 @@ function makePublicRouterInstance(router) { instance.events = _router2["default"].events; + propertyFields.forEach(function (field) { + // Here we need to use Object.defineProperty because, we need to return + // the property assigned to the actual router + // The value might get changed as we change routes and this is the + // proper way to access it + (0, _defineProperty["default"])(instance, field, { + get: function get() { + return _router[field]; + } + }); + }); coreMethodFields.forEach(function (field) { instance[field] = function () { return _router[field].apply(_router, arguments); ```
Diff for main.js ```diff @@ -1,20 +1,5 @@ (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), - /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,28 +54,6 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; - -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); - - -/***/ }), - /***/ "BMP1": /***/ (function(module, exports, __webpack_require__) { @@ -894,15 +857,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -970,17 +924,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -1058,22 +1001,6 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { @@ -1097,12 +1024,10 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ +/* global document, window */ function supportsPreload(el) { @@ -1122,6 +1047,17 @@ function preloadScript(url) { link.href = url; link.as = 'script'; document.head.appendChild(link); +} // Retrieve a list of dependencies for a given route from the build manifest + + +function getDependencies(route, _m) { + if ((_m = window.__BUILD_MANIFEST) && (_m = _m[route])) { + return _m.map(function (url) { + return "/_next/" + url; + }); + } + + return []; } var PageLoader = @@ -1132,7 +1068,6 @@ function () { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set["default"](); this.pageRegisterEvents = (0, _mitt["default"])(); this.loadingRoutes = {}; this.promisedBuildId = _promise["default"].resolve(); @@ -1188,11 +1123,16 @@ function () { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!_this3.loadingRoutes[route]) { - _this3.loadScript(route); + getDependencies(route).forEach(function (d) { + if (!document.querySelector("script[src^=\"" + d + "\"]")) { + _this3.loadScript(d, route, false); + } + }); + + _this3.loadRoute(route); _this3.loadingRoutes[route] = true; } @@ -1224,14 +1164,14 @@ function () { }); } }, { - key: "loadScript", - value: function loadScript(route) { + key: "loadRoute", + value: function loadRoute(route) { var _this = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee() { - var scriptRoute, script, url; + var scriptRoute, url; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { @@ -1242,38 +1182,46 @@ function () { case 2: route = _this.normalizeRoute(route); scriptRoute = route === '/' ? '/index.js' : route + ".js"; - script = document.createElement('script'); - - if (false) {} - url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = undefined; - script.src = url; - - script.onerror = function () { - var error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; - - _this.pageRegisterEvents.emit(route, { - error: error - }); - }; - document.body.appendChild(script); + _this.loadScript(url, route, true); - case 11: + case 6: case "end": return _context.stop(); } } }, _callee); }))(); + } + }, { + key: "loadScript", + value: function loadScript(url, route, isPage) { + var _this5 = this; + + var script = document.createElement('script'); + + if (false) {} + + script.crossOrigin = undefined; + script.src = url; + + script.onerror = function () { + var error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + + _this5.pageRegisterEvents.emit(route, { + error: error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. }, { key: "registerPage", value: function registerPage(route, regFn) { - var _this5 = this; + var _this6 = this; var register = function register() { try { @@ -1281,21 +1229,21 @@ function () { error = _regFn.error, page = _regFn.page; - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error, page: page }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error, page: page }); } catch (error) { - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error }); } @@ -1307,67 +1255,84 @@ function () { } }, { key: "prefetch", - value: function prefetch(route) { + value: function prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee2() { - var scriptRoute, cn; + var scriptRoute, url, cn; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: + _context2.next = 2; + return _this2.promisedBuildId; + + case 2: route = _this2.normalizeRoute(route); scriptRoute = (route === '/' ? '/index' : route) + ".js"; if (false) {} - if (!(_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route))) { - _context2.next = 5; + url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. + + if (!(document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route))) { + _context2.next = 8; break; } return _context2.abrupt("return"); - case 5: - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE - - + case 8: if (!(cn = navigator.connection)) { - _context2.next = 9; + _context2.next = 11; break; } if (!((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData)) { - _context2.next = 9; + _context2.next = 11; break; } return _context2.abrupt("return"); - case 9: + case 11: + if (!isDependency) { + getDependencies(route).forEach(function (url) { + _this2.prefetch(url, true); + }); + } // Feature detection is used to see if preload is supported + // If not fall back to loading script tags before the page is loaded + // https://caniuse.com/#feat=link-rel-preload + + if (!hasPreload) { - _context2.next = 14; + _context2.next = 15; break; } - _context2.next = 12; - return _this2.promisedBuildId; + preloadScript(url); + return _context2.abrupt("return"); + + case 15: + if (!isDependency) { + _context2.next = 17; + break; + } - case 12: - preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute); return _context2.abrupt("return"); - case 14: + case 17: if (!(document.readyState === 'complete')) { - _context2.next = 18; + _context2.next = 21; break; } return _context2.abrupt("return", _this2.loadPage(route)["catch"](function () {})); - case 18: + case 21: return _context2.abrupt("return", new _promise["default"](function (resolve) { window.addEventListener('load', function () { _this2.loadPage(route).then(function () { @@ -1378,7 +1343,7 @@ function () { }); })); - case 19: + case 22: case "end": return _context2.stop(); } ```
ijjk commented 5 years ago

Stats from current PR

Click to expand stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 13.2s | 13.1s | -94ms | | `node_modules` Size | 43.6 MB | 43.6 MB | ⚠️ +7.09 kB | | Total Bundle (main, webpack, commons) Size | 206 kB | 206 kB | -123 B | | Total Bundle (main, webpack, commons) gzip Size | 67.8 kB | 67.8 kB | ⚠️ +45 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `main` Size | 15.4 kB | 15.2 kB | -210 B | | Client `main` gzip Size | 5.35 kB | 5.38 kB | ⚠️ +28 B | | Client `commons` Size | 188 kB | 188 kB | ⚠️ +87 B | | Client `commons` gzip Size | 61.1 kB | 61.1 kB | ⚠️ +17 B | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Base Rendered Size | 1.35 kB | 1.35 kB | ✓ | | Build Dir Size | 700 kB | 703 kB | ⚠️ +2.68 kB |
Click to expand serverless stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 13.9s | 14.4s | ⚠️ +488ms | | `node_modules` Size | 43.6 MB | 43.6 MB | ⚠️ +7.09 kB | | Total Bundle (main, webpack, commons) Size | 206 kB | 206 kB | -123 B | | Total Bundle (main, webpack, commons) gzip Size | 67.8 kB | 67.8 kB | ⚠️ +46 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ⚠️ +1 B | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 300 B | 301 B | ⚠️ +1 B | | Client `main` Size | 15.4 kB | 15.2 kB | -210 B | | Client `main` gzip Size | 5.35 kB | 5.38 kB | ⚠️ +28 B | | Client `commons` Size | 188 kB | 188 kB | ⚠️ +87 B | | Client `commons` gzip Size | 61.1 kB | 61.1 kB | ⚠️ +17 B | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Serverless `pages/link` Size | 251 kB | 251 kB | ⚠️ +434 B | | Serverless `pages/link` gzip Size | 67.8 kB | 67.8 kB | ⚠️ +59 B | | Serverless `pages/index` Size | 243 kB | 244 kB | ⚠️ +434 B | | Serverless `pages/index` gzip Size | 65.6 kB | 65.6 kB | ⚠️ +58 B | | Serverless `pages/_error` Size | 243 kB | 243 kB | ⚠️ +434 B | | Serverless `pages/_error` gzip Size | 65.3 kB | 65.4 kB | ⚠️ +57 B | | Serverless `pages/routerDirect` Size | 244 kB | 244 kB | ⚠️ +434 B | | Serverless `pages/routerDirect` gzip Size | 65.5 kB | 65.6 kB | ⚠️ +56 B | | Serverless `pages/withRouter` Size | 244 kB | 244 kB | ⚠️ +434 B | | Serverless `pages/withRouter` gzip Size | 65.7 kB | 65.7 kB | ⚠️ +56 B | | Build Dir Size | 1.88 MB | 1.89 MB | ⚠️ +3.98 kB |
Diff for commons.js ```diff @@ -6684,7 +6684,8 @@ var singletonRouter = { } }; // Create public properties and methods of the router in the singletonRouter -var urlPropertyFields = ['pathname', 'route', 'query', 'asPath', 'components']; +var urlPropertyFields = ['pathname', 'route', 'query', 'asPath']; +var propertyFields = ['components']; var routerEvents = ['routeChangeStart', 'beforeHistoryChange', 'routeChangeComplete', 'routeChangeError', 'hashChangeStart', 'hashChangeComplete']; var coreMethodFields = ['push', 'replace', 'reload', 'back', 'prefetch', 'beforePopState']; // Events is a static property on the router, the router doesn't have to be initialized to use it @@ -6693,7 +6694,7 @@ var coreMethodFields = ['push', 'replace', 'reload', 'back', 'prefetch', 'before return _router2["default"].events; } }); -urlPropertyFields.forEach(function (field) { +propertyFields.concat(urlPropertyFields).forEach(function (field) { // Here we need to use Object.defineProperty because, we need to return // the property assigned to the actual router // The value might get changed as we change routes and this is the @@ -6792,6 +6793,17 @@ function makePublicRouterInstance(router) { instance.events = _router2["default"].events; + propertyFields.forEach(function (field) { + // Here we need to use Object.defineProperty because, we need to return + // the property assigned to the actual router + // The value might get changed as we change routes and this is the + // proper way to access it + (0, _defineProperty["default"])(instance, field, { + get: function get() { + return _router[field]; + } + }); + }); coreMethodFields.forEach(function (field) { instance[field] = function () { return _router[field].apply(_router, arguments); ```
Diff for main.js ```diff @@ -1,19 +1,4 @@ -(window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ - -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), +(window["webpackJsonp"] = window["webpackJsonp"] || []).push([[2],{ /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,28 +54,6 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; - -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); - - -/***/ }), - /***/ "BMP1": /***/ (function(module, exports, __webpack_require__) { @@ -894,15 +857,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -970,17 +924,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -1058,22 +1001,6 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { @@ -1097,12 +1024,10 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ +/* global document, window */ function supportsPreload(el) { @@ -1122,6 +1047,17 @@ function preloadScript(url) { link.href = url; link.as = 'script'; document.head.appendChild(link); +} // Retrieve a list of dependencies for a given route from the build manifest + + +function getDependencies(route, _m) { + if ((_m = window.__BUILD_MANIFEST) && (_m = _m[route])) { + return _m.map(function (url) { + return "/_next/" + url; + }); + } + + return []; } var PageLoader = @@ -1132,7 +1068,6 @@ function () { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set["default"](); this.pageRegisterEvents = (0, _mitt["default"])(); this.loadingRoutes = {}; this.promisedBuildId = _promise["default"].resolve(); @@ -1188,11 +1123,16 @@ function () { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!_this3.loadingRoutes[route]) { - _this3.loadScript(route); + getDependencies(route).forEach(function (d) { + if (!document.querySelector("script[src^=\"" + d + "\"]")) { + _this3.loadScript(d, route, false); + } + }); + + _this3.loadRoute(route); _this3.loadingRoutes[route] = true; } @@ -1224,14 +1164,14 @@ function () { }); } }, { - key: "loadScript", - value: function loadScript(route) { + key: "loadRoute", + value: function loadRoute(route) { var _this = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee() { - var scriptRoute, script, url; + var scriptRoute, url; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { @@ -1242,38 +1182,46 @@ function () { case 2: route = _this.normalizeRoute(route); scriptRoute = route === '/' ? '/index.js' : route + ".js"; - script = document.createElement('script'); - - if (false) {} - url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = undefined; - script.src = url; - - script.onerror = function () { - var error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; - - _this.pageRegisterEvents.emit(route, { - error: error - }); - }; - document.body.appendChild(script); + _this.loadScript(url, route, true); - case 11: + case 6: case "end": return _context.stop(); } } }, _callee); }))(); + } + }, { + key: "loadScript", + value: function loadScript(url, route, isPage) { + var _this5 = this; + + var script = document.createElement('script'); + + if (false) {} + + script.crossOrigin = undefined; + script.src = url; + + script.onerror = function () { + var error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + + _this5.pageRegisterEvents.emit(route, { + error: error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. }, { key: "registerPage", value: function registerPage(route, regFn) { - var _this5 = this; + var _this6 = this; var register = function register() { try { @@ -1281,21 +1229,21 @@ function () { error = _regFn.error, page = _regFn.page; - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error, page: page }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error, page: page }); } catch (error) { - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error }); } @@ -1307,67 +1255,84 @@ function () { } }, { key: "prefetch", - value: function prefetch(route) { + value: function prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee2() { - var scriptRoute, cn; + var scriptRoute, url, cn; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: + _context2.next = 2; + return _this2.promisedBuildId; + + case 2: route = _this2.normalizeRoute(route); scriptRoute = (route === '/' ? '/index' : route) + ".js"; if (false) {} - if (!(_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route))) { - _context2.next = 5; + url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. + + if (!(document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route))) { + _context2.next = 8; break; } return _context2.abrupt("return"); - case 5: - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE - - + case 8: if (!(cn = navigator.connection)) { - _context2.next = 9; + _context2.next = 11; break; } if (!((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData)) { - _context2.next = 9; + _context2.next = 11; break; } return _context2.abrupt("return"); - case 9: + case 11: + if (!isDependency) { + getDependencies(route).forEach(function (url) { + _this2.prefetch(url, true); + }); + } // Feature detection is used to see if preload is supported + // If not fall back to loading script tags before the page is loaded + // https://caniuse.com/#feat=link-rel-preload + + if (!hasPreload) { - _context2.next = 14; + _context2.next = 15; break; } - _context2.next = 12; - return _this2.promisedBuildId; + preloadScript(url); + return _context2.abrupt("return"); + + case 15: + if (!isDependency) { + _context2.next = 17; + break; + } - case 12: - preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute); return _context2.abrupt("return"); - case 14: + case 17: if (!(document.readyState === 'complete')) { - _context2.next = 18; + _context2.next = 21; break; } return _context2.abrupt("return", _this2.loadPage(route)["catch"](function () {})); - case 18: + case 21: return _context2.abrupt("return", new _promise["default"](function (resolve) { window.addEventListener('load', function () { _this2.loadPage(route).then(function () { @@ -1378,7 +1343,7 @@ function () { }); })); - case 19: + case 22: case "end": return _context2.stop(); } ```
ijjk commented 5 years ago

Stats from current PR

Click to expand stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 22.5s | 21.4s | -1.2s | | `node_modules` Size | 43.6 MB | 43.6 MB | -1.62 kB | | Total Bundle (main, webpack, commons) Size | 207 kB | 206 kB | -460 B | | Total Bundle (main, webpack, commons) gzip Size | 68.1 kB | 68 kB | -130 B | | Total Bundle (main, webpack, commons) Modern Size | 181 kB | 181 kB | -482 B | | Total Bundle (main, webpack, commons) Modern gzip Size | 59.9 kB | 59.7 kB | -152 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_app` Modern Size | 1.83 kB | 1.83 kB | ✓ | | Client `_app` gzip Modern Size | 890 B | 890 B | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `_error` Modern Size | 5.85 kB | 5.85 kB | ✓ | | Client `_error` gzip Modern Size | 2.33 kB | 2.33 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/index` Modern Size | 319 B | 319 B | ✓ | | Client `pages/index` gzip Modern Size | 254 B | 254 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/link` Modern Size | 3.7 kB | 3.7 kB | ✓ | | Client `pages/link` gzip Modern Size | 1.7 kB | 1.7 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/routerDirect` Modern Size | 411 B | 411 B | ✓ | | Client `pages/routerDirect` gzip Modern Size | 314 B | 314 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `pages/withRouter` Modern Size | 423 B | 423 B | ✓ | | Client `pages/withRouter` gzip Modern Size | 309 B | 309 B | ✓ | | Client `main` Size | 15.8 kB | 15.7 kB | -99 B | | Client `main` gzip Size | 5.46 kB | 5.52 kB | ⚠️ +60 B | | Client `main` Modern Size | 12.8 kB | 12.6 kB | -278 B | | Client `main` Modern gzip Size | 4.83 kB | 4.8 kB | -34 B | | Client `commons` Size | 188 kB | 188 kB | -361 B | | Client `commons` gzip Size | 61.3 kB | 61.1 kB | -190 B | | Client `commons` Modern Size | 169 kB | 168 kB | -204 B | | Client `commons` Modern gzip Size | 55.1 kB | 54.9 kB | -118 B | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Client `webpack` Modern Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` Modern gzip Size | 785 B | 785 B | ✓ | | Base Rendered Size | 2.76 kB | 2.76 kB | ✓ | | Build Dir Size | 1.39 MB | 1.39 MB | -465 B |
Click to expand serverless stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 22.7s | 23.1s | ⚠️ +466ms | | `node_modules` Size | 43.6 MB | 43.6 MB | -1.62 kB | | Total Bundle (main, webpack, commons) Size | 207 kB | 206 kB | -460 B | | Total Bundle (main, webpack, commons) gzip Size | 68.1 kB | 68 kB | -132 B | | Total Bundle (main, webpack, commons) Modern Size | 181 kB | 181 kB | -482 B | | Total Bundle (main, webpack, commons) Modern gzip Size | 59.9 kB | 59.7 kB | -152 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | -1 B | | Client `_app` Modern Size | 1.83 kB | 1.83 kB | ✓ | | Client `_app` gzip Modern Size | 890 B | 890 B | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `_error` Modern Size | 5.85 kB | 5.85 kB | ✓ | | Client `_error` gzip Modern Size | 2.33 kB | 2.33 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/index` Modern Size | 319 B | 319 B | ✓ | | Client `pages/index` gzip Modern Size | 254 B | 254 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/link` Modern Size | 3.7 kB | 3.7 kB | ✓ | | Client `pages/link` gzip Modern Size | 1.7 kB | 1.7 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/routerDirect` Modern Size | 411 B | 411 B | ✓ | | Client `pages/routerDirect` gzip Modern Size | 314 B | 314 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 300 B | -1 B | | Client `pages/withRouter` Modern Size | 423 B | 423 B | ✓ | | Client `pages/withRouter` gzip Modern Size | 309 B | 309 B | ✓ | | Client `main` Size | 15.8 kB | 15.7 kB | -99 B | | Client `main` gzip Size | 5.46 kB | 5.52 kB | ⚠️ +59 B | | Client `main` Modern Size | 12.8 kB | 12.6 kB | -278 B | | Client `main` Modern gzip Size | 4.83 kB | 4.8 kB | -34 B | | Client `commons` Size | 188 kB | 188 kB | -361 B | | Client `commons` gzip Size | 61.3 kB | 61.1 kB | -190 B | | Client `commons` Modern Size | 169 kB | 168 kB | -204 B | | Client `commons` Modern gzip Size | 55.1 kB | 54.9 kB | -118 B | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Client `webpack` Modern Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` Modern gzip Size | 785 B | 785 B | ✓ | | Serverless `pages/link` Size | 255 kB | 254 kB | -935 B | | Serverless `pages/link` gzip Size | 68.5 kB | 68.2 kB | -340 B | | Serverless `pages/index` Size | 247 kB | 247 kB | -935 B | | Serverless `pages/index` gzip Size | 66.3 kB | 66 kB | -346 B | | Serverless `pages/_error` Size | 247 kB | 246 kB | -935 B | | Serverless `pages/_error` gzip Size | 66.1 kB | 65.7 kB | -340 B | | Serverless `pages/routerDirect` Size | 248 kB | 247 kB | -935 B | | Serverless `pages/routerDirect` gzip Size | 66.3 kB | 65.9 kB | -343 B | | Serverless `pages/withRouter` Size | 248 kB | 247 kB | -935 B | | Serverless `pages/withRouter` gzip Size | 66.4 kB | 66 kB | -341 B | | Build Dir Size | 2.59 MB | 2.58 MB | -6.6 kB |
Diff for main.js ```diff @@ -1,20 +1,5 @@ (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), - /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,28 +54,6 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; - -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); - - -/***/ }), - /***/ "BMP1": /***/ (function(module, exports, __webpack_require__) { @@ -503,7 +466,7 @@ function () { var _ref2 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee(_temp) { - var _ref, passedWebpackHMR, initialErr, _require, isValidElementType, renderCtx, appCtx; + var _ref, passedWebpackHMR, initialErr, _require, isValidElementType; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { @@ -584,41 +547,16 @@ function () { }); } }); - renderCtx = { + render({ App: App, Component: Component, props: props, err: initialErr, emitter: emitter - }; - render(renderCtx); - - if (!(window.__NEXT_DATA__.skeleton && Component.getInitialProps)) { - _context.next = 32; - break; - } - - appCtx = { - router: router, - AppTree: wrapApp(App), - Component: Component, - ctx: { - pathname: page, - asPath: asPath, - query: query - } - }; - _context.next = 30; - return App.getInitialProps(appCtx); - - case 30: - props.pageProps = _context.sent.pageProps; - render(renderCtx); - - case 32: + }); return _context.abrupt("return", emitter); - case 33: + case 26: case "end": return _context.stop(); } @@ -919,15 +857,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -995,17 +924,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -1083,22 +1001,6 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { @@ -1122,12 +1024,10 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ +/* global document, window */ function supportsPreload(el) { @@ -1157,13 +1057,31 @@ function () { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set["default"](); this.pageRegisterEvents = (0, _mitt["default"])(); this.loadingRoutes = {}; this.promisedBuildId = _promise["default"].resolve(); - } + this.promisedBuildManifest = new _promise["default"](function (resolve) { + if (window.__BUILD_MANIFEST) { + resolve(window.__BUILD_MANIFEST); + } else { + window.__BUILD_MANIFEST_CB = function () { + resolve(window.__BUILD_MANIFEST); + }; + } + }); + } // Returns a promise for the dependencies for a particular route + (0, _createClass2["default"])(PageLoader, [{ + key: "getDependencies", + value: function getDependencies(route) { + return this.promisedBuildManifest.then(function (man) { + return man[route] && man[route].map(function (url) { + return "/_next/" + url; + }) || []; + }); + } + }, { key: "normalizeRoute", value: function normalizeRoute(route) { if (route[0] !== '/') { @@ -1213,13 +1131,20 @@ function () { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!_this3.loadingRoutes[route]) { - _this3.loadScript(route); + _this3.getDependencies(route).then(function (deps) { + deps.forEach(function (d) { + if (!document.querySelector("script[src^=\"" + d + "\"]")) { + _this3.loadScript(d, route, false); + } + }); + + _this3.loadRoute(route); - _this3.loadingRoutes[route] = true; + _this3.loadingRoutes[route] = true; + }); } }); } @@ -1249,14 +1174,14 @@ function () { }); } }, { - key: "loadScript", - value: function loadScript(route) { + key: "loadRoute", + value: function loadRoute(route) { var _this = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee() { - var scriptRoute, script, url; + var scriptRoute, url; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { @@ -1267,41 +1192,51 @@ function () { case 2: route = _this.normalizeRoute(route); scriptRoute = route === '/' ? '/index.js' : route + ".js"; - script = document.createElement('script'); - - if ( true && 'noModule' in script) { - script.type = 'module'; - scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); - } - url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = "anonymous"; - script.src = url; - script.onerror = function () { - var error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; + _this.loadScript(url, route, true); - _this.pageRegisterEvents.emit(route, { - error: error - }); - }; - - document.body.appendChild(script); - - case 11: + case 6: case "end": return _context.stop(); } } }, _callee); }))(); + } + }, { + key: "loadScript", + value: function loadScript(url, route, isPage) { + var _this5 = this; + + var script = document.createElement('script'); + + if ( true && 'noModule' in script) { + script.type = 'module'; // Only page bundle scripts need to have .module added to url, + // dependencies already have it added during build manifest creation + + if (isPage) url = url.replace(/\.js$/, '.module.js'); + } + + script.crossOrigin = "anonymous"; + script.src = url; + + script.onerror = function () { + var error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + + _this5.pageRegisterEvents.emit(route, { + error: error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. }, { key: "registerPage", value: function registerPage(route, regFn) { - var _this5 = this; + var _this6 = this; var register = function register() { try { @@ -1309,21 +1244,21 @@ function () { error = _regFn.error, page = _regFn.page; - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error, page: page }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error, page: page }); } catch (error) { - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error }); } @@ -1335,17 +1270,21 @@ function () { } }, { key: "prefetch", - value: function prefetch(route) { + value: function prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee2() { - var scriptRoute, cn; + var scriptRoute, url, cn; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: + _context2.next = 2; + return _this2.promisedBuildId; + + case 2: route = _this2.normalizeRoute(route); scriptRoute = (route === '/' ? '/index' : route) + ".js"; @@ -1353,51 +1292,72 @@ function () { scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); } - if (!(_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route))) { - _context2.next = 5; + url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. + + if (!(document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route))) { + _context2.next = 8; break; } return _context2.abrupt("return"); - case 5: - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE - - + case 8: if (!(cn = navigator.connection)) { - _context2.next = 9; + _context2.next = 11; break; } if (!((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData)) { - _context2.next = 9; + _context2.next = 11; break; } return _context2.abrupt("return"); - case 9: + case 11: + if (isDependency) { + _context2.next = 17; + break; + } + + ; + _context2.next = 15; + return _this2.getDependencies(route); + + case 15: + _context2.t0 = function (url) { + _this2.prefetch(url, true); + }; + + _context2.sent.forEach(_context2.t0); + + case 17: if (!hasPreload) { - _context2.next = 14; + _context2.next = 20; break; } - _context2.next = 12; - return _this2.promisedBuildId; + preloadScript(url); + return _context2.abrupt("return"); + + case 20: + if (!isDependency) { + _context2.next = 22; + break; + } - case 12: - preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute); return _context2.abrupt("return"); - case 14: + case 22: if (!(document.readyState === 'complete')) { - _context2.next = 18; + _context2.next = 26; break; } return _context2.abrupt("return", _this2.loadPage(route)["catch"](function () {})); - case 18: + case 26: return _context2.abrupt("return", new _promise["default"](function (resolve) { window.addEventListener('load', function () { _this2.loadPage(route).then(function () { @@ -1408,7 +1368,7 @@ function () { }); })); - case 19: + case 27: case "end": return _context2.stop(); } ```
Diff for commons.js ```diff @@ -3563,7 +3563,7 @@ function () { var _getInitialProps = (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee2(Component, ctx) { - var cancelled, cancel, App, props, url, res, err; + var cancelled, cancel, App, props, err; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { @@ -3576,59 +3576,7 @@ function () { this.clc = cancel; App = this.components['/_app'].Component; - - if (!Component.__NEXT_PRERENDER) { - _context2.next = 20; - break; - } - - url = url_1.format({ - pathname: ctx.asPath, - query: ctx.query - }); - _context2.next = 8; - return fetch(url, { - headers: { - 'content-type': 'application/json' - } - }); - - case 8: - res = _context2.sent; - - if (!res.ok) { - _context2.next = 15; - break; - } - - _context2.next = 12; - return res.json()["catch"](function (err) { - return { - error: err.message - }; - }); - - case 12: - _context2.t0 = _context2.sent; - _context2.next = 16; - break; - - case 15: - _context2.t0 = { - error: 'failed to load prerender', - statusCode: res.status - }; - - case 16: - _context2.t1 = _context2.t0; - props = { - pageProps: _context2.t1 - }; - _context2.next = 23; - break; - - case 20: - _context2.next = 22; + _context2.next = 6; return utils_1.loadGetInitialProps(App, { AppTree: this._wrapApp(App), Component: Component, @@ -3636,16 +3584,15 @@ function () { ctx: ctx }); - case 22: + case 6: props = _context2.sent; - case 23: if (cancel === this.clc) { this.clc = null; } if (!cancelled) { - _context2.next = 28; + _context2.next = 12; break; } @@ -3653,10 +3600,10 @@ function () { err.cancelled = true; throw err; - case 28: + case 12: return _context2.abrupt("return", props); - case 29: + case 13: case "end": return _context2.stop(); } @@ -6737,7 +6684,8 @@ var singletonRouter = { } }; // Create public properties and methods of the router in the singletonRouter -var urlPropertyFields = ['pathname', 'route', 'query', 'asPath', 'components']; +var urlPropertyFields = ['pathname', 'route', 'query', 'asPath']; +var propertyFields = ['components']; var routerEvents = ['routeChangeStart', 'beforeHistoryChange', 'routeChangeComplete', 'routeChangeError', 'hashChangeStart', 'hashChangeComplete']; var coreMethodFields = ['push', 'replace', 'reload', 'back', 'prefetch', 'beforePopState']; // Events is a static property on the router, the router doesn't have to be initialized to use it @@ -6746,7 +6694,7 @@ var coreMethodFields = ['push', 'replace', 'reload', 'back', 'prefetch', 'before return _router2["default"].events; } }); -urlPropertyFields.forEach(function (field) { +propertyFields.concat(urlPropertyFields).forEach(function (field) { // Here we need to use Object.defineProperty because, we need to return // the property assigned to the actual router // The value might get changed as we change routes and this is the @@ -6845,6 +6793,17 @@ function makePublicRouterInstance(router) { instance.events = _router2["default"].events; + propertyFields.forEach(function (field) { + // Here we need to use Object.defineProperty because, we need to return + // the property assigned to the actual router + // The value might get changed as we change routes and this is the + // proper way to access it + (0, _defineProperty["default"])(instance, field, { + get: function get() { + return _router[field]; + } + }); + }); coreMethodFields.forEach(function (field) { instance[field] = function () { return _router[field].apply(_router, arguments); ```
Diff for mainModern.js ```diff @@ -1,20 +1,5 @@ (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), - /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,28 +54,6 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; - -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); - - -/***/ }), - /***/ "BMP1": /***/ (function(module, exports, __webpack_require__) { @@ -495,30 +458,13 @@ function () { }); } }); - const renderCtx = { + render({ App, Component, props, err: initialErr, emitter - }; - render(renderCtx); - - if (window.__NEXT_DATA__.skeleton && Component.getInitialProps) { - const appCtx = { - router, - AppTree: wrapApp(App), - Component: Component, - ctx: { - pathname: page, - asPath, - query - } - }; - props.pageProps = (yield App.getInitialProps(appCtx)).pageProps; - render(renderCtx); - } - + }); return emitter; }); @@ -729,15 +675,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -792,17 +729,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -878,22 +804,6 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { @@ -909,12 +819,10 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ +/* global document, window */ function supportsPreload(el) { @@ -941,10 +849,23 @@ class PageLoader { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set.default(); this.pageRegisterEvents = (0, _mitt.default)(); this.loadingRoutes = {}; this.promisedBuildId = _promise.default.resolve(); + this.promisedBuildManifest = new _promise.default(resolve => { + if (window.__BUILD_MANIFEST) { + resolve(window.__BUILD_MANIFEST); + } else { + window.__BUILD_MANIFEST_CB = () => { + resolve(window.__BUILD_MANIFEST); + }; + } + }); + } // Returns a promise for the dependencies for a particular route + + + getDependencies(route) { + return this.promisedBuildManifest.then(man => man[route] && man[route].map(url => "/_next/" + url) || []); } normalizeRoute(route) { @@ -993,12 +914,18 @@ class PageLoader { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!this.loadingRoutes[route]) { - this.loadScript(route); - this.loadingRoutes[route] = true; + this.getDependencies(route).then(deps => { + deps.forEach(d => { + if (!document.querySelector("script[src^=\"" + d + "\"]")) { + this.loadScript(d, route, false); + } + }); + this.loadRoute(route); + this.loadingRoutes[route] = true; + }); } }); } @@ -1023,35 +950,41 @@ class PageLoader { }); } - loadScript(route) { + loadRoute(route) { var _this = this; return (0, _asyncToGenerator2.default)(function* () { yield _this.promisedBuildId; route = _this.normalizeRoute(route); let scriptRoute = route === '/' ? '/index.js' : route + ".js"; - const script = document.createElement('script'); + const url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - if ( true && 'noModule' in script) { - script.type = 'module'; - scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); - } + _this.loadScript(url, route, true); + })(); + } - const url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = "anonymous"; - script.src = url; + loadScript(url, route, isPage) { + const script = document.createElement('script'); - script.onerror = () => { - const error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; + if ( true && 'noModule' in script) { + script.type = 'module'; // Only page bundle scripts need to have .module added to url, + // dependencies already have it added during build manifest creation - _this.pageRegisterEvents.emit(route, { - error - }); - }; + if (isPage) url = url.replace(/\.js$/, '.module.js'); + } - document.body.appendChild(script); - })(); + script.crossOrigin = "anonymous"; + script.src = url; + + script.onerror = () => { + const error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + this.pageRegisterEvents.emit(route, { + error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. @@ -1085,10 +1018,11 @@ class PageLoader { register(); } - prefetch(route) { + prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2.default)(function* () { + yield _this2.promisedBuildId; route = _this2.normalizeRoute(route); let scriptRoute = (route === '/' ? '/index' : route) + ".js"; @@ -1096,11 +1030,12 @@ class PageLoader { scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); } - if (_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route)) { - return; - } + const url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE + if (document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route)) { + return; + } // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE let cn; @@ -1110,14 +1045,26 @@ class PageLoader { if ((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData) { return; } + } + + if (!isDependency) { + ; + (yield _this2.getDependencies(route)).forEach(url => { + _this2.prefetch(url, true); + }); } // Feature detection is used to see if preload is supported // If not fall back to loading script tags before the page is loaded // https://caniuse.com/#feat=link-rel-preload if (hasPreload) { - yield _this2.promisedBuildId; - preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute); + preloadScript(url); + return; + } + + if (isDependency) { + // loadPage will automatically handle depencies, so no need to + // preload them manually return; } ```
Diff for commonsModern.js ```diff @@ -2989,34 +2989,12 @@ class Router { const { Component: App } = this.components['/_app']; - let props; - - if (Component.__NEXT_PRERENDER) { - const url = url_1.format({ - pathname: ctx.asPath, - query: ctx.query - }); - const res = await fetch(url, { - headers: { - 'content-type': 'application/json' - } - }); - props = { - pageProps: res.ok ? await res.json().catch(err => ({ - error: err.message - })) : { - error: 'failed to load prerender', - statusCode: res.status - } - }; - } else { - props = await utils_1.loadGetInitialProps(App, { - AppTree: this._wrapApp(App), - Component, - router: this, - ctx - }); - } + const props = await utils_1.loadGetInitialProps(App, { + AppTree: this._wrapApp(App), + Component, + router: this, + ctx + }); if (cancel === this.clc) { this.clc = null; @@ -4885,7 +4863,8 @@ const singletonRouter = { }; // Create public properties and methods of the router in the singletonRouter -const urlPropertyFields = ['pathname', 'route', 'query', 'asPath', 'components']; +const urlPropertyFields = ['pathname', 'route', 'query', 'asPath']; +const propertyFields = ['components']; const routerEvents = ['routeChangeStart', 'beforeHistoryChange', 'routeChangeComplete', 'routeChangeError', 'hashChangeStart', 'hashChangeComplete']; const coreMethodFields = ['push', 'replace', 'reload', 'back', 'prefetch', 'beforePopState']; // Events is a static property on the router, the router doesn't have to be initialized to use it @@ -4895,7 +4874,7 @@ const coreMethodFields = ['push', 'replace', 'reload', 'back', 'prefetch', 'befo } }); -urlPropertyFields.forEach(field => { +propertyFields.concat(urlPropertyFields).forEach(field => { // Here we need to use Object.defineProperty because, we need to return // the property assigned to the actual router // The value might get changed as we change routes and this is the @@ -4991,6 +4970,18 @@ function makePublicRouterInstance(router) { instance.events = _router2.default.events; + propertyFields.forEach(field => { + // Here we need to use Object.defineProperty because, we need to return + // the property assigned to the actual router + // The value might get changed as we change routes and this is the + // proper way to access it + (0, _defineProperty.default)(instance, field, { + get() { + return _router[field]; + } + + }); + }); coreMethodFields.forEach(field => { instance[field] = function () { return _router[field](...arguments); ```
ijjk commented 5 years ago

Stats from current PR

Click to expand stats ⚠️ Total Bundle Size Increase ⚠️ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 22.5s | 22.4s | -86ms | | `node_modules` Size | 43.6 MB | 43.6 MB | -1.28 kB | | Total Bundle (main, webpack, commons) Size | 207 kB | 208 kB | ⚠️ +1.36 kB | | Total Bundle (main, webpack, commons) gzip Size | 68.1 kB | 68.6 kB | ⚠️ +506 B | | Total Bundle (main, webpack, commons) Modern Size | 181 kB | 183 kB | ⚠️ +1.34 kB | | Total Bundle (main, webpack, commons) Modern gzip Size | 59.9 kB | 60.4 kB | ⚠️ +479 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_app` Modern Size | 1.83 kB | 1.83 kB | ✓ | | Client `_app` gzip Modern Size | 890 B | 890 B | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `_error` Modern Size | 5.85 kB | 5.85 kB | ✓ | | Client `_error` gzip Modern Size | 2.33 kB | 2.33 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/index` Modern Size | 319 B | 319 B | ✓ | | Client `pages/index` gzip Modern Size | 254 B | 254 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/link` Modern Size | 3.7 kB | 3.7 kB | ✓ | | Client `pages/link` gzip Modern Size | 1.7 kB | 1.7 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/routerDirect` Modern Size | 411 B | 411 B | ✓ | | Client `pages/routerDirect` gzip Modern Size | 314 B | 314 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `pages/withRouter` Modern Size | 423 B | 423 B | ✓ | | Client `pages/withRouter` gzip Modern Size | 309 B | 309 B | ✓ | | Client `main` Size | 15.8 kB | 17.5 kB | ⚠️ +1.72 kB | | Client `main` gzip Size | 5.46 kB | 6.15 kB | ⚠️ +696 B | | Client `main` Modern Size | 12.8 kB | 14.4 kB | ⚠️ +1.55 kB | | Client `main` Modern gzip Size | 4.83 kB | 5.43 kB | ⚠️ +597 B | | Client `commons` Size | 188 kB | 188 kB | -361 B | | Client `commons` gzip Size | 61.3 kB | 61.1 kB | -190 B | | Client `commons` Modern Size | 169 kB | 168 kB | -204 B | | Client `commons` Modern gzip Size | 55.1 kB | 54.9 kB | -118 B | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Client `webpack` Modern Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` Modern gzip Size | 785 B | 785 B | ✓ | | Base Rendered Size | 2.76 kB | 2.76 kB | ✓ | | Build Dir Size | 1.39 MB | 1.4 MB | ⚠️ +9.17 kB |
Click to expand serverless stats ⚠️ Total Bundle Size Increase ⚠️ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 23.9s | 24s | ⚠️ +92ms | | `node_modules` Size | 43.6 MB | 43.6 MB | -1.28 kB | | Total Bundle (main, webpack, commons) Size | 207 kB | 208 kB | ⚠️ +1.36 kB | | Total Bundle (main, webpack, commons) gzip Size | 68.1 kB | 68.6 kB | ⚠️ +506 B | | Total Bundle (main, webpack, commons) Modern Size | 181 kB | 183 kB | ⚠️ +1.34 kB | | Total Bundle (main, webpack, commons) Modern gzip Size | 59.9 kB | 60.4 kB | ⚠️ +479 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_app` Modern Size | 1.83 kB | 1.83 kB | ✓ | | Client `_app` gzip Modern Size | 890 B | 890 B | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `_error` Modern Size | 5.85 kB | 5.85 kB | ✓ | | Client `_error` gzip Modern Size | 2.33 kB | 2.33 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/index` Modern Size | 319 B | 319 B | ✓ | | Client `pages/index` gzip Modern Size | 254 B | 254 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/link` Modern Size | 3.7 kB | 3.7 kB | ✓ | | Client `pages/link` gzip Modern Size | 1.7 kB | 1.7 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/routerDirect` Modern Size | 411 B | 411 B | ✓ | | Client `pages/routerDirect` gzip Modern Size | 314 B | 314 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `pages/withRouter` Modern Size | 423 B | 423 B | ✓ | | Client `pages/withRouter` gzip Modern Size | 309 B | 309 B | ✓ | | Client `main` Size | 15.8 kB | 17.5 kB | ⚠️ +1.72 kB | | Client `main` gzip Size | 5.46 kB | 6.15 kB | ⚠️ +696 B | | Client `main` Modern Size | 12.8 kB | 14.4 kB | ⚠️ +1.55 kB | | Client `main` Modern gzip Size | 4.83 kB | 5.43 kB | ⚠️ +597 B | | Client `commons` Size | 188 kB | 188 kB | -361 B | | Client `commons` gzip Size | 61.3 kB | 61.1 kB | -190 B | | Client `commons` Modern Size | 169 kB | 168 kB | -204 B | | Client `commons` Modern gzip Size | 55.1 kB | 54.9 kB | -118 B | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Client `webpack` Modern Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` Modern gzip Size | 785 B | 785 B | ✓ | | Serverless `pages/link` Size | 255 kB | 254 kB | -935 B | | Serverless `pages/link` gzip Size | 68.5 kB | 68.2 kB | -342 B | | Serverless `pages/index` Size | 247 kB | 247 kB | -935 B | | Serverless `pages/index` gzip Size | 66.3 kB | 66 kB | -347 B | | Serverless `pages/_error` Size | 247 kB | 246 kB | -935 B | | Serverless `pages/_error` gzip Size | 66.1 kB | 65.7 kB | -342 B | | Serverless `pages/routerDirect` Size | 248 kB | 247 kB | -935 B | | Serverless `pages/routerDirect` gzip Size | 66.3 kB | 65.9 kB | -345 B | | Serverless `pages/withRouter` Size | 248 kB | 247 kB | -935 B | | Serverless `pages/withRouter` gzip Size | 66.4 kB | 66 kB | -340 B | | Build Dir Size | 2.59 MB | 2.59 MB | ⚠️ +3.04 kB |
Diff for main.js ```diff @@ -1,20 +1,5 @@ (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), - /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,24 +54,193 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { +/***/ "8oxB": +/***/ (function(module, exports) { -"use strict"; +// shim for using process in browser +var process = module.exports = {}; -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); +var cachedSetTimeout; +var cachedClearTimeout; + +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); +} +function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); +} +(function () { + try { + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; + } + } catch (e) { + cachedSetTimeout = defaultSetTimout; + } + try { + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; + } else { + cachedClearTimeout = defaultClearTimeout; + } + } catch (e) { + cachedClearTimeout = defaultClearTimeout; + } +} ()) +function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); + } + } + + +} +function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); + } + } + + + +} +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; + +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} + +function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + runClearTimeout(timeout); +} + +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } +}; + +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; +process.prependListener = noop; +process.prependOnceListener = noop; + +process.listeners = function (name) { return [] } + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; /***/ }), @@ -503,7 +657,7 @@ function () { var _ref2 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee(_temp) { - var _ref, passedWebpackHMR, initialErr, _require, isValidElementType, renderCtx, appCtx; + var _ref, passedWebpackHMR, initialErr, _require, isValidElementType; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { @@ -584,41 +738,16 @@ function () { }); } }); - renderCtx = { + render({ App: App, Component: Component, props: props, err: initialErr, emitter: emitter - }; - render(renderCtx); - - if (!(window.__NEXT_DATA__.skeleton && Component.getInitialProps)) { - _context.next = 32; - break; - } - - appCtx = { - router: router, - AppTree: wrapApp(App), - Component: Component, - ctx: { - pathname: page, - asPath: asPath, - query: query - } - }; - _context.next = 30; - return App.getInitialProps(appCtx); - - case 30: - props.pageProps = _context.sent.pageProps; - render(renderCtx); - - case 32: + }); return _context.abrupt("return", emitter); - case 33: + case 26: case "end": return _context.stop(); } @@ -919,15 +1048,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -995,17 +1115,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -1083,27 +1192,11 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { "use strict"; - +/* WEBPACK VAR INJECTION */(function(process) { var _interopRequireDefault2 = __webpack_require__("KI45"); @@ -1122,12 +1215,10 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ +/* global document, window */ function supportsPreload(el) { @@ -1157,13 +1248,31 @@ function () { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set["default"](); this.pageRegisterEvents = (0, _mitt["default"])(); this.loadingRoutes = {}; this.promisedBuildId = _promise["default"].resolve(); - } + this.promisedBuildManifest = new _promise["default"](function (resolve) { + if (window.__BUILD_MANIFEST) { + resolve(window.__BUILD_MANIFEST); + } else { + window.__BUILD_MANIFEST_CB = function () { + resolve(window.__BUILD_MANIFEST); + }; + } + }); + } // Returns a promise for the dependencies for a particular route + (0, _createClass2["default"])(PageLoader, [{ + key: "getDependencies", + value: function getDependencies(route) { + return this.promisedBuildManifest.then(function (man) { + return man[route] && man[route].map(function (url) { + return "/_next/" + url; + }) || []; + }); + } + }, { key: "normalizeRoute", value: function normalizeRoute(route) { if (route[0] !== '/') { @@ -1213,13 +1322,26 @@ function () { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!_this3.loadingRoutes[route]) { - _this3.loadScript(route); + if (process.env.__NEXT_GRANULAR_CHUNKS) { + _this3.getDependencies(route).then(function (deps) { + deps.forEach(function (d) { + if (!document.querySelector("script[src^=\"" + d + "\"]")) { + _this3.loadScript(d, route, false); + } + }); + + _this3.loadRoute(route); + + _this3.loadingRoutes[route] = true; + }); + } else { + _this3.loadRoute(route); - _this3.loadingRoutes[route] = true; + _this3.loadingRoutes[route] = true; + } } }); } @@ -1249,14 +1371,14 @@ function () { }); } }, { - key: "loadScript", - value: function loadScript(route) { + key: "loadRoute", + value: function loadRoute(route) { var _this = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee() { - var scriptRoute, script, url; + var scriptRoute, url; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { @@ -1267,41 +1389,51 @@ function () { case 2: route = _this.normalizeRoute(route); scriptRoute = route === '/' ? '/index.js' : route + ".js"; - script = document.createElement('script'); - - if ( true && 'noModule' in script) { - script.type = 'module'; - scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); - } - url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = "anonymous"; - script.src = url; - - script.onerror = function () { - var error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; - - _this.pageRegisterEvents.emit(route, { - error: error - }); - }; - document.body.appendChild(script); + _this.loadScript(url, route, true); - case 11: + case 6: case "end": return _context.stop(); } } }, _callee); }))(); + } + }, { + key: "loadScript", + value: function loadScript(url, route, isPage) { + var _this5 = this; + + var script = document.createElement('script'); + + if ( true && 'noModule' in script) { + script.type = 'module'; // Only page bundle scripts need to have .module added to url, + // dependencies already have it added during build manifest creation + + if (isPage) url = url.replace(/\.js$/, '.module.js'); + } + + script.crossOrigin = "anonymous"; + script.src = url; + + script.onerror = function () { + var error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + + _this5.pageRegisterEvents.emit(route, { + error: error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. }, { key: "registerPage", value: function registerPage(route, regFn) { - var _this5 = this; + var _this6 = this; var register = function register() { try { @@ -1309,21 +1441,21 @@ function () { error = _regFn.error, page = _regFn.page; - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error, page: page }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error, page: page }); } catch (error) { - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error }); } @@ -1335,17 +1467,21 @@ function () { } }, { key: "prefetch", - value: function prefetch(route) { + value: function prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee2() { - var scriptRoute, cn; + var scriptRoute, url, cn; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: + _context2.next = 2; + return _this2.promisedBuildId; + + case 2: route = _this2.normalizeRoute(route); scriptRoute = (route === '/' ? '/index' : route) + ".js"; @@ -1353,51 +1489,72 @@ function () { scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); } - if (!(_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route))) { - _context2.next = 5; + url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. + + if (!(document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route))) { + _context2.next = 8; break; } return _context2.abrupt("return"); - case 5: - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE - - + case 8: if (!(cn = navigator.connection)) { - _context2.next = 9; + _context2.next = 11; break; } if (!((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData)) { - _context2.next = 9; + _context2.next = 11; break; } return _context2.abrupt("return"); - case 9: + case 11: + if (!(process.env.__NEXT_GRANULAR_CHUNKS && !isDependency)) { + _context2.next = 17; + break; + } + + ; + _context2.next = 15; + return _this2.getDependencies(route); + + case 15: + _context2.t0 = function (url) { + _this2.prefetch(url, true); + }; + + _context2.sent.forEach(_context2.t0); + + case 17: if (!hasPreload) { - _context2.next = 14; + _context2.next = 20; break; } - _context2.next = 12; - return _this2.promisedBuildId; + preloadScript(url); + return _context2.abrupt("return"); + + case 20: + if (!isDependency) { + _context2.next = 22; + break; + } - case 12: - preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute); return _context2.abrupt("return"); - case 14: + case 22: if (!(document.readyState === 'complete')) { - _context2.next = 18; + _context2.next = 26; break; } return _context2.abrupt("return", _this2.loadPage(route)["catch"](function () {})); - case 18: + case 26: return _context2.abrupt("return", new _promise["default"](function (resolve) { window.addEventListener('load', function () { _this2.loadPage(route).then(function () { @@ -1408,7 +1565,7 @@ function () { }); })); - case 19: + case 27: case "end": return _context2.stop(); } @@ -1421,6 +1578,7 @@ function () { }(); exports["default"] = PageLoader; +/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__("8oxB"))) /***/ }) ```
Diff for commons.js ```diff @@ -3563,7 +3563,7 @@ function () { var _getInitialProps = (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee2(Component, ctx) { - var cancelled, cancel, App, props, url, res, err; + var cancelled, cancel, App, props, err; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { @@ -3576,59 +3576,7 @@ function () { this.clc = cancel; App = this.components['/_app'].Component; - - if (!Component.__NEXT_PRERENDER) { - _context2.next = 20; - break; - } - - url = url_1.format({ - pathname: ctx.asPath, - query: ctx.query - }); - _context2.next = 8; - return fetch(url, { - headers: { - 'content-type': 'application/json' - } - }); - - case 8: - res = _context2.sent; - - if (!res.ok) { - _context2.next = 15; - break; - } - - _context2.next = 12; - return res.json()["catch"](function (err) { - return { - error: err.message - }; - }); - - case 12: - _context2.t0 = _context2.sent; - _context2.next = 16; - break; - - case 15: - _context2.t0 = { - error: 'failed to load prerender', - statusCode: res.status - }; - - case 16: - _context2.t1 = _context2.t0; - props = { - pageProps: _context2.t1 - }; - _context2.next = 23; - break; - - case 20: - _context2.next = 22; + _context2.next = 6; return utils_1.loadGetInitialProps(App, { AppTree: this._wrapApp(App), Component: Component, @@ -3636,16 +3584,15 @@ function () { ctx: ctx }); - case 22: + case 6: props = _context2.sent; - case 23: if (cancel === this.clc) { this.clc = null; } if (!cancelled) { - _context2.next = 28; + _context2.next = 12; break; } @@ -3653,10 +3600,10 @@ function () { err.cancelled = true; throw err; - case 28: + case 12: return _context2.abrupt("return", props); - case 29: + case 13: case "end": return _context2.stop(); } @@ -6737,7 +6684,8 @@ var singletonRouter = { } }; // Create public properties and methods of the router in the singletonRouter -var urlPropertyFields = ['pathname', 'route', 'query', 'asPath', 'components']; +var urlPropertyFields = ['pathname', 'route', 'query', 'asPath']; +var propertyFields = ['components']; var routerEvents = ['routeChangeStart', 'beforeHistoryChange', 'routeChangeComplete', 'routeChangeError', 'hashChangeStart', 'hashChangeComplete']; var coreMethodFields = ['push', 'replace', 'reload', 'back', 'prefetch', 'beforePopState']; // Events is a static property on the router, the router doesn't have to be initialized to use it @@ -6746,7 +6694,7 @@ var coreMethodFields = ['push', 'replace', 'reload', 'back', 'prefetch', 'before return _router2["default"].events; } }); -urlPropertyFields.forEach(function (field) { +propertyFields.concat(urlPropertyFields).forEach(function (field) { // Here we need to use Object.defineProperty because, we need to return // the property assigned to the actual router // The value might get changed as we change routes and this is the @@ -6845,6 +6793,17 @@ function makePublicRouterInstance(router) { instance.events = _router2["default"].events; + propertyFields.forEach(function (field) { + // Here we need to use Object.defineProperty because, we need to return + // the property assigned to the actual router + // The value might get changed as we change routes and this is the + // proper way to access it + (0, _defineProperty["default"])(instance, field, { + get: function get() { + return _router[field]; + } + }); + }); coreMethodFields.forEach(function (field) { instance[field] = function () { return _router[field].apply(_router, arguments); ```
Diff for mainModern.js ```diff @@ -1,20 +1,5 @@ (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), - /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,24 +54,193 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { +/***/ "8oxB": +/***/ (function(module, exports) { -"use strict"; +// shim for using process in browser +var process = module.exports = {}; -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. + +var cachedSetTimeout; +var cachedClearTimeout; + +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); +} +function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); +} +(function () { + try { + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; + } + } catch (e) { + cachedSetTimeout = defaultSetTimout; + } + try { + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; + } else { + cachedClearTimeout = defaultClearTimeout; + } + } catch (e) { + cachedClearTimeout = defaultClearTimeout; + } +} ()) +function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); + } + } + + +} +function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); + } + } -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); + + +} +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; + +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} + +function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + runClearTimeout(timeout); +} + +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } +}; + +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; +process.prependListener = noop; +process.prependOnceListener = noop; + +process.listeners = function (name) { return [] } + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; /***/ }), @@ -495,30 +649,13 @@ function () { }); } }); - const renderCtx = { + render({ App, Component, props, err: initialErr, emitter - }; - render(renderCtx); - - if (window.__NEXT_DATA__.skeleton && Component.getInitialProps) { - const appCtx = { - router, - AppTree: wrapApp(App), - Component: Component, - ctx: { - pathname: page, - asPath, - query - } - }; - props.pageProps = (yield App.getInitialProps(appCtx)).pageProps; - render(renderCtx); - } - + }); return emitter; }); @@ -729,15 +866,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -792,17 +920,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -878,27 +995,11 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { "use strict"; - +/* WEBPACK VAR INJECTION */(function(process) { var _interopRequireDefault = __webpack_require__("KI45"); @@ -909,12 +1010,10 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ +/* global document, window */ function supportsPreload(el) { @@ -941,10 +1040,23 @@ class PageLoader { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set.default(); this.pageRegisterEvents = (0, _mitt.default)(); this.loadingRoutes = {}; this.promisedBuildId = _promise.default.resolve(); + this.promisedBuildManifest = new _promise.default(resolve => { + if (window.__BUILD_MANIFEST) { + resolve(window.__BUILD_MANIFEST); + } else { + window.__BUILD_MANIFEST_CB = () => { + resolve(window.__BUILD_MANIFEST); + }; + } + }); + } // Returns a promise for the dependencies for a particular route + + + getDependencies(route) { + return this.promisedBuildManifest.then(man => man[route] && man[route].map(url => "/_next/" + url) || []); } normalizeRoute(route) { @@ -993,12 +1105,23 @@ class PageLoader { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!this.loadingRoutes[route]) { - this.loadScript(route); - this.loadingRoutes[route] = true; + if (process.env.__NEXT_GRANULAR_CHUNKS) { + this.getDependencies(route).then(deps => { + deps.forEach(d => { + if (!document.querySelector("script[src^=\"" + d + "\"]")) { + this.loadScript(d, route, false); + } + }); + this.loadRoute(route); + this.loadingRoutes[route] = true; + }); + } else { + this.loadRoute(route); + this.loadingRoutes[route] = true; + } } }); } @@ -1023,35 +1146,41 @@ class PageLoader { }); } - loadScript(route) { + loadRoute(route) { var _this = this; return (0, _asyncToGenerator2.default)(function* () { yield _this.promisedBuildId; route = _this.normalizeRoute(route); let scriptRoute = route === '/' ? '/index.js' : route + ".js"; - const script = document.createElement('script'); + const url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - if ( true && 'noModule' in script) { - script.type = 'module'; - scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); - } + _this.loadScript(url, route, true); + })(); + } - const url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = "anonymous"; - script.src = url; + loadScript(url, route, isPage) { + const script = document.createElement('script'); - script.onerror = () => { - const error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; + if ( true && 'noModule' in script) { + script.type = 'module'; // Only page bundle scripts need to have .module added to url, + // dependencies already have it added during build manifest creation - _this.pageRegisterEvents.emit(route, { - error - }); - }; + if (isPage) url = url.replace(/\.js$/, '.module.js'); + } - document.body.appendChild(script); - })(); + script.crossOrigin = "anonymous"; + script.src = url; + + script.onerror = () => { + const error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + this.pageRegisterEvents.emit(route, { + error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. @@ -1085,10 +1214,11 @@ class PageLoader { register(); } - prefetch(route) { + prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2.default)(function* () { + yield _this2.promisedBuildId; route = _this2.normalizeRoute(route); let scriptRoute = (route === '/' ? '/index' : route) + ".js"; @@ -1096,11 +1226,12 @@ class PageLoader { scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); } - if (_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route)) { - return; - } + const url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE + if (document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route)) { + return; + } // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE let cn; @@ -1110,14 +1241,26 @@ class PageLoader { if ((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData) { return; } + } + + if (process.env.__NEXT_GRANULAR_CHUNKS && !isDependency) { + ; + (yield _this2.getDependencies(route)).forEach(url => { + _this2.prefetch(url, true); + }); } // Feature detection is used to see if preload is supported // If not fall back to loading script tags before the page is loaded // https://caniuse.com/#feat=link-rel-preload if (hasPreload) { - yield _this2.promisedBuildId; - preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute); + preloadScript(url); + return; + } + + if (isDependency) { + // loadPage will automatically handle depencies, so no need to + // preload them manually return; } @@ -1136,6 +1279,7 @@ class PageLoader { } exports.default = PageLoader; +/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__("8oxB"))) /***/ }) ```
Diff for commonsModern.js ```diff @@ -2989,34 +2989,12 @@ class Router { const { Component: App } = this.components['/_app']; - let props; - - if (Component.__NEXT_PRERENDER) { - const url = url_1.format({ - pathname: ctx.asPath, - query: ctx.query - }); - const res = await fetch(url, { - headers: { - 'content-type': 'application/json' - } - }); - props = { - pageProps: res.ok ? await res.json().catch(err => ({ - error: err.message - })) : { - error: 'failed to load prerender', - statusCode: res.status - } - }; - } else { - props = await utils_1.loadGetInitialProps(App, { - AppTree: this._wrapApp(App), - Component, - router: this, - ctx - }); - } + const props = await utils_1.loadGetInitialProps(App, { + AppTree: this._wrapApp(App), + Component, + router: this, + ctx + }); if (cancel === this.clc) { this.clc = null; @@ -4885,7 +4863,8 @@ const singletonRouter = { }; // Create public properties and methods of the router in the singletonRouter -const urlPropertyFields = ['pathname', 'route', 'query', 'asPath', 'components']; +const urlPropertyFields = ['pathname', 'route', 'query', 'asPath']; +const propertyFields = ['components']; const routerEvents = ['routeChangeStart', 'beforeHistoryChange', 'routeChangeComplete', 'routeChangeError', 'hashChangeStart', 'hashChangeComplete']; const coreMethodFields = ['push', 'replace', 'reload', 'back', 'prefetch', 'beforePopState']; // Events is a static property on the router, the router doesn't have to be initialized to use it @@ -4895,7 +4874,7 @@ const coreMethodFields = ['push', 'replace', 'reload', 'back', 'prefetch', 'befo } }); -urlPropertyFields.forEach(field => { +propertyFields.concat(urlPropertyFields).forEach(field => { // Here we need to use Object.defineProperty because, we need to return // the property assigned to the actual router // The value might get changed as we change routes and this is the @@ -4991,6 +4970,18 @@ function makePublicRouterInstance(router) { instance.events = _router2.default.events; + propertyFields.forEach(field => { + // Here we need to use Object.defineProperty because, we need to return + // the property assigned to the actual router + // The value might get changed as we change routes and this is the + // proper way to access it + (0, _defineProperty.default)(instance, field, { + get() { + return _router[field]; + } + + }); + }); coreMethodFields.forEach(field => { instance[field] = function () { return _router[field](...arguments); ```
atcastle commented 5 years ago

I increased the size limit back to 188, to account for some new conditionals I had to add, now that the build-manifest is blocking in granular chunks mode. These conditionals can be removed if granular chunks graduates to non-experimental, so we should be able to recoup the size increase.

ijjk commented 5 years ago

Stats from current PR

Click to expand stats ⚠️ Total Bundle Size Increase ⚠️ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 21.8s | 22s | ⚠️ +187ms | | `node_modules` Size | 43.6 MB | 43.6 MB | -22.3 kB | | Total Bundle (main, webpack, commons) Size | 207 kB | 208 kB | ⚠️ +1.29 kB | | Total Bundle (main, webpack, commons) gzip Size | 68.1 kB | 68.6 kB | ⚠️ +474 B | | Total Bundle (main, webpack, commons) Modern Size | 182 kB | 183 kB | ⚠️ +1.28 kB | | Total Bundle (main, webpack, commons) Modern gzip Size | 59.9 kB | 60.4 kB | ⚠️ +457 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_app` Modern Size | 1.83 kB | 1.83 kB | ✓ | | Client `_app` gzip Modern Size | 890 B | 890 B | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `_error` Modern Size | 5.85 kB | 5.85 kB | ✓ | | Client `_error` gzip Modern Size | 2.33 kB | 2.33 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/index` Modern Size | 319 B | 319 B | ✓ | | Client `pages/index` gzip Modern Size | 254 B | 254 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/link` Modern Size | 3.7 kB | 3.7 kB | ✓ | | Client `pages/link` gzip Modern Size | 1.7 kB | 1.7 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/routerDirect` Modern Size | 411 B | 411 B | ✓ | | Client `pages/routerDirect` gzip Modern Size | 314 B | 314 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `pages/withRouter` Modern Size | 423 B | 423 B | ✓ | | Client `pages/withRouter` gzip Modern Size | 309 B | 309 B | ✓ | | Client `main` Size | 15.8 kB | 17.5 kB | ⚠️ +1.72 kB | | Client `main` gzip Size | 5.46 kB | 6.15 kB | ⚠️ +696 B | | Client `main` Modern Size | 12.8 kB | 14.4 kB | ⚠️ +1.55 kB | | Client `main` Modern gzip Size | 4.83 kB | 5.43 kB | ⚠️ +597 B | | Client `commons` Size | 188 kB | 188 kB | -434 B | | Client `commons` gzip Size | 61.3 kB | 61.1 kB | -222 B | | Client `commons` Modern Size | 169 kB | 168 kB | -270 B | | Client `commons` Modern gzip Size | 55.1 kB | 54.9 kB | -140 B | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Client `webpack` Modern Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` Modern gzip Size | 785 B | 785 B | ✓ | | Base Rendered Size | 2.76 kB | 2.76 kB | ✓ | | Build Dir Size | 1.39 MB | 1.4 MB | ⚠️ +7.49 kB |
Click to expand serverless stats ⚠️ Total Bundle Size Increase ⚠️ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 23.5s | 23.4s | -79ms | | `node_modules` Size | 43.6 MB | 43.6 MB | -22.3 kB | | Total Bundle (main, webpack, commons) Size | 207 kB | 208 kB | ⚠️ +1.29 kB | | Total Bundle (main, webpack, commons) gzip Size | 68.1 kB | 68.6 kB | ⚠️ +474 B | | Total Bundle (main, webpack, commons) Modern Size | 182 kB | 183 kB | ⚠️ +1.28 kB | | Total Bundle (main, webpack, commons) Modern gzip Size | 59.9 kB | 60.4 kB | ⚠️ +457 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_app` Modern Size | 1.83 kB | 1.83 kB | ✓ | | Client `_app` gzip Modern Size | 890 B | 890 B | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `_error` Modern Size | 5.85 kB | 5.85 kB | ✓ | | Client `_error` gzip Modern Size | 2.33 kB | 2.33 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/index` Modern Size | 319 B | 319 B | ✓ | | Client `pages/index` gzip Modern Size | 254 B | 254 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/link` Modern Size | 3.7 kB | 3.7 kB | ✓ | | Client `pages/link` gzip Modern Size | 1.7 kB | 1.7 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/routerDirect` Modern Size | 411 B | 411 B | ✓ | | Client `pages/routerDirect` gzip Modern Size | 314 B | 314 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `pages/withRouter` Modern Size | 423 B | 423 B | ✓ | | Client `pages/withRouter` gzip Modern Size | 309 B | 309 B | ✓ | | Client `main` Size | 15.8 kB | 17.5 kB | ⚠️ +1.72 kB | | Client `main` gzip Size | 5.46 kB | 6.15 kB | ⚠️ +696 B | | Client `main` Modern Size | 12.8 kB | 14.4 kB | ⚠️ +1.55 kB | | Client `main` Modern gzip Size | 4.83 kB | 5.43 kB | ⚠️ +597 B | | Client `commons` Size | 188 kB | 188 kB | -434 B | | Client `commons` gzip Size | 61.3 kB | 61.1 kB | -222 B | | Client `commons` Modern Size | 169 kB | 168 kB | -270 B | | Client `commons` Modern gzip Size | 55.1 kB | 54.9 kB | -140 B | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Client `webpack` Modern Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` Modern gzip Size | 785 B | 785 B | ✓ | | Serverless `pages/link` Size | 255 kB | 254 kB | -1.18 kB | | Serverless `pages/link` gzip Size | 68.6 kB | 68.2 kB | -403 B | | Serverless `pages/index` Size | 248 kB | 247 kB | -1.16 kB | | Serverless `pages/index` gzip Size | 66.4 kB | 66 kB | -387 B | | Serverless `pages/_error` Size | 247 kB | 246 kB | -1.16 kB | | Serverless `pages/_error` gzip Size | 66.1 kB | 65.7 kB | -390 B | | Serverless `pages/routerDirect` Size | 248 kB | 247 kB | -1.16 kB | | Serverless `pages/routerDirect` gzip Size | 66.3 kB | 65.9 kB | -391 B | | Serverless `pages/withRouter` Size | 248 kB | 247 kB | -1.16 kB | | Serverless `pages/withRouter` gzip Size | 66.4 kB | 66 kB | -388 B | | Build Dir Size | 2.59 MB | 2.59 MB | -301 B |
Diff for main.js ```diff @@ -1,19 +1,4 @@ -(window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ - -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), +(window["webpackJsonp"] = window["webpackJsonp"] || []).push([[2],{ /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,24 +54,193 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { +/***/ "8oxB": +/***/ (function(module, exports) { -"use strict"; +// shim for using process in browser +var process = module.exports = {}; -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); +var cachedSetTimeout; +var cachedClearTimeout; + +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); +} +function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); +} +(function () { + try { + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; + } + } catch (e) { + cachedSetTimeout = defaultSetTimout; + } + try { + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; + } else { + cachedClearTimeout = defaultClearTimeout; + } + } catch (e) { + cachedClearTimeout = defaultClearTimeout; + } +} ()) +function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); + } + } + + +} +function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); + } + } + + + +} +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; + +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} + +function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + runClearTimeout(timeout); +} + +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } +}; + +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; +process.prependListener = noop; +process.prependOnceListener = noop; + +process.listeners = function (name) { return [] } + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; /***/ }), @@ -503,7 +657,7 @@ function () { var _ref2 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee(_temp) { - var _ref, passedWebpackHMR, initialErr, _require, isValidElementType, renderCtx, appCtx; + var _ref, passedWebpackHMR, initialErr, _require, isValidElementType; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { @@ -584,41 +738,16 @@ function () { }); } }); - renderCtx = { + render({ App: App, Component: Component, props: props, err: initialErr, emitter: emitter - }; - render(renderCtx); - - if (!(window.__NEXT_DATA__.skeleton && Component.getInitialProps)) { - _context.next = 32; - break; - } - - appCtx = { - router: router, - AppTree: wrapApp(App), - Component: Component, - ctx: { - pathname: page, - asPath: asPath, - query: query - } - }; - _context.next = 30; - return App.getInitialProps(appCtx); - - case 30: - props.pageProps = _context.sent.pageProps; - render(renderCtx); - - case 32: + }); return _context.abrupt("return", emitter); - case 33: + case 26: case "end": return _context.stop(); } @@ -919,15 +1048,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -995,17 +1115,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -1083,27 +1192,11 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { "use strict"; - +/* WEBPACK VAR INJECTION */(function(process) { var _interopRequireDefault2 = __webpack_require__("KI45"); @@ -1122,12 +1215,10 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ +/* global document, window */ function supportsPreload(el) { @@ -1157,13 +1248,31 @@ function () { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set["default"](); this.pageRegisterEvents = (0, _mitt["default"])(); this.loadingRoutes = {}; this.promisedBuildId = _promise["default"].resolve(); - } + this.promisedBuildManifest = new _promise["default"](function (resolve) { + if (window.__BUILD_MANIFEST) { + resolve(window.__BUILD_MANIFEST); + } else { + window.__BUILD_MANIFEST_CB = function () { + resolve(window.__BUILD_MANIFEST); + }; + } + }); + } // Returns a promise for the dependencies for a particular route + (0, _createClass2["default"])(PageLoader, [{ + key: "getDependencies", + value: function getDependencies(route) { + return this.promisedBuildManifest.then(function (man) { + return man[route] && man[route].map(function (url) { + return "/_next/" + url; + }) || []; + }); + } + }, { key: "normalizeRoute", value: function normalizeRoute(route) { if (route[0] !== '/') { @@ -1213,13 +1322,26 @@ function () { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!_this3.loadingRoutes[route]) { - _this3.loadScript(route); + if (process.env.__NEXT_GRANULAR_CHUNKS) { + _this3.getDependencies(route).then(function (deps) { + deps.forEach(function (d) { + if (!document.querySelector("script[src^=\"" + d + "\"]")) { + _this3.loadScript(d, route, false); + } + }); + + _this3.loadRoute(route); + + _this3.loadingRoutes[route] = true; + }); + } else { + _this3.loadRoute(route); - _this3.loadingRoutes[route] = true; + _this3.loadingRoutes[route] = true; + } } }); } @@ -1249,14 +1371,14 @@ function () { }); } }, { - key: "loadScript", - value: function loadScript(route) { + key: "loadRoute", + value: function loadRoute(route) { var _this = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee() { - var scriptRoute, script, url; + var scriptRoute, url; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { @@ -1267,41 +1389,51 @@ function () { case 2: route = _this.normalizeRoute(route); scriptRoute = route === '/' ? '/index.js' : route + ".js"; - script = document.createElement('script'); - - if ( true && 'noModule' in script) { - script.type = 'module'; - scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); - } - url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = "anonymous"; - script.src = url; - - script.onerror = function () { - var error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; - - _this.pageRegisterEvents.emit(route, { - error: error - }); - }; - document.body.appendChild(script); + _this.loadScript(url, route, true); - case 11: + case 6: case "end": return _context.stop(); } } }, _callee); }))(); + } + }, { + key: "loadScript", + value: function loadScript(url, route, isPage) { + var _this5 = this; + + var script = document.createElement('script'); + + if ( true && 'noModule' in script) { + script.type = 'module'; // Only page bundle scripts need to have .module added to url, + // dependencies already have it added during build manifest creation + + if (isPage) url = url.replace(/\.js$/, '.module.js'); + } + + script.crossOrigin = "anonymous"; + script.src = url; + + script.onerror = function () { + var error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + + _this5.pageRegisterEvents.emit(route, { + error: error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. }, { key: "registerPage", value: function registerPage(route, regFn) { - var _this5 = this; + var _this6 = this; var register = function register() { try { @@ -1309,21 +1441,21 @@ function () { error = _regFn.error, page = _regFn.page; - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error, page: page }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error, page: page }); } catch (error) { - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error }); } @@ -1335,17 +1467,21 @@ function () { } }, { key: "prefetch", - value: function prefetch(route) { + value: function prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee2() { - var scriptRoute, cn; + var scriptRoute, url, cn; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: + _context2.next = 2; + return _this2.promisedBuildId; + + case 2: route = _this2.normalizeRoute(route); scriptRoute = (route === '/' ? '/index' : route) + ".js"; @@ -1353,51 +1489,72 @@ function () { scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); } - if (!(_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route))) { - _context2.next = 5; + url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. + + if (!(document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route))) { + _context2.next = 8; break; } return _context2.abrupt("return"); - case 5: - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE - - + case 8: if (!(cn = navigator.connection)) { - _context2.next = 9; + _context2.next = 11; break; } if (!((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData)) { - _context2.next = 9; + _context2.next = 11; break; } return _context2.abrupt("return"); - case 9: + case 11: + if (!(process.env.__NEXT_GRANULAR_CHUNKS && !isDependency)) { + _context2.next = 17; + break; + } + + ; + _context2.next = 15; + return _this2.getDependencies(route); + + case 15: + _context2.t0 = function (url) { + _this2.prefetch(url, true); + }; + + _context2.sent.forEach(_context2.t0); + + case 17: if (!hasPreload) { - _context2.next = 14; + _context2.next = 20; break; } - _context2.next = 12; - return _this2.promisedBuildId; + preloadScript(url); + return _context2.abrupt("return"); + + case 20: + if (!isDependency) { + _context2.next = 22; + break; + } - case 12: - preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute); return _context2.abrupt("return"); - case 14: + case 22: if (!(document.readyState === 'complete')) { - _context2.next = 18; + _context2.next = 26; break; } return _context2.abrupt("return", _this2.loadPage(route)["catch"](function () {})); - case 18: + case 26: return _context2.abrupt("return", new _promise["default"](function (resolve) { window.addEventListener('load', function () { _this2.loadPage(route).then(function () { @@ -1408,7 +1565,7 @@ function () { }); })); - case 19: + case 27: case "end": return _context2.stop(); } @@ -1421,6 +1578,7 @@ function () { }(); exports["default"] = PageLoader; +/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__("8oxB"))) /***/ }) ```
Diff for commons.js ```diff @@ -3223,14 +3223,7 @@ function () { var _url_1$parse = url_1.parse(url, true), pathname = _url_1$parse.pathname, - query = _url_1$parse.query, - protocol = _url_1$parse.protocol; - - if (!pathname || protocol) { - if (false) {} - - return resolve(false); - } // If asked to change the current URL we should reload the current page + query = _url_1$parse.query; // If asked to change the current URL we should reload the current page // (not location.reload() but reload getInitialProps and other Next.js stuffs) // We also need to set the method = replaceState always // as this should not go into the history (That's how browsers work) @@ -3499,18 +3492,12 @@ function () { var _this4 = this; return new _promise["default"](function (resolve, reject) { - var _url_1$parse3 = url_1.parse(url), - pathname = _url_1$parse3.pathname, - protocol = _url_1$parse3.protocol; - - if (!pathname || protocol) { - if (false) {} - - return; - } // Prefetch is not supported in development mode because it would trigger on-demand-entries + // Prefetch is not supported in development mode because it would trigger on-demand-entries + if (false) {} + var _url_1$parse3 = url_1.parse(url), + pathname = _url_1$parse3.pathname; // @ts-ignore pathname is always defined - if (false) {} // @ts-ignore pathname is always defined var route = toRoute(pathname); @@ -3576,7 +3563,7 @@ function () { var _getInitialProps = (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee2(Component, ctx) { - var cancelled, cancel, App, props, url, res, err; + var cancelled, cancel, App, props, err; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { @@ -3589,59 +3576,7 @@ function () { this.clc = cancel; App = this.components['/_app'].Component; - - if (!Component.__NEXT_PRERENDER) { - _context2.next = 20; - break; - } - - url = url_1.format({ - pathname: ctx.asPath, - query: ctx.query - }); - _context2.next = 8; - return fetch(url, { - headers: { - 'content-type': 'application/json' - } - }); - - case 8: - res = _context2.sent; - - if (!res.ok) { - _context2.next = 15; - break; - } - - _context2.next = 12; - return res.json()["catch"](function (err) { - return { - error: err.message - }; - }); - - case 12: - _context2.t0 = _context2.sent; - _context2.next = 16; - break; - - case 15: - _context2.t0 = { - error: 'failed to load prerender', - statusCode: res.status - }; - - case 16: - _context2.t1 = _context2.t0; - props = { - pageProps: _context2.t1 - }; - _context2.next = 23; - break; - - case 20: - _context2.next = 22; + _context2.next = 6; return utils_1.loadGetInitialProps(App, { AppTree: this._wrapApp(App), Component: Component, @@ -3649,16 +3584,15 @@ function () { ctx: ctx }); - case 22: + case 6: props = _context2.sent; - case 23: if (cancel === this.clc) { this.clc = null; } if (!cancelled) { - _context2.next = 28; + _context2.next = 12; break; } @@ -3666,10 +3600,10 @@ function () { err.cancelled = true; throw err; - case 28: + case 12: return _context2.abrupt("return", props); - case 29: + case 13: case "end": return _context2.stop(); } @@ -6750,7 +6684,8 @@ var singletonRouter = { } }; // Create public properties and methods of the router in the singletonRouter -var urlPropertyFields = ['pathname', 'route', 'query', 'asPath', 'components']; +var urlPropertyFields = ['pathname', 'route', 'query', 'asPath']; +var propertyFields = ['components']; var routerEvents = ['routeChangeStart', 'beforeHistoryChange', 'routeChangeComplete', 'routeChangeError', 'hashChangeStart', 'hashChangeComplete']; var coreMethodFields = ['push', 'replace', 'reload', 'back', 'prefetch', 'beforePopState']; // Events is a static property on the router, the router doesn't have to be initialized to use it @@ -6759,7 +6694,7 @@ var coreMethodFields = ['push', 'replace', 'reload', 'back', 'prefetch', 'before return _router2["default"].events; } }); -urlPropertyFields.forEach(function (field) { +propertyFields.concat(urlPropertyFields).forEach(function (field) { // Here we need to use Object.defineProperty because, we need to return // the property assigned to the actual router // The value might get changed as we change routes and this is the @@ -6858,6 +6793,17 @@ function makePublicRouterInstance(router) { instance.events = _router2["default"].events; + propertyFields.forEach(function (field) { + // Here we need to use Object.defineProperty because, we need to return + // the property assigned to the actual router + // The value might get changed as we change routes and this is the + // proper way to access it + (0, _defineProperty["default"])(instance, field, { + get: function get() { + return _router[field]; + } + }); + }); coreMethodFields.forEach(function (field) { instance[field] = function () { return _router[field].apply(_router, arguments); ```
Diff for mainModern.js ```diff @@ -1,19 +1,4 @@ -(window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ - -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), +(window["webpackJsonp"] = window["webpackJsonp"] || []).push([[2],{ /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,24 +54,193 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { +/***/ "8oxB": +/***/ (function(module, exports) { -"use strict"; +// shim for using process in browser +var process = module.exports = {}; -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. + +var cachedSetTimeout; +var cachedClearTimeout; + +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); +} +function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); +} +(function () { + try { + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; + } + } catch (e) { + cachedSetTimeout = defaultSetTimout; + } + try { + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; + } else { + cachedClearTimeout = defaultClearTimeout; + } + } catch (e) { + cachedClearTimeout = defaultClearTimeout; + } +} ()) +function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); + } + } + + +} +function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); + } + } -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); + + +} +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; + +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} + +function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + runClearTimeout(timeout); +} + +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } +}; + +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; +process.prependListener = noop; +process.prependOnceListener = noop; + +process.listeners = function (name) { return [] } + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; /***/ }), @@ -495,30 +649,13 @@ function () { }); } }); - const renderCtx = { + render({ App, Component, props, err: initialErr, emitter - }; - render(renderCtx); - - if (window.__NEXT_DATA__.skeleton && Component.getInitialProps) { - const appCtx = { - router, - AppTree: wrapApp(App), - Component: Component, - ctx: { - pathname: page, - asPath, - query - } - }; - props.pageProps = (yield App.getInitialProps(appCtx)).pageProps; - render(renderCtx); - } - + }); return emitter; }); @@ -729,15 +866,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -792,17 +920,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -878,27 +995,11 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { "use strict"; - +/* WEBPACK VAR INJECTION */(function(process) { var _interopRequireDefault = __webpack_require__("KI45"); @@ -909,12 +1010,10 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ +/* global document, window */ function supportsPreload(el) { @@ -941,10 +1040,23 @@ class PageLoader { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set.default(); this.pageRegisterEvents = (0, _mitt.default)(); this.loadingRoutes = {}; this.promisedBuildId = _promise.default.resolve(); + this.promisedBuildManifest = new _promise.default(resolve => { + if (window.__BUILD_MANIFEST) { + resolve(window.__BUILD_MANIFEST); + } else { + window.__BUILD_MANIFEST_CB = () => { + resolve(window.__BUILD_MANIFEST); + }; + } + }); + } // Returns a promise for the dependencies for a particular route + + + getDependencies(route) { + return this.promisedBuildManifest.then(man => man[route] && man[route].map(url => "/_next/" + url) || []); } normalizeRoute(route) { @@ -993,12 +1105,23 @@ class PageLoader { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!this.loadingRoutes[route]) { - this.loadScript(route); - this.loadingRoutes[route] = true; + if (process.env.__NEXT_GRANULAR_CHUNKS) { + this.getDependencies(route).then(deps => { + deps.forEach(d => { + if (!document.querySelector("script[src^=\"" + d + "\"]")) { + this.loadScript(d, route, false); + } + }); + this.loadRoute(route); + this.loadingRoutes[route] = true; + }); + } else { + this.loadRoute(route); + this.loadingRoutes[route] = true; + } } }); } @@ -1023,35 +1146,41 @@ class PageLoader { }); } - loadScript(route) { + loadRoute(route) { var _this = this; return (0, _asyncToGenerator2.default)(function* () { yield _this.promisedBuildId; route = _this.normalizeRoute(route); let scriptRoute = route === '/' ? '/index.js' : route + ".js"; - const script = document.createElement('script'); + const url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - if ( true && 'noModule' in script) { - script.type = 'module'; - scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); - } + _this.loadScript(url, route, true); + })(); + } - const url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = "anonymous"; - script.src = url; + loadScript(url, route, isPage) { + const script = document.createElement('script'); - script.onerror = () => { - const error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; + if ( true && 'noModule' in script) { + script.type = 'module'; // Only page bundle scripts need to have .module added to url, + // dependencies already have it added during build manifest creation - _this.pageRegisterEvents.emit(route, { - error - }); - }; + if (isPage) url = url.replace(/\.js$/, '.module.js'); + } - document.body.appendChild(script); - })(); + script.crossOrigin = "anonymous"; + script.src = url; + + script.onerror = () => { + const error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + this.pageRegisterEvents.emit(route, { + error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. @@ -1085,10 +1214,11 @@ class PageLoader { register(); } - prefetch(route) { + prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2.default)(function* () { + yield _this2.promisedBuildId; route = _this2.normalizeRoute(route); let scriptRoute = (route === '/' ? '/index' : route) + ".js"; @@ -1096,11 +1226,12 @@ class PageLoader { scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); } - if (_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route)) { - return; - } + const url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE + if (document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route)) { + return; + } // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE let cn; @@ -1110,14 +1241,26 @@ class PageLoader { if ((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData) { return; } + } + + if (process.env.__NEXT_GRANULAR_CHUNKS && !isDependency) { + ; + (yield _this2.getDependencies(route)).forEach(url => { + _this2.prefetch(url, true); + }); } // Feature detection is used to see if preload is supported // If not fall back to loading script tags before the page is loaded // https://caniuse.com/#feat=link-rel-preload if (hasPreload) { - yield _this2.promisedBuildId; - preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute); + preloadScript(url); + return; + } + + if (isDependency) { + // loadPage will automatically handle depencies, so no need to + // preload them manually return; } @@ -1136,6 +1279,7 @@ class PageLoader { } exports.default = PageLoader; +/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__("8oxB"))) /***/ }) ```
Diff for commonsModern.js ```diff @@ -2700,21 +2700,13 @@ class Router { const { pathname, - query, - protocol - } = url_1.parse(url, true); - - if (!pathname || protocol) { - if (false) {} - - return resolve(false); - } // If asked to change the current URL we should reload the current page + query + } = url_1.parse(url, true); // If asked to change the current URL we should reload the current page // (not location.reload() but reload getInitialProps and other Next.js stuffs) // We also need to set the method = replaceState always // as this should not go into the history (That's how browsers work) // We should compare the new asPath to the current asPath, not the url - if (!this.urlIsNew(as)) { method = 'replaceState'; } // @ts-ignore pathname is always a string @@ -2953,19 +2945,11 @@ class Router { prefetch(url) { return new _promise.default((resolve, reject) => { + // Prefetch is not supported in development mode because it would trigger on-demand-entries + if (false) {} const { - pathname, - protocol - } = url_1.parse(url); - - if (!pathname || protocol) { - if (false) {} - - return; - } // Prefetch is not supported in development mode because it would trigger on-demand-entries - - - if (false) {} // @ts-ignore pathname is always defined + pathname + } = url_1.parse(url); // @ts-ignore pathname is always defined const route = toRoute(pathname); this.pageLoader.prefetch(route).then(resolve, reject); @@ -3005,34 +2989,12 @@ class Router { const { Component: App } = this.components['/_app']; - let props; - - if (Component.__NEXT_PRERENDER) { - const url = url_1.format({ - pathname: ctx.asPath, - query: ctx.query - }); - const res = await fetch(url, { - headers: { - 'content-type': 'application/json' - } - }); - props = { - pageProps: res.ok ? await res.json().catch(err => ({ - error: err.message - })) : { - error: 'failed to load prerender', - statusCode: res.status - } - }; - } else { - props = await utils_1.loadGetInitialProps(App, { - AppTree: this._wrapApp(App), - Component, - router: this, - ctx - }); - } + const props = await utils_1.loadGetInitialProps(App, { + AppTree: this._wrapApp(App), + Component, + router: this, + ctx + }); if (cancel === this.clc) { this.clc = null; @@ -4901,7 +4863,8 @@ const singletonRouter = { }; // Create public properties and methods of the router in the singletonRouter -const urlPropertyFields = ['pathname', 'route', 'query', 'asPath', 'components']; +const urlPropertyFields = ['pathname', 'route', 'query', 'asPath']; +const propertyFields = ['components']; const routerEvents = ['routeChangeStart', 'beforeHistoryChange', 'routeChangeComplete', 'routeChangeError', 'hashChangeStart', 'hashChangeComplete']; const coreMethodFields = ['push', 'replace', 'reload', 'back', 'prefetch', 'beforePopState']; // Events is a static property on the router, the router doesn't have to be initialized to use it @@ -4911,7 +4874,7 @@ const coreMethodFields = ['push', 'replace', 'reload', 'back', 'prefetch', 'befo } }); -urlPropertyFields.forEach(field => { +propertyFields.concat(urlPropertyFields).forEach(field => { // Here we need to use Object.defineProperty because, we need to return // the property assigned to the actual router // The value might get changed as we change routes and this is the @@ -5007,6 +4970,18 @@ function makePublicRouterInstance(router) { instance.events = _router2.default.events; + propertyFields.forEach(field => { + // Here we need to use Object.defineProperty because, we need to return + // the property assigned to the actual router + // The value might get changed as we change routes and this is the + // proper way to access it + (0, _defineProperty.default)(instance, field, { + get() { + return _router[field]; + } + + }); + }); coreMethodFields.forEach(field => { instance[field] = function () { return _router[field](...arguments); ```
ijjk commented 5 years ago

Stats from current PR

Click to expand stats ⚠️ Total Bundle Size Increase ⚠️ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 22s | 22.4s | ⚠️ +352ms | | `node_modules` Size | 43.6 MB | 43.6 MB | ⚠️ +12.3 kB | | Total Bundle (main, webpack, commons) Size | 207 kB | 209 kB | ⚠️ +1.96 kB | | Total Bundle (main, webpack, commons) gzip Size | 68.1 kB | 68.9 kB | ⚠️ +765 B | | Total Bundle (main, webpack, commons) Modern Size | 182 kB | 183 kB | ⚠️ +1.75 kB | | Total Bundle (main, webpack, commons) Modern gzip Size | 59.9 kB | 60.6 kB | ⚠️ +675 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_app` Modern Size | 1.83 kB | 1.83 kB | ✓ | | Client `_app` gzip Modern Size | 890 B | 890 B | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `_error` Modern Size | 5.85 kB | 5.85 kB | ✓ | | Client `_error` gzip Modern Size | 2.33 kB | 2.33 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/index` Modern Size | 319 B | 319 B | ✓ | | Client `pages/index` gzip Modern Size | 254 B | 254 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/link` Modern Size | 3.7 kB | 3.7 kB | ✓ | | Client `pages/link` gzip Modern Size | 1.7 kB | 1.7 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/routerDirect` Modern Size | 411 B | 411 B | ✓ | | Client `pages/routerDirect` gzip Modern Size | 314 B | 314 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `pages/withRouter` Modern Size | 423 B | 423 B | ✓ | | Client `pages/withRouter` gzip Modern Size | 309 B | 309 B | ✓ | | Client `main` Size | 15.8 kB | 17.8 kB | ⚠️ +1.96 kB | | Client `main` gzip Size | 5.46 kB | 6.22 kB | ⚠️ +765 B | | Client `main` Modern Size | 12.8 kB | 14.6 kB | ⚠️ +1.75 kB | | Client `main` Modern gzip Size | 4.83 kB | 5.51 kB | ⚠️ +675 B | | Client `commons` Size | 188 kB | 188 kB | ✓ | | Client `commons` gzip Size | 61.3 kB | 61.3 kB | ✓ | | Client `commons` Modern Size | 169 kB | 169 kB | ✓ | | Client `commons` Modern gzip Size | 55.1 kB | 55.1 kB | ✓ | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Client `webpack` Modern Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` Modern gzip Size | 785 B | 785 B | ✓ | | Base Rendered Size | 2.76 kB | 2.76 kB | ✓ | | Build Dir Size | 1.39 MB | 1.4 MB | ⚠️ +12.5 kB |
Click to expand serverless stats ⚠️ Total Bundle Size Increase ⚠️ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 23.7s | 23.5s | -182ms | | `node_modules` Size | 43.6 MB | 43.6 MB | ⚠️ +12.3 kB | | Total Bundle (main, webpack, commons) Size | 207 kB | 209 kB | ⚠️ +1.96 kB | | Total Bundle (main, webpack, commons) gzip Size | 68.1 kB | 68.9 kB | ⚠️ +765 B | | Total Bundle (main, webpack, commons) Modern Size | 182 kB | 183 kB | ⚠️ +1.75 kB | | Total Bundle (main, webpack, commons) Modern gzip Size | 59.9 kB | 60.6 kB | ⚠️ +675 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_app` Modern Size | 1.83 kB | 1.83 kB | ✓ | | Client `_app` gzip Modern Size | 890 B | 890 B | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `_error` Modern Size | 5.85 kB | 5.85 kB | ✓ | | Client `_error` gzip Modern Size | 2.33 kB | 2.33 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/index` Modern Size | 319 B | 319 B | ✓ | | Client `pages/index` gzip Modern Size | 254 B | 254 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/link` Modern Size | 3.7 kB | 3.7 kB | ✓ | | Client `pages/link` gzip Modern Size | 1.7 kB | 1.7 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/routerDirect` Modern Size | 411 B | 411 B | ✓ | | Client `pages/routerDirect` gzip Modern Size | 314 B | 314 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `pages/withRouter` Modern Size | 423 B | 423 B | ✓ | | Client `pages/withRouter` gzip Modern Size | 309 B | 309 B | ✓ | | Client `main` Size | 15.8 kB | 17.8 kB | ⚠️ +1.96 kB | | Client `main` gzip Size | 5.46 kB | 6.22 kB | ⚠️ +765 B | | Client `main` Modern Size | 12.8 kB | 14.6 kB | ⚠️ +1.75 kB | | Client `main` Modern gzip Size | 4.83 kB | 5.51 kB | ⚠️ +675 B | | Client `commons` Size | 188 kB | 188 kB | ✓ | | Client `commons` gzip Size | 61.3 kB | 61.3 kB | ✓ | | Client `commons` Modern Size | 169 kB | 169 kB | ✓ | | Client `commons` Modern gzip Size | 55.1 kB | 55.1 kB | ✓ | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Client `webpack` Modern Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` Modern gzip Size | 785 B | 785 B | ✓ | | Serverless `pages/link` Size | 255 kB | 255 kB | ✓ | | Serverless `pages/link` gzip Size | 68.6 kB | 68.6 kB | ⚠️ +1 B | | Serverless `pages/index` Size | 248 kB | 248 kB | ✓ | | Serverless `pages/index` gzip Size | 66.4 kB | 66.4 kB | ⚠️ +1 B | | Serverless `pages/_error` Size | 247 kB | 247 kB | ✓ | | Serverless `pages/_error` gzip Size | 66.1 kB | 66.1 kB | ✓ | | Serverless `pages/routerDirect` Size | 248 kB | 248 kB | ✓ | | Serverless `pages/routerDirect` gzip Size | 66.3 kB | 66.3 kB | ⚠️ +1 B | | Serverless `pages/withRouter` Size | 248 kB | 248 kB | ✓ | | Serverless `pages/withRouter` gzip Size | 66.4 kB | 66.4 kB | ✓ | | Build Dir Size | 2.59 MB | 2.61 MB | ⚠️ +12.5 kB |
Diff for main.js ```diff @@ -1,20 +1,5 @@ (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), - /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,24 +54,193 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { +/***/ "8oxB": +/***/ (function(module, exports) { -"use strict"; +// shim for using process in browser +var process = module.exports = {}; + +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. + +var cachedSetTimeout; +var cachedClearTimeout; + +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); +} +function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); +} +(function () { + try { + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; + } + } catch (e) { + cachedSetTimeout = defaultSetTimout; + } + try { + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; + } else { + cachedClearTimeout = defaultClearTimeout; + } + } catch (e) { + cachedClearTimeout = defaultClearTimeout; + } +} ()) +function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); + } + } + + +} +function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); + } + } -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); + +} +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; + +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} + +function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + runClearTimeout(timeout); +} + +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } +}; + +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; +process.prependListener = noop; +process.prependOnceListener = noop; + +process.listeners = function (name) { return [] } + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; /***/ }), @@ -919,15 +1073,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -995,17 +1140,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -1083,27 +1217,11 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { "use strict"; - +/* WEBPACK VAR INJECTION */(function(process) { var _interopRequireDefault2 = __webpack_require__("KI45"); @@ -1122,12 +1240,10 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ +/* global document, window */ function supportsPreload(el) { @@ -1157,13 +1273,31 @@ function () { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set["default"](); this.pageRegisterEvents = (0, _mitt["default"])(); this.loadingRoutes = {}; this.promisedBuildId = _promise["default"].resolve(); - } + this.promisedBuildManifest = new _promise["default"](function (resolve) { + if (window.__BUILD_MANIFEST) { + resolve(window.__BUILD_MANIFEST); + } else { + window.__BUILD_MANIFEST_CB = function () { + resolve(window.__BUILD_MANIFEST); + }; + } + }); + } // Returns a promise for the dependencies for a particular route + (0, _createClass2["default"])(PageLoader, [{ + key: "getDependencies", + value: function getDependencies(route) { + return this.promisedBuildManifest.then(function (man) { + return man[route] && man[route].map(function (url) { + return "/_next/" + url; + }) || []; + }); + } + }, { key: "normalizeRoute", value: function normalizeRoute(route) { if (route[0] !== '/') { @@ -1213,13 +1347,26 @@ function () { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!_this3.loadingRoutes[route]) { - _this3.loadScript(route); + if (process.env.__NEXT_GRANULAR_CHUNKS) { + _this3.getDependencies(route).then(function (deps) { + deps.forEach(function (d) { + if (!document.querySelector("script[src^=\"" + d + "\"]")) { + _this3.loadScript(d, route, false); + } + }); + + _this3.loadRoute(route); + + _this3.loadingRoutes[route] = true; + }); + } else { + _this3.loadRoute(route); - _this3.loadingRoutes[route] = true; + _this3.loadingRoutes[route] = true; + } } }); } @@ -1249,14 +1396,14 @@ function () { }); } }, { - key: "loadScript", - value: function loadScript(route) { + key: "loadRoute", + value: function loadRoute(route) { var _this = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee() { - var scriptRoute, script, url; + var scriptRoute, url; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { @@ -1267,41 +1414,51 @@ function () { case 2: route = _this.normalizeRoute(route); scriptRoute = route === '/' ? '/index.js' : route + ".js"; - script = document.createElement('script'); - - if ( true && 'noModule' in script) { - script.type = 'module'; - scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); - } - url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = "anonymous"; - script.src = url; - - script.onerror = function () { - var error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; - _this.pageRegisterEvents.emit(route, { - error: error - }); - }; + _this.loadScript(url, route, true); - document.body.appendChild(script); - - case 11: + case 6: case "end": return _context.stop(); } } }, _callee); }))(); + } + }, { + key: "loadScript", + value: function loadScript(url, route, isPage) { + var _this5 = this; + + var script = document.createElement('script'); + + if ( true && 'noModule' in script) { + script.type = 'module'; // Only page bundle scripts need to have .module added to url, + // dependencies already have it added during build manifest creation + + if (isPage) url = url.replace(/\.js$/, '.module.js'); + } + + script.crossOrigin = "anonymous"; + script.src = url; + + script.onerror = function () { + var error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + + _this5.pageRegisterEvents.emit(route, { + error: error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. }, { key: "registerPage", value: function registerPage(route, regFn) { - var _this5 = this; + var _this6 = this; var register = function register() { try { @@ -1309,21 +1466,21 @@ function () { error = _regFn.error, page = _regFn.page; - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error, page: page }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error, page: page }); } catch (error) { - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error }); } @@ -1335,17 +1492,21 @@ function () { } }, { key: "prefetch", - value: function prefetch(route) { + value: function prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee2() { - var scriptRoute, cn; + var scriptRoute, url, cn; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: + _context2.next = 2; + return _this2.promisedBuildId; + + case 2: route = _this2.normalizeRoute(route); scriptRoute = (route === '/' ? '/index' : route) + ".js"; @@ -1353,51 +1514,72 @@ function () { scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); } - if (!(_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route))) { - _context2.next = 5; + url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. + + if (!(document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route))) { + _context2.next = 8; break; } return _context2.abrupt("return"); - case 5: - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE - - + case 8: if (!(cn = navigator.connection)) { - _context2.next = 9; + _context2.next = 11; break; } if (!((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData)) { - _context2.next = 9; + _context2.next = 11; break; } return _context2.abrupt("return"); - case 9: + case 11: + if (!(process.env.__NEXT_GRANULAR_CHUNKS && !isDependency)) { + _context2.next = 17; + break; + } + + ; + _context2.next = 15; + return _this2.getDependencies(route); + + case 15: + _context2.t0 = function (url) { + _this2.prefetch(url, true); + }; + + _context2.sent.forEach(_context2.t0); + + case 17: if (!hasPreload) { - _context2.next = 14; + _context2.next = 20; break; } - _context2.next = 12; - return _this2.promisedBuildId; + preloadScript(url); + return _context2.abrupt("return"); + + case 20: + if (!isDependency) { + _context2.next = 22; + break; + } - case 12: - preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute); return _context2.abrupt("return"); - case 14: + case 22: if (!(document.readyState === 'complete')) { - _context2.next = 18; + _context2.next = 26; break; } return _context2.abrupt("return", _this2.loadPage(route)["catch"](function () {})); - case 18: + case 26: return _context2.abrupt("return", new _promise["default"](function (resolve) { window.addEventListener('load', function () { _this2.loadPage(route).then(function () { @@ -1408,7 +1590,7 @@ function () { }); })); - case 19: + case 27: case "end": return _context2.stop(); } @@ -1421,6 +1603,7 @@ function () { }(); exports["default"] = PageLoader; +/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__("8oxB"))) /***/ }) ```
Diff for mainModern.js ```diff @@ -1,20 +1,5 @@ (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), - /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,24 +54,193 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { +/***/ "8oxB": +/***/ (function(module, exports) { -"use strict"; +// shim for using process in browser +var process = module.exports = {}; -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); +var cachedSetTimeout; +var cachedClearTimeout; + +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); +} +function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); +} +(function () { + try { + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; + } + } catch (e) { + cachedSetTimeout = defaultSetTimout; + } + try { + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; + } else { + cachedClearTimeout = defaultClearTimeout; + } + } catch (e) { + cachedClearTimeout = defaultClearTimeout; + } +} ()) +function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); + } + } + + +} +function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); + } + } + + + +} +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; + +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} + +function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + runClearTimeout(timeout); +} + +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } +}; + +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; +process.prependListener = noop; +process.prependOnceListener = noop; + +process.listeners = function (name) { return [] } + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; /***/ }), @@ -729,15 +883,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -792,17 +937,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -878,27 +1012,11 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { "use strict"; - +/* WEBPACK VAR INJECTION */(function(process) { var _interopRequireDefault = __webpack_require__("KI45"); @@ -909,12 +1027,10 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ +/* global document, window */ function supportsPreload(el) { @@ -941,10 +1057,23 @@ class PageLoader { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set.default(); this.pageRegisterEvents = (0, _mitt.default)(); this.loadingRoutes = {}; this.promisedBuildId = _promise.default.resolve(); + this.promisedBuildManifest = new _promise.default(resolve => { + if (window.__BUILD_MANIFEST) { + resolve(window.__BUILD_MANIFEST); + } else { + window.__BUILD_MANIFEST_CB = () => { + resolve(window.__BUILD_MANIFEST); + }; + } + }); + } // Returns a promise for the dependencies for a particular route + + + getDependencies(route) { + return this.promisedBuildManifest.then(man => man[route] && man[route].map(url => "/_next/" + url) || []); } normalizeRoute(route) { @@ -993,12 +1122,23 @@ class PageLoader { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!this.loadingRoutes[route]) { - this.loadScript(route); - this.loadingRoutes[route] = true; + if (process.env.__NEXT_GRANULAR_CHUNKS) { + this.getDependencies(route).then(deps => { + deps.forEach(d => { + if (!document.querySelector("script[src^=\"" + d + "\"]")) { + this.loadScript(d, route, false); + } + }); + this.loadRoute(route); + this.loadingRoutes[route] = true; + }); + } else { + this.loadRoute(route); + this.loadingRoutes[route] = true; + } } }); } @@ -1023,35 +1163,41 @@ class PageLoader { }); } - loadScript(route) { + loadRoute(route) { var _this = this; return (0, _asyncToGenerator2.default)(function* () { yield _this.promisedBuildId; route = _this.normalizeRoute(route); let scriptRoute = route === '/' ? '/index.js' : route + ".js"; - const script = document.createElement('script'); + const url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - if ( true && 'noModule' in script) { - script.type = 'module'; - scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); - } + _this.loadScript(url, route, true); + })(); + } - const url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = "anonymous"; - script.src = url; + loadScript(url, route, isPage) { + const script = document.createElement('script'); - script.onerror = () => { - const error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; + if ( true && 'noModule' in script) { + script.type = 'module'; // Only page bundle scripts need to have .module added to url, + // dependencies already have it added during build manifest creation - _this.pageRegisterEvents.emit(route, { - error - }); - }; + if (isPage) url = url.replace(/\.js$/, '.module.js'); + } - document.body.appendChild(script); - })(); + script.crossOrigin = "anonymous"; + script.src = url; + + script.onerror = () => { + const error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + this.pageRegisterEvents.emit(route, { + error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. @@ -1085,10 +1231,11 @@ class PageLoader { register(); } - prefetch(route) { + prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2.default)(function* () { + yield _this2.promisedBuildId; route = _this2.normalizeRoute(route); let scriptRoute = (route === '/' ? '/index' : route) + ".js"; @@ -1096,11 +1243,12 @@ class PageLoader { scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); } - if (_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route)) { - return; - } + const url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE + if (document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route)) { + return; + } // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE let cn; @@ -1110,14 +1258,26 @@ class PageLoader { if ((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData) { return; } + } + + if (process.env.__NEXT_GRANULAR_CHUNKS && !isDependency) { + ; + (yield _this2.getDependencies(route)).forEach(url => { + _this2.prefetch(url, true); + }); } // Feature detection is used to see if preload is supported // If not fall back to loading script tags before the page is loaded // https://caniuse.com/#feat=link-rel-preload if (hasPreload) { - yield _this2.promisedBuildId; - preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute); + preloadScript(url); + return; + } + + if (isDependency) { + // loadPage will automatically handle depencies, so no need to + // preload them manually return; } @@ -1136,6 +1296,7 @@ class PageLoader { } exports.default = PageLoader; +/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__("8oxB"))) /***/ }) ```
ijjk commented 5 years ago

Stats from current PR

Click to expand stats ⚠️ Total Bundle Size Increase ⚠️ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 22.5s | 21.9s | -580ms | | `node_modules` Size | 43.6 MB | 43.6 MB | ⚠️ +12.3 kB | | Total Bundle (main, webpack, commons) Size | 207 kB | 209 kB | ⚠️ +1.96 kB | | Total Bundle (main, webpack, commons) gzip Size | 68.1 kB | 68.9 kB | ⚠️ +765 B | | Total Bundle (main, webpack, commons) Modern Size | 182 kB | 183 kB | ⚠️ +1.75 kB | | Total Bundle (main, webpack, commons) Modern gzip Size | 59.9 kB | 60.6 kB | ⚠️ +675 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_app` Modern Size | 1.83 kB | 1.83 kB | ✓ | | Client `_app` gzip Modern Size | 890 B | 890 B | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `_error` Modern Size | 5.85 kB | 5.85 kB | ✓ | | Client `_error` gzip Modern Size | 2.33 kB | 2.33 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/index` Modern Size | 319 B | 319 B | ✓ | | Client `pages/index` gzip Modern Size | 254 B | 254 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/link` Modern Size | 3.7 kB | 3.7 kB | ✓ | | Client `pages/link` gzip Modern Size | 1.7 kB | 1.7 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/routerDirect` Modern Size | 411 B | 411 B | ✓ | | Client `pages/routerDirect` gzip Modern Size | 314 B | 314 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `pages/withRouter` Modern Size | 423 B | 423 B | ✓ | | Client `pages/withRouter` gzip Modern Size | 309 B | 309 B | ✓ | | Client `main` Size | 15.8 kB | 17.8 kB | ⚠️ +1.96 kB | | Client `main` gzip Size | 5.46 kB | 6.22 kB | ⚠️ +765 B | | Client `main` Modern Size | 12.8 kB | 14.6 kB | ⚠️ +1.75 kB | | Client `main` Modern gzip Size | 4.83 kB | 5.51 kB | ⚠️ +675 B | | Client `commons` Size | 188 kB | 188 kB | ✓ | | Client `commons` gzip Size | 61.3 kB | 61.3 kB | ✓ | | Client `commons` Modern Size | 169 kB | 169 kB | ✓ | | Client `commons` Modern gzip Size | 55.1 kB | 55.1 kB | ✓ | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Client `webpack` Modern Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` Modern gzip Size | 785 B | 785 B | ✓ | | Base Rendered Size | 2.76 kB | 2.76 kB | ✓ | | Build Dir Size | 1.39 MB | 1.4 MB | ⚠️ +12.5 kB |
Click to expand serverless stats ⚠️ Total Bundle Size Increase ⚠️ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 22.9s | 23.7s | ⚠️ +815ms | | `node_modules` Size | 43.6 MB | 43.6 MB | ⚠️ +12.3 kB | | Total Bundle (main, webpack, commons) Size | 207 kB | 209 kB | ⚠️ +1.96 kB | | Total Bundle (main, webpack, commons) gzip Size | 68.1 kB | 68.9 kB | ⚠️ +765 B | | Total Bundle (main, webpack, commons) Modern Size | 182 kB | 183 kB | ⚠️ +1.75 kB | | Total Bundle (main, webpack, commons) Modern gzip Size | 59.9 kB | 60.6 kB | ⚠️ +675 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_app` Modern Size | 1.83 kB | 1.83 kB | ✓ | | Client `_app` gzip Modern Size | 890 B | 890 B | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `_error` Modern Size | 5.85 kB | 5.85 kB | ✓ | | Client `_error` gzip Modern Size | 2.33 kB | 2.33 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/index` Modern Size | 319 B | 319 B | ✓ | | Client `pages/index` gzip Modern Size | 254 B | 254 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/link` Modern Size | 3.7 kB | 3.7 kB | ✓ | | Client `pages/link` gzip Modern Size | 1.7 kB | 1.7 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/routerDirect` Modern Size | 411 B | 411 B | ✓ | | Client `pages/routerDirect` gzip Modern Size | 314 B | 314 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `pages/withRouter` Modern Size | 423 B | 423 B | ✓ | | Client `pages/withRouter` gzip Modern Size | 309 B | 309 B | ✓ | | Client `main` Size | 15.8 kB | 17.8 kB | ⚠️ +1.96 kB | | Client `main` gzip Size | 5.46 kB | 6.22 kB | ⚠️ +765 B | | Client `main` Modern Size | 12.8 kB | 14.6 kB | ⚠️ +1.75 kB | | Client `main` Modern gzip Size | 4.83 kB | 5.51 kB | ⚠️ +675 B | | Client `commons` Size | 188 kB | 188 kB | ✓ | | Client `commons` gzip Size | 61.3 kB | 61.3 kB | ✓ | | Client `commons` Modern Size | 169 kB | 169 kB | ✓ | | Client `commons` Modern gzip Size | 55.1 kB | 55.1 kB | ✓ | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Client `webpack` Modern Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` Modern gzip Size | 785 B | 785 B | ✓ | | Serverless `pages/link` Size | 255 kB | 255 kB | ✓ | | Serverless `pages/link` gzip Size | 68.6 kB | 68.6 kB | -1 B | | Serverless `pages/index` Size | 248 kB | 248 kB | ✓ | | Serverless `pages/index` gzip Size | 66.4 kB | 66.4 kB | -1 B | | Serverless `pages/_error` Size | 247 kB | 247 kB | ✓ | | Serverless `pages/_error` gzip Size | 66.1 kB | 66.1 kB | -1 B | | Serverless `pages/routerDirect` Size | 248 kB | 248 kB | ✓ | | Serverless `pages/routerDirect` gzip Size | 66.3 kB | 66.3 kB | ✓ | | Serverless `pages/withRouter` Size | 248 kB | 248 kB | ✓ | | Serverless `pages/withRouter` gzip Size | 66.4 kB | 66.4 kB | -1 B | | Build Dir Size | 2.59 MB | 2.61 MB | ⚠️ +12.5 kB |
Diff for main.js ```diff @@ -1,20 +1,5 @@ (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), - /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,24 +54,193 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { +/***/ "8oxB": +/***/ (function(module, exports) { -"use strict"; +// shim for using process in browser +var process = module.exports = {}; + +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. + +var cachedSetTimeout; +var cachedClearTimeout; + +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); +} +function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); +} +(function () { + try { + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; + } + } catch (e) { + cachedSetTimeout = defaultSetTimout; + } + try { + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; + } else { + cachedClearTimeout = defaultClearTimeout; + } + } catch (e) { + cachedClearTimeout = defaultClearTimeout; + } +} ()) +function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); + } + } + + +} +function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); + } + } -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); + +} +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; + +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} + +function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + runClearTimeout(timeout); +} + +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } +}; + +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; +process.prependListener = noop; +process.prependOnceListener = noop; + +process.listeners = function (name) { return [] } + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; /***/ }), @@ -919,15 +1073,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -995,17 +1140,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -1083,27 +1217,11 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { "use strict"; - +/* WEBPACK VAR INJECTION */(function(process) { var _interopRequireDefault2 = __webpack_require__("KI45"); @@ -1122,12 +1240,10 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ +/* global document, window */ function supportsPreload(el) { @@ -1157,13 +1273,31 @@ function () { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set["default"](); this.pageRegisterEvents = (0, _mitt["default"])(); this.loadingRoutes = {}; this.promisedBuildId = _promise["default"].resolve(); - } + this.promisedBuildManifest = new _promise["default"](function (resolve) { + if (window.__BUILD_MANIFEST) { + resolve(window.__BUILD_MANIFEST); + } else { + window.__BUILD_MANIFEST_CB = function () { + resolve(window.__BUILD_MANIFEST); + }; + } + }); + } // Returns a promise for the dependencies for a particular route + (0, _createClass2["default"])(PageLoader, [{ + key: "getDependencies", + value: function getDependencies(route) { + return this.promisedBuildManifest.then(function (man) { + return man[route] && man[route].map(function (url) { + return "/_next/" + url; + }) || []; + }); + } + }, { key: "normalizeRoute", value: function normalizeRoute(route) { if (route[0] !== '/') { @@ -1213,13 +1347,26 @@ function () { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!_this3.loadingRoutes[route]) { - _this3.loadScript(route); + if (process.env.__NEXT_GRANULAR_CHUNKS) { + _this3.getDependencies(route).then(function (deps) { + deps.forEach(function (d) { + if (!document.querySelector("script[src^=\"" + d + "\"]")) { + _this3.loadScript(d, route, false); + } + }); + + _this3.loadRoute(route); + + _this3.loadingRoutes[route] = true; + }); + } else { + _this3.loadRoute(route); - _this3.loadingRoutes[route] = true; + _this3.loadingRoutes[route] = true; + } } }); } @@ -1249,14 +1396,14 @@ function () { }); } }, { - key: "loadScript", - value: function loadScript(route) { + key: "loadRoute", + value: function loadRoute(route) { var _this = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee() { - var scriptRoute, script, url; + var scriptRoute, url; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { @@ -1267,41 +1414,51 @@ function () { case 2: route = _this.normalizeRoute(route); scriptRoute = route === '/' ? '/index.js' : route + ".js"; - script = document.createElement('script'); - - if ( true && 'noModule' in script) { - script.type = 'module'; - scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); - } - url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = "anonymous"; - script.src = url; - - script.onerror = function () { - var error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; - _this.pageRegisterEvents.emit(route, { - error: error - }); - }; + _this.loadScript(url, route, true); - document.body.appendChild(script); - - case 11: + case 6: case "end": return _context.stop(); } } }, _callee); }))(); + } + }, { + key: "loadScript", + value: function loadScript(url, route, isPage) { + var _this5 = this; + + var script = document.createElement('script'); + + if ( true && 'noModule' in script) { + script.type = 'module'; // Only page bundle scripts need to have .module added to url, + // dependencies already have it added during build manifest creation + + if (isPage) url = url.replace(/\.js$/, '.module.js'); + } + + script.crossOrigin = "anonymous"; + script.src = url; + + script.onerror = function () { + var error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + + _this5.pageRegisterEvents.emit(route, { + error: error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. }, { key: "registerPage", value: function registerPage(route, regFn) { - var _this5 = this; + var _this6 = this; var register = function register() { try { @@ -1309,21 +1466,21 @@ function () { error = _regFn.error, page = _regFn.page; - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error, page: page }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error, page: page }); } catch (error) { - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error }); } @@ -1335,17 +1492,21 @@ function () { } }, { key: "prefetch", - value: function prefetch(route) { + value: function prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee2() { - var scriptRoute, cn; + var scriptRoute, url, cn; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: + _context2.next = 2; + return _this2.promisedBuildId; + + case 2: route = _this2.normalizeRoute(route); scriptRoute = (route === '/' ? '/index' : route) + ".js"; @@ -1353,51 +1514,72 @@ function () { scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); } - if (!(_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route))) { - _context2.next = 5; + url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. + + if (!(document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route))) { + _context2.next = 8; break; } return _context2.abrupt("return"); - case 5: - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE - - + case 8: if (!(cn = navigator.connection)) { - _context2.next = 9; + _context2.next = 11; break; } if (!((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData)) { - _context2.next = 9; + _context2.next = 11; break; } return _context2.abrupt("return"); - case 9: + case 11: + if (!(process.env.__NEXT_GRANULAR_CHUNKS && !isDependency)) { + _context2.next = 17; + break; + } + + ; + _context2.next = 15; + return _this2.getDependencies(route); + + case 15: + _context2.t0 = function (url) { + _this2.prefetch(url, true); + }; + + _context2.sent.forEach(_context2.t0); + + case 17: if (!hasPreload) { - _context2.next = 14; + _context2.next = 20; break; } - _context2.next = 12; - return _this2.promisedBuildId; + preloadScript(url); + return _context2.abrupt("return"); + + case 20: + if (!isDependency) { + _context2.next = 22; + break; + } - case 12: - preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute); return _context2.abrupt("return"); - case 14: + case 22: if (!(document.readyState === 'complete')) { - _context2.next = 18; + _context2.next = 26; break; } return _context2.abrupt("return", _this2.loadPage(route)["catch"](function () {})); - case 18: + case 26: return _context2.abrupt("return", new _promise["default"](function (resolve) { window.addEventListener('load', function () { _this2.loadPage(route).then(function () { @@ -1408,7 +1590,7 @@ function () { }); })); - case 19: + case 27: case "end": return _context2.stop(); } @@ -1421,6 +1603,7 @@ function () { }(); exports["default"] = PageLoader; +/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__("8oxB"))) /***/ }) ```
Diff for mainModern.js ```diff @@ -1,20 +1,5 @@ (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), - /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,24 +54,193 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { +/***/ "8oxB": +/***/ (function(module, exports) { -"use strict"; +// shim for using process in browser +var process = module.exports = {}; -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); +var cachedSetTimeout; +var cachedClearTimeout; + +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); +} +function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); +} +(function () { + try { + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; + } + } catch (e) { + cachedSetTimeout = defaultSetTimout; + } + try { + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; + } else { + cachedClearTimeout = defaultClearTimeout; + } + } catch (e) { + cachedClearTimeout = defaultClearTimeout; + } +} ()) +function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); + } + } + + +} +function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); + } + } + + + +} +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; + +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} + +function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + runClearTimeout(timeout); +} + +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } +}; + +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; +process.prependListener = noop; +process.prependOnceListener = noop; + +process.listeners = function (name) { return [] } + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; /***/ }), @@ -729,15 +883,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -792,17 +937,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -878,27 +1012,11 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { "use strict"; - +/* WEBPACK VAR INJECTION */(function(process) { var _interopRequireDefault = __webpack_require__("KI45"); @@ -909,12 +1027,10 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ +/* global document, window */ function supportsPreload(el) { @@ -941,10 +1057,23 @@ class PageLoader { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set.default(); this.pageRegisterEvents = (0, _mitt.default)(); this.loadingRoutes = {}; this.promisedBuildId = _promise.default.resolve(); + this.promisedBuildManifest = new _promise.default(resolve => { + if (window.__BUILD_MANIFEST) { + resolve(window.__BUILD_MANIFEST); + } else { + window.__BUILD_MANIFEST_CB = () => { + resolve(window.__BUILD_MANIFEST); + }; + } + }); + } // Returns a promise for the dependencies for a particular route + + + getDependencies(route) { + return this.promisedBuildManifest.then(man => man[route] && man[route].map(url => "/_next/" + url) || []); } normalizeRoute(route) { @@ -993,12 +1122,23 @@ class PageLoader { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!this.loadingRoutes[route]) { - this.loadScript(route); - this.loadingRoutes[route] = true; + if (process.env.__NEXT_GRANULAR_CHUNKS) { + this.getDependencies(route).then(deps => { + deps.forEach(d => { + if (!document.querySelector("script[src^=\"" + d + "\"]")) { + this.loadScript(d, route, false); + } + }); + this.loadRoute(route); + this.loadingRoutes[route] = true; + }); + } else { + this.loadRoute(route); + this.loadingRoutes[route] = true; + } } }); } @@ -1023,35 +1163,41 @@ class PageLoader { }); } - loadScript(route) { + loadRoute(route) { var _this = this; return (0, _asyncToGenerator2.default)(function* () { yield _this.promisedBuildId; route = _this.normalizeRoute(route); let scriptRoute = route === '/' ? '/index.js' : route + ".js"; - const script = document.createElement('script'); + const url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - if ( true && 'noModule' in script) { - script.type = 'module'; - scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); - } + _this.loadScript(url, route, true); + })(); + } - const url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = "anonymous"; - script.src = url; + loadScript(url, route, isPage) { + const script = document.createElement('script'); - script.onerror = () => { - const error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; + if ( true && 'noModule' in script) { + script.type = 'module'; // Only page bundle scripts need to have .module added to url, + // dependencies already have it added during build manifest creation - _this.pageRegisterEvents.emit(route, { - error - }); - }; + if (isPage) url = url.replace(/\.js$/, '.module.js'); + } - document.body.appendChild(script); - })(); + script.crossOrigin = "anonymous"; + script.src = url; + + script.onerror = () => { + const error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + this.pageRegisterEvents.emit(route, { + error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. @@ -1085,10 +1231,11 @@ class PageLoader { register(); } - prefetch(route) { + prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2.default)(function* () { + yield _this2.promisedBuildId; route = _this2.normalizeRoute(route); let scriptRoute = (route === '/' ? '/index' : route) + ".js"; @@ -1096,11 +1243,12 @@ class PageLoader { scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); } - if (_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route)) { - return; - } + const url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE + if (document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route)) { + return; + } // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE let cn; @@ -1110,14 +1258,26 @@ class PageLoader { if ((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData) { return; } + } + + if (process.env.__NEXT_GRANULAR_CHUNKS && !isDependency) { + ; + (yield _this2.getDependencies(route)).forEach(url => { + _this2.prefetch(url, true); + }); } // Feature detection is used to see if preload is supported // If not fall back to loading script tags before the page is loaded // https://caniuse.com/#feat=link-rel-preload if (hasPreload) { - yield _this2.promisedBuildId; - preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute); + preloadScript(url); + return; + } + + if (isDependency) { + // loadPage will automatically handle depencies, so no need to + // preload them manually return; } @@ -1136,6 +1296,7 @@ class PageLoader { } exports.default = PageLoader; +/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__("8oxB"))) /***/ }) ```
ijjk commented 5 years ago

Stats from current PR

Click to expand stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 22.9s | 22s | -880ms | | `node_modules` Size | 43.6 MB | 43.6 MB | ⚠️ +12.5 kB | | Total Bundle (main, webpack, commons) Size | 207 kB | 207 kB | -34 B | | Total Bundle (main, webpack, commons) gzip Size | 68.1 kB | 68.2 kB | ⚠️ +83 B | | Total Bundle (main, webpack, commons) Modern Size | 182 kB | 181 kB | -265 B | | Total Bundle (main, webpack, commons) Modern gzip Size | 59.9 kB | 59.9 kB | -16 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_app` Modern Size | 1.83 kB | 1.83 kB | ✓ | | Client `_app` gzip Modern Size | 890 B | 890 B | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `_error` Modern Size | 5.85 kB | 5.85 kB | ✓ | | Client `_error` gzip Modern Size | 2.33 kB | 2.33 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/index` Modern Size | 319 B | 319 B | ✓ | | Client `pages/index` gzip Modern Size | 254 B | 254 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/link` Modern Size | 3.7 kB | 3.7 kB | ✓ | | Client `pages/link` gzip Modern Size | 1.7 kB | 1.7 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/routerDirect` Modern Size | 411 B | 411 B | ✓ | | Client `pages/routerDirect` gzip Modern Size | 314 B | 314 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `pages/withRouter` Modern Size | 423 B | 423 B | ✓ | | Client `pages/withRouter` gzip Modern Size | 309 B | 309 B | ✓ | | Client `main` Size | 15.8 kB | 15.8 kB | -34 B | | Client `main` gzip Size | 5.46 kB | 5.54 kB | ⚠️ +83 B | | Client `main` Modern Size | 12.8 kB | 12.6 kB | -265 B | | Client `main` Modern gzip Size | 4.83 kB | 4.82 kB | -16 B | | Client `commons` Size | 188 kB | 188 kB | ✓ | | Client `commons` gzip Size | 61.3 kB | 61.3 kB | ✓ | | Client `commons` Modern Size | 169 kB | 169 kB | ✓ | | Client `commons` Modern gzip Size | 55.1 kB | 55.1 kB | ✓ | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Client `webpack` Modern Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` Modern gzip Size | 785 B | 785 B | ✓ | | Base Rendered Size | 2.76 kB | 2.76 kB | ✓ | | Build Dir Size | 1.39 MB | 1.39 MB | ⚠️ +2.41 kB |
Click to expand serverless stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 23.6s | 23.6s | ⚠️ +18ms | | `node_modules` Size | 43.6 MB | 43.6 MB | ⚠️ +12.5 kB | | Total Bundle (main, webpack, commons) Size | 207 kB | 207 kB | -34 B | | Total Bundle (main, webpack, commons) gzip Size | 68.1 kB | 68.2 kB | ⚠️ +82 B | | Total Bundle (main, webpack, commons) Modern Size | 182 kB | 181 kB | -265 B | | Total Bundle (main, webpack, commons) Modern gzip Size | 59.9 kB | 59.9 kB | -16 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | -1 B | | Client `_app` Modern Size | 1.83 kB | 1.83 kB | ✓ | | Client `_app` gzip Modern Size | 890 B | 890 B | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `_error` Modern Size | 5.85 kB | 5.85 kB | ✓ | | Client `_error` gzip Modern Size | 2.33 kB | 2.33 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/index` Modern Size | 319 B | 319 B | ✓ | | Client `pages/index` gzip Modern Size | 254 B | 254 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/link` Modern Size | 3.7 kB | 3.7 kB | ✓ | | Client `pages/link` gzip Modern Size | 1.7 kB | 1.7 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/routerDirect` Modern Size | 411 B | 411 B | ✓ | | Client `pages/routerDirect` gzip Modern Size | 314 B | 314 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 300 B | -1 B | | Client `pages/withRouter` Modern Size | 423 B | 423 B | ✓ | | Client `pages/withRouter` gzip Modern Size | 309 B | 309 B | ✓ | | Client `main` Size | 15.8 kB | 15.8 kB | -34 B | | Client `main` gzip Size | 5.46 kB | 5.54 kB | ⚠️ +83 B | | Client `main` Modern Size | 12.8 kB | 12.6 kB | -265 B | | Client `main` Modern gzip Size | 4.83 kB | 4.82 kB | -16 B | | Client `commons` Size | 188 kB | 188 kB | ✓ | | Client `commons` gzip Size | 61.3 kB | 61.3 kB | ✓ | | Client `commons` Modern Size | 169 kB | 169 kB | ✓ | | Client `commons` Modern gzip Size | 55.1 kB | 55.1 kB | ✓ | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Client `webpack` Modern Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` Modern gzip Size | 785 B | 785 B | ✓ | | Serverless `pages/link` Size | 255 kB | 255 kB | ✓ | | Serverless `pages/link` gzip Size | 68.6 kB | 68.6 kB | ✓ | | Serverless `pages/index` Size | 248 kB | 248 kB | ✓ | | Serverless `pages/index` gzip Size | 66.4 kB | 66.4 kB | ✓ | | Serverless `pages/_error` Size | 247 kB | 247 kB | ✓ | | Serverless `pages/_error` gzip Size | 66.1 kB | 66.1 kB | ✓ | | Serverless `pages/routerDirect` Size | 248 kB | 248 kB | ✓ | | Serverless `pages/routerDirect` gzip Size | 66.3 kB | 66.3 kB | ✓ | | Serverless `pages/withRouter` Size | 248 kB | 248 kB | ✓ | | Serverless `pages/withRouter` gzip Size | 66.4 kB | 66.4 kB | -1 B | | Build Dir Size | 2.59 MB | 2.6 MB | ⚠️ +2.41 kB |
Diff for main.js ```diff @@ -1,20 +1,5 @@ (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), - /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,28 +54,6 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; - -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); - - -/***/ }), - /***/ "BMP1": /***/ (function(module, exports, __webpack_require__) { @@ -919,15 +882,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -995,17 +949,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -1083,22 +1026,6 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { @@ -1122,12 +1049,10 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ +/* global document, window */ function supportsPreload(el) { @@ -1157,13 +1082,31 @@ function () { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set["default"](); this.pageRegisterEvents = (0, _mitt["default"])(); this.loadingRoutes = {}; this.promisedBuildId = _promise["default"].resolve(); - } + this.promisedBuildManifest = new _promise["default"](function (resolve) { + if (window.__BUILD_MANIFEST) { + resolve(window.__BUILD_MANIFEST); + } else { + window.__BUILD_MANIFEST_CB = function () { + resolve(window.__BUILD_MANIFEST); + }; + } + }); + } // Returns a promise for the dependencies for a particular route + (0, _createClass2["default"])(PageLoader, [{ + key: "getDependencies", + value: function getDependencies(route) { + return this.promisedBuildManifest.then(function (man) { + return man[route] && man[route].map(function (url) { + return "/_next/" + url; + }) || []; + }); + } + }, { key: "normalizeRoute", value: function normalizeRoute(route) { if (route[0] !== '/') { @@ -1213,13 +1156,14 @@ function () { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!_this3.loadingRoutes[route]) { - _this3.loadScript(route); + if (false) {} else { + _this3.loadRoute(route); - _this3.loadingRoutes[route] = true; + _this3.loadingRoutes[route] = true; + } } }); } @@ -1249,14 +1193,14 @@ function () { }); } }, { - key: "loadScript", - value: function loadScript(route) { + key: "loadRoute", + value: function loadRoute(route) { var _this = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee() { - var scriptRoute, script, url; + var scriptRoute, url; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { @@ -1267,41 +1211,51 @@ function () { case 2: route = _this.normalizeRoute(route); scriptRoute = route === '/' ? '/index.js' : route + ".js"; - script = document.createElement('script'); - - if ( true && 'noModule' in script) { - script.type = 'module'; - scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); - } - url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = "anonymous"; - script.src = url; - - script.onerror = function () { - var error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; - _this.pageRegisterEvents.emit(route, { - error: error - }); - }; + _this.loadScript(url, route, true); - document.body.appendChild(script); - - case 11: + case 6: case "end": return _context.stop(); } } }, _callee); }))(); + } + }, { + key: "loadScript", + value: function loadScript(url, route, isPage) { + var _this5 = this; + + var script = document.createElement('script'); + + if ( true && 'noModule' in script) { + script.type = 'module'; // Only page bundle scripts need to have .module added to url, + // dependencies already have it added during build manifest creation + + if (isPage) url = url.replace(/\.js$/, '.module.js'); + } + + script.crossOrigin = "anonymous"; + script.src = url; + + script.onerror = function () { + var error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + + _this5.pageRegisterEvents.emit(route, { + error: error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. }, { key: "registerPage", value: function registerPage(route, regFn) { - var _this5 = this; + var _this6 = this; var register = function register() { try { @@ -1309,21 +1263,21 @@ function () { error = _regFn.error, page = _regFn.page; - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error, page: page }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error, page: page }); } catch (error) { - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error }); } @@ -1335,17 +1289,21 @@ function () { } }, { key: "prefetch", - value: function prefetch(route) { + value: function prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee2() { - var scriptRoute, cn; + var scriptRoute, url, cn; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: + _context2.next = 2; + return _this2.promisedBuildId; + + case 2: route = _this2.normalizeRoute(route); scriptRoute = (route === '/' ? '/index' : route) + ".js"; @@ -1353,51 +1311,72 @@ function () { scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); } - if (!(_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route))) { - _context2.next = 5; + url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. + + if (!(document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route))) { + _context2.next = 8; break; } return _context2.abrupt("return"); - case 5: - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE - - + case 8: if (!(cn = navigator.connection)) { - _context2.next = 9; + _context2.next = 11; break; } if (!((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData)) { - _context2.next = 9; + _context2.next = 11; break; } return _context2.abrupt("return"); - case 9: + case 11: + if (true) { + _context2.next = 17; + break; + } + + ; + _context2.next = 15; + return _this2.getDependencies(route); + + case 15: + _context2.t0 = function (url) { + _this2.prefetch(url, true); + }; + + _context2.sent.forEach(_context2.t0); + + case 17: if (!hasPreload) { - _context2.next = 14; + _context2.next = 20; break; } - _context2.next = 12; - return _this2.promisedBuildId; + preloadScript(url); + return _context2.abrupt("return"); + + case 20: + if (!isDependency) { + _context2.next = 22; + break; + } - case 12: - preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute); return _context2.abrupt("return"); - case 14: + case 22: if (!(document.readyState === 'complete')) { - _context2.next = 18; + _context2.next = 26; break; } return _context2.abrupt("return", _this2.loadPage(route)["catch"](function () {})); - case 18: + case 26: return _context2.abrupt("return", new _promise["default"](function (resolve) { window.addEventListener('load', function () { _this2.loadPage(route).then(function () { @@ -1408,7 +1387,7 @@ function () { }); })); - case 19: + case 27: case "end": return _context2.stop(); } ```
Diff for mainModern.js ```diff @@ -1,20 +1,5 @@ (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), - /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,28 +54,6 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; - -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); - - -/***/ }), - /***/ "BMP1": /***/ (function(module, exports, __webpack_require__) { @@ -729,15 +692,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -792,17 +746,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -878,22 +821,6 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { @@ -909,12 +836,10 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ +/* global document, window */ function supportsPreload(el) { @@ -941,10 +866,23 @@ class PageLoader { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set.default(); this.pageRegisterEvents = (0, _mitt.default)(); this.loadingRoutes = {}; this.promisedBuildId = _promise.default.resolve(); + this.promisedBuildManifest = new _promise.default(resolve => { + if (window.__BUILD_MANIFEST) { + resolve(window.__BUILD_MANIFEST); + } else { + window.__BUILD_MANIFEST_CB = () => { + resolve(window.__BUILD_MANIFEST); + }; + } + }); + } // Returns a promise for the dependencies for a particular route + + + getDependencies(route) { + return this.promisedBuildManifest.then(man => man[route] && man[route].map(url => "/_next/" + url) || []); } normalizeRoute(route) { @@ -993,12 +931,13 @@ class PageLoader { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!this.loadingRoutes[route]) { - this.loadScript(route); - this.loadingRoutes[route] = true; + if (false) {} else { + this.loadRoute(route); + this.loadingRoutes[route] = true; + } } }); } @@ -1023,35 +962,41 @@ class PageLoader { }); } - loadScript(route) { + loadRoute(route) { var _this = this; return (0, _asyncToGenerator2.default)(function* () { yield _this.promisedBuildId; route = _this.normalizeRoute(route); let scriptRoute = route === '/' ? '/index.js' : route + ".js"; - const script = document.createElement('script'); + const url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - if ( true && 'noModule' in script) { - script.type = 'module'; - scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); - } + _this.loadScript(url, route, true); + })(); + } - const url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = "anonymous"; - script.src = url; + loadScript(url, route, isPage) { + const script = document.createElement('script'); - script.onerror = () => { - const error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; + if ( true && 'noModule' in script) { + script.type = 'module'; // Only page bundle scripts need to have .module added to url, + // dependencies already have it added during build manifest creation - _this.pageRegisterEvents.emit(route, { - error - }); - }; + if (isPage) url = url.replace(/\.js$/, '.module.js'); + } - document.body.appendChild(script); - })(); + script.crossOrigin = "anonymous"; + script.src = url; + + script.onerror = () => { + const error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + this.pageRegisterEvents.emit(route, { + error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. @@ -1085,10 +1030,11 @@ class PageLoader { register(); } - prefetch(route) { + prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2.default)(function* () { + yield _this2.promisedBuildId; route = _this2.normalizeRoute(route); let scriptRoute = (route === '/' ? '/index' : route) + ".js"; @@ -1096,11 +1042,12 @@ class PageLoader { scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); } - if (_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route)) { - return; - } + const url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE + if (document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route)) { + return; + } // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE let cn; @@ -1110,14 +1057,21 @@ class PageLoader { if ((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData) { return; } - } // Feature detection is used to see if preload is supported + } + + if (false) {} // Feature detection is used to see if preload is supported // If not fall back to loading script tags before the page is loaded // https://caniuse.com/#feat=link-rel-preload if (hasPreload) { - yield _this2.promisedBuildId; - preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute); + preloadScript(url); + return; + } + + if (isDependency) { + // loadPage will automatically handle depencies, so no need to + // preload them manually return; } ```
ijjk commented 5 years ago

Stats from current PR

Click to expand stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 21.5s | 21.9s | ⚠️ +377ms | | `node_modules` Size | 43.6 MB | 43.6 MB | ⚠️ +12.5 kB | | Total Bundle (main, webpack, commons) Size | 207 kB | 207 kB | -34 B | | Total Bundle (main, webpack, commons) gzip Size | 68.1 kB | 68.2 kB | ⚠️ +82 B | | Total Bundle (main, webpack, commons) Modern Size | 182 kB | 181 kB | -265 B | | Total Bundle (main, webpack, commons) Modern gzip Size | 59.9 kB | 59.9 kB | -16 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ⚠️ +1 B | | Client `_app` Modern Size | 1.83 kB | 1.83 kB | ✓ | | Client `_app` gzip Modern Size | 890 B | 890 B | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `_error` Modern Size | 5.85 kB | 5.85 kB | ✓ | | Client `_error` gzip Modern Size | 2.33 kB | 2.33 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/index` Modern Size | 319 B | 319 B | ✓ | | Client `pages/index` gzip Modern Size | 254 B | 254 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/link` Modern Size | 3.7 kB | 3.7 kB | ✓ | | Client `pages/link` gzip Modern Size | 1.7 kB | 1.7 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/routerDirect` Modern Size | 411 B | 411 B | ✓ | | Client `pages/routerDirect` gzip Modern Size | 314 B | 314 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 300 B | 301 B | ⚠️ +1 B | | Client `pages/withRouter` Modern Size | 423 B | 423 B | ✓ | | Client `pages/withRouter` gzip Modern Size | 309 B | 309 B | ✓ | | Client `main` Size | 15.8 kB | 15.8 kB | -34 B | | Client `main` gzip Size | 5.46 kB | 5.54 kB | ⚠️ +81 B | | Client `main` Modern Size | 12.8 kB | 12.6 kB | -265 B | | Client `main` Modern gzip Size | 4.83 kB | 4.82 kB | -16 B | | Client `commons` Size | 188 kB | 188 kB | ✓ | | Client `commons` gzip Size | 61.3 kB | 61.3 kB | ✓ | | Client `commons` Modern Size | 169 kB | 169 kB | ✓ | | Client `commons` Modern gzip Size | 55.1 kB | 55.1 kB | ✓ | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Client `webpack` Modern Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` Modern gzip Size | 785 B | 785 B | ✓ | | Base Rendered Size | 2.76 kB | 2.76 kB | ✓ | | Build Dir Size | 1.39 MB | 1.39 MB | ⚠️ +2.41 kB |
Click to expand serverless stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 23.8s | 23.2s | -583ms | | `node_modules` Size | 43.6 MB | 43.6 MB | ⚠️ +12.5 kB | | Total Bundle (main, webpack, commons) Size | 207 kB | 207 kB | -34 B | | Total Bundle (main, webpack, commons) gzip Size | 68.1 kB | 68.2 kB | ⚠️ +83 B | | Total Bundle (main, webpack, commons) Modern Size | 182 kB | 181 kB | -265 B | | Total Bundle (main, webpack, commons) Modern gzip Size | 59.9 kB | 59.9 kB | -16 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_app` Modern Size | 1.83 kB | 1.83 kB | ✓ | | Client `_app` gzip Modern Size | 890 B | 890 B | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `_error` Modern Size | 5.85 kB | 5.85 kB | ✓ | | Client `_error` gzip Modern Size | 2.33 kB | 2.33 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/index` Modern Size | 319 B | 319 B | ✓ | | Client `pages/index` gzip Modern Size | 254 B | 254 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/link` Modern Size | 3.7 kB | 3.7 kB | ✓ | | Client `pages/link` gzip Modern Size | 1.7 kB | 1.7 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/routerDirect` Modern Size | 411 B | 411 B | ✓ | | Client `pages/routerDirect` gzip Modern Size | 314 B | 314 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `pages/withRouter` Modern Size | 423 B | 423 B | ✓ | | Client `pages/withRouter` gzip Modern Size | 309 B | 309 B | ✓ | | Client `main` Size | 15.8 kB | 15.8 kB | -34 B | | Client `main` gzip Size | 5.46 kB | 5.54 kB | ⚠️ +83 B | | Client `main` Modern Size | 12.8 kB | 12.6 kB | -265 B | | Client `main` Modern gzip Size | 4.83 kB | 4.82 kB | -16 B | | Client `commons` Size | 188 kB | 188 kB | ✓ | | Client `commons` gzip Size | 61.3 kB | 61.3 kB | ✓ | | Client `commons` Modern Size | 169 kB | 169 kB | ✓ | | Client `commons` Modern gzip Size | 55.1 kB | 55.1 kB | ✓ | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Client `webpack` Modern Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` Modern gzip Size | 785 B | 785 B | ✓ | | Serverless `pages/link` Size | 255 kB | 255 kB | ✓ | | Serverless `pages/link` gzip Size | 68.6 kB | 68.6 kB | ⚠️ +2 B | | Serverless `pages/index` Size | 248 kB | 248 kB | ✓ | | Serverless `pages/index` gzip Size | 66.4 kB | 66.4 kB | ⚠️ +3 B | | Serverless `pages/_error` Size | 247 kB | 247 kB | ✓ | | Serverless `pages/_error` gzip Size | 66.1 kB | 66.1 kB | ⚠️ +2 B | | Serverless `pages/routerDirect` Size | 248 kB | 248 kB | ✓ | | Serverless `pages/routerDirect` gzip Size | 66.3 kB | 66.3 kB | ⚠️ +2 B | | Serverless `pages/withRouter` Size | 248 kB | 248 kB | ✓ | | Serverless `pages/withRouter` gzip Size | 66.4 kB | 66.4 kB | ⚠️ +2 B | | Build Dir Size | 2.59 MB | 2.6 MB | ⚠️ +2.41 kB |
Diff for main.js ```diff @@ -1,20 +1,5 @@ (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), - /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,28 +54,6 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; - -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); - - -/***/ }), - /***/ "BMP1": /***/ (function(module, exports, __webpack_require__) { @@ -919,15 +882,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -995,17 +949,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -1083,22 +1026,6 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { @@ -1122,12 +1049,10 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ +/* global document, window */ function supportsPreload(el) { @@ -1157,13 +1082,31 @@ function () { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set["default"](); this.pageRegisterEvents = (0, _mitt["default"])(); this.loadingRoutes = {}; this.promisedBuildId = _promise["default"].resolve(); - } + this.promisedBuildManifest = new _promise["default"](function (resolve) { + if (window.__BUILD_MANIFEST) { + resolve(window.__BUILD_MANIFEST); + } else { + window.__BUILD_MANIFEST_CB = function () { + resolve(window.__BUILD_MANIFEST); + }; + } + }); + } // Returns a promise for the dependencies for a particular route + (0, _createClass2["default"])(PageLoader, [{ + key: "getDependencies", + value: function getDependencies(route) { + return this.promisedBuildManifest.then(function (man) { + return man[route] && man[route].map(function (url) { + return "/_next/" + url; + }) || []; + }); + } + }, { key: "normalizeRoute", value: function normalizeRoute(route) { if (route[0] !== '/') { @@ -1213,13 +1156,14 @@ function () { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!_this3.loadingRoutes[route]) { - _this3.loadScript(route); + if (false) {} else { + _this3.loadRoute(route); - _this3.loadingRoutes[route] = true; + _this3.loadingRoutes[route] = true; + } } }); } @@ -1249,14 +1193,14 @@ function () { }); } }, { - key: "loadScript", - value: function loadScript(route) { + key: "loadRoute", + value: function loadRoute(route) { var _this = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee() { - var scriptRoute, script, url; + var scriptRoute, url; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { @@ -1267,41 +1211,51 @@ function () { case 2: route = _this.normalizeRoute(route); scriptRoute = route === '/' ? '/index.js' : route + ".js"; - script = document.createElement('script'); - - if ( true && 'noModule' in script) { - script.type = 'module'; - scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); - } - url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = "anonymous"; - script.src = url; - - script.onerror = function () { - var error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; - _this.pageRegisterEvents.emit(route, { - error: error - }); - }; + _this.loadScript(url, route, true); - document.body.appendChild(script); - - case 11: + case 6: case "end": return _context.stop(); } } }, _callee); }))(); + } + }, { + key: "loadScript", + value: function loadScript(url, route, isPage) { + var _this5 = this; + + var script = document.createElement('script'); + + if ( true && 'noModule' in script) { + script.type = 'module'; // Only page bundle scripts need to have .module added to url, + // dependencies already have it added during build manifest creation + + if (isPage) url = url.replace(/\.js$/, '.module.js'); + } + + script.crossOrigin = "anonymous"; + script.src = url; + + script.onerror = function () { + var error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + + _this5.pageRegisterEvents.emit(route, { + error: error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. }, { key: "registerPage", value: function registerPage(route, regFn) { - var _this5 = this; + var _this6 = this; var register = function register() { try { @@ -1309,21 +1263,21 @@ function () { error = _regFn.error, page = _regFn.page; - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error, page: page }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error, page: page }); } catch (error) { - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error }); } @@ -1335,17 +1289,21 @@ function () { } }, { key: "prefetch", - value: function prefetch(route) { + value: function prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee2() { - var scriptRoute, cn; + var scriptRoute, url, cn; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: + _context2.next = 2; + return _this2.promisedBuildId; + + case 2: route = _this2.normalizeRoute(route); scriptRoute = (route === '/' ? '/index' : route) + ".js"; @@ -1353,51 +1311,72 @@ function () { scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); } - if (!(_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route))) { - _context2.next = 5; + url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. + + if (!(document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route))) { + _context2.next = 8; break; } return _context2.abrupt("return"); - case 5: - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE - - + case 8: if (!(cn = navigator.connection)) { - _context2.next = 9; + _context2.next = 11; break; } if (!((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData)) { - _context2.next = 9; + _context2.next = 11; break; } return _context2.abrupt("return"); - case 9: + case 11: + if (true) { + _context2.next = 17; + break; + } + + ; + _context2.next = 15; + return _this2.getDependencies(route); + + case 15: + _context2.t0 = function (url) { + _this2.prefetch(url, true); + }; + + _context2.sent.forEach(_context2.t0); + + case 17: if (!hasPreload) { - _context2.next = 14; + _context2.next = 20; break; } - _context2.next = 12; - return _this2.promisedBuildId; + preloadScript(url); + return _context2.abrupt("return"); + + case 20: + if (!isDependency) { + _context2.next = 22; + break; + } - case 12: - preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute); return _context2.abrupt("return"); - case 14: + case 22: if (!(document.readyState === 'complete')) { - _context2.next = 18; + _context2.next = 26; break; } return _context2.abrupt("return", _this2.loadPage(route)["catch"](function () {})); - case 18: + case 26: return _context2.abrupt("return", new _promise["default"](function (resolve) { window.addEventListener('load', function () { _this2.loadPage(route).then(function () { @@ -1408,7 +1387,7 @@ function () { }); })); - case 19: + case 27: case "end": return _context2.stop(); } ```
Diff for mainModern.js ```diff @@ -1,20 +1,5 @@ (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), - /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,28 +54,6 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; - -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); - - -/***/ }), - /***/ "BMP1": /***/ (function(module, exports, __webpack_require__) { @@ -729,15 +692,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -792,17 +746,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -878,22 +821,6 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { @@ -909,12 +836,10 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ +/* global document, window */ function supportsPreload(el) { @@ -941,10 +866,23 @@ class PageLoader { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set.default(); this.pageRegisterEvents = (0, _mitt.default)(); this.loadingRoutes = {}; this.promisedBuildId = _promise.default.resolve(); + this.promisedBuildManifest = new _promise.default(resolve => { + if (window.__BUILD_MANIFEST) { + resolve(window.__BUILD_MANIFEST); + } else { + window.__BUILD_MANIFEST_CB = () => { + resolve(window.__BUILD_MANIFEST); + }; + } + }); + } // Returns a promise for the dependencies for a particular route + + + getDependencies(route) { + return this.promisedBuildManifest.then(man => man[route] && man[route].map(url => "/_next/" + url) || []); } normalizeRoute(route) { @@ -993,12 +931,13 @@ class PageLoader { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!this.loadingRoutes[route]) { - this.loadScript(route); - this.loadingRoutes[route] = true; + if (false) {} else { + this.loadRoute(route); + this.loadingRoutes[route] = true; + } } }); } @@ -1023,35 +962,41 @@ class PageLoader { }); } - loadScript(route) { + loadRoute(route) { var _this = this; return (0, _asyncToGenerator2.default)(function* () { yield _this.promisedBuildId; route = _this.normalizeRoute(route); let scriptRoute = route === '/' ? '/index.js' : route + ".js"; - const script = document.createElement('script'); + const url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - if ( true && 'noModule' in script) { - script.type = 'module'; - scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); - } + _this.loadScript(url, route, true); + })(); + } - const url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = "anonymous"; - script.src = url; + loadScript(url, route, isPage) { + const script = document.createElement('script'); - script.onerror = () => { - const error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; + if ( true && 'noModule' in script) { + script.type = 'module'; // Only page bundle scripts need to have .module added to url, + // dependencies already have it added during build manifest creation - _this.pageRegisterEvents.emit(route, { - error - }); - }; + if (isPage) url = url.replace(/\.js$/, '.module.js'); + } - document.body.appendChild(script); - })(); + script.crossOrigin = "anonymous"; + script.src = url; + + script.onerror = () => { + const error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + this.pageRegisterEvents.emit(route, { + error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. @@ -1085,10 +1030,11 @@ class PageLoader { register(); } - prefetch(route) { + prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2.default)(function* () { + yield _this2.promisedBuildId; route = _this2.normalizeRoute(route); let scriptRoute = (route === '/' ? '/index' : route) + ".js"; @@ -1096,11 +1042,12 @@ class PageLoader { scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); } - if (_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route)) { - return; - } + const url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE + if (document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route)) { + return; + } // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE let cn; @@ -1110,14 +1057,21 @@ class PageLoader { if ((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData) { return; } - } // Feature detection is used to see if preload is supported + } + + if (false) {} // Feature detection is used to see if preload is supported // If not fall back to loading script tags before the page is loaded // https://caniuse.com/#feat=link-rel-preload if (hasPreload) { - yield _this2.promisedBuildId; - preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute); + preloadScript(url); + return; + } + + if (isDependency) { + // loadPage will automatically handle depencies, so no need to + // preload them manually return; } ```
ijjk commented 5 years ago

Stats from current PR

Click to expand stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 20.5s | 22.1s | ⚠️ +1.6s | | `node_modules` Size | 43.6 MB | 43.6 MB | ⚠️ +12.5 kB | | Total Bundle (main, webpack, commons) Size | 207 kB | 207 kB | -34 B | | Total Bundle (main, webpack, commons) gzip Size | 68.1 kB | 68.2 kB | ⚠️ +82 B | | Total Bundle (main, webpack, commons) Modern Size | 182 kB | 181 kB | -265 B | | Total Bundle (main, webpack, commons) Modern gzip Size | 59.9 kB | 59.9 kB | -16 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ⚠️ +1 B | | Client `_app` Modern Size | 1.83 kB | 1.83 kB | ✓ | | Client `_app` gzip Modern Size | 890 B | 890 B | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `_error` Modern Size | 5.85 kB | 5.85 kB | ✓ | | Client `_error` gzip Modern Size | 2.33 kB | 2.33 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/index` Modern Size | 319 B | 319 B | ✓ | | Client `pages/index` gzip Modern Size | 254 B | 254 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/link` Modern Size | 3.7 kB | 3.7 kB | ✓ | | Client `pages/link` gzip Modern Size | 1.7 kB | 1.7 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/routerDirect` Modern Size | 411 B | 411 B | ✓ | | Client `pages/routerDirect` gzip Modern Size | 314 B | 314 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 300 B | 301 B | ⚠️ +1 B | | Client `pages/withRouter` Modern Size | 423 B | 423 B | ✓ | | Client `pages/withRouter` gzip Modern Size | 309 B | 309 B | ✓ | | Client `main` Size | 15.8 kB | 15.8 kB | -34 B | | Client `main` gzip Size | 5.46 kB | 5.54 kB | ⚠️ +81 B | | Client `main` Modern Size | 12.8 kB | 12.6 kB | -265 B | | Client `main` Modern gzip Size | 4.83 kB | 4.82 kB | -16 B | | Client `commons` Size | 188 kB | 188 kB | ✓ | | Client `commons` gzip Size | 61.3 kB | 61.3 kB | ✓ | | Client `commons` Modern Size | 169 kB | 169 kB | ✓ | | Client `commons` Modern gzip Size | 55.1 kB | 55.1 kB | ✓ | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Client `webpack` Modern Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` Modern gzip Size | 785 B | 785 B | ✓ | | Base Rendered Size | 2.76 kB | 2.76 kB | ✓ | | Build Dir Size | 1.39 MB | 1.39 MB | ⚠️ +2.41 kB |
Click to expand serverless stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 22.2s | 22s | -192ms | | `node_modules` Size | 43.6 MB | 43.6 MB | ⚠️ +12.5 kB | | Total Bundle (main, webpack, commons) Size | 207 kB | 207 kB | -34 B | | Total Bundle (main, webpack, commons) gzip Size | 68.1 kB | 68.2 kB | ⚠️ +83 B | | Total Bundle (main, webpack, commons) Modern Size | 182 kB | 181 kB | -265 B | | Total Bundle (main, webpack, commons) Modern gzip Size | 59.9 kB | 59.9 kB | -16 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_app` Modern Size | 1.83 kB | 1.83 kB | ✓ | | Client `_app` gzip Modern Size | 890 B | 890 B | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `_error` Modern Size | 5.85 kB | 5.85 kB | ✓ | | Client `_error` gzip Modern Size | 2.33 kB | 2.33 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/index` Modern Size | 319 B | 319 B | ✓ | | Client `pages/index` gzip Modern Size | 254 B | 254 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/link` Modern Size | 3.7 kB | 3.7 kB | ✓ | | Client `pages/link` gzip Modern Size | 1.7 kB | 1.7 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/routerDirect` Modern Size | 411 B | 411 B | ✓ | | Client `pages/routerDirect` gzip Modern Size | 314 B | 314 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `pages/withRouter` Modern Size | 423 B | 423 B | ✓ | | Client `pages/withRouter` gzip Modern Size | 309 B | 309 B | ✓ | | Client `main` Size | 15.8 kB | 15.8 kB | -34 B | | Client `main` gzip Size | 5.46 kB | 5.54 kB | ⚠️ +83 B | | Client `main` Modern Size | 12.8 kB | 12.6 kB | -265 B | | Client `main` Modern gzip Size | 4.83 kB | 4.82 kB | -16 B | | Client `commons` Size | 188 kB | 188 kB | ✓ | | Client `commons` gzip Size | 61.3 kB | 61.3 kB | ✓ | | Client `commons` Modern Size | 169 kB | 169 kB | ✓ | | Client `commons` Modern gzip Size | 55.1 kB | 55.1 kB | ✓ | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Client `webpack` Modern Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` Modern gzip Size | 785 B | 785 B | ✓ | | Serverless `pages/link` Size | 255 kB | 255 kB | ✓ | | Serverless `pages/link` gzip Size | 68.6 kB | 68.6 kB | ⚠️ +1 B | | Serverless `pages/index` Size | 248 kB | 248 kB | ✓ | | Serverless `pages/index` gzip Size | 66.4 kB | 66.4 kB | ⚠️ +1 B | | Serverless `pages/_error` Size | 247 kB | 247 kB | ✓ | | Serverless `pages/_error` gzip Size | 66.1 kB | 66.1 kB | ⚠️ +1 B | | Serverless `pages/routerDirect` Size | 248 kB | 248 kB | ✓ | | Serverless `pages/routerDirect` gzip Size | 66.3 kB | 66.3 kB | ⚠️ +2 B | | Serverless `pages/withRouter` Size | 248 kB | 248 kB | ✓ | | Serverless `pages/withRouter` gzip Size | 66.4 kB | 66.4 kB | ⚠️ +1 B | | Build Dir Size | 2.59 MB | 2.6 MB | ⚠️ +2.41 kB |
Diff for main.js ```diff @@ -1,20 +1,5 @@ (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), - /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,28 +54,6 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; - -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); - - -/***/ }), - /***/ "BMP1": /***/ (function(module, exports, __webpack_require__) { @@ -919,15 +882,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -995,17 +949,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -1083,22 +1026,6 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { @@ -1122,12 +1049,10 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ +/* global document, window */ function supportsPreload(el) { @@ -1157,13 +1082,31 @@ function () { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set["default"](); this.pageRegisterEvents = (0, _mitt["default"])(); this.loadingRoutes = {}; this.promisedBuildId = _promise["default"].resolve(); - } + this.promisedBuildManifest = new _promise["default"](function (resolve) { + if (window.__BUILD_MANIFEST) { + resolve(window.__BUILD_MANIFEST); + } else { + window.__BUILD_MANIFEST_CB = function () { + resolve(window.__BUILD_MANIFEST); + }; + } + }); + } // Returns a promise for the dependencies for a particular route + (0, _createClass2["default"])(PageLoader, [{ + key: "getDependencies", + value: function getDependencies(route) { + return this.promisedBuildManifest.then(function (man) { + return man[route] && man[route].map(function (url) { + return "/_next/" + url; + }) || []; + }); + } + }, { key: "normalizeRoute", value: function normalizeRoute(route) { if (route[0] !== '/') { @@ -1213,13 +1156,14 @@ function () { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!_this3.loadingRoutes[route]) { - _this3.loadScript(route); + if (false) {} else { + _this3.loadRoute(route); - _this3.loadingRoutes[route] = true; + _this3.loadingRoutes[route] = true; + } } }); } @@ -1249,14 +1193,14 @@ function () { }); } }, { - key: "loadScript", - value: function loadScript(route) { + key: "loadRoute", + value: function loadRoute(route) { var _this = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee() { - var scriptRoute, script, url; + var scriptRoute, url; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { @@ -1267,41 +1211,51 @@ function () { case 2: route = _this.normalizeRoute(route); scriptRoute = route === '/' ? '/index.js' : route + ".js"; - script = document.createElement('script'); - - if ( true && 'noModule' in script) { - script.type = 'module'; - scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); - } - url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = "anonymous"; - script.src = url; - - script.onerror = function () { - var error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; - _this.pageRegisterEvents.emit(route, { - error: error - }); - }; + _this.loadScript(url, route, true); - document.body.appendChild(script); - - case 11: + case 6: case "end": return _context.stop(); } } }, _callee); }))(); + } + }, { + key: "loadScript", + value: function loadScript(url, route, isPage) { + var _this5 = this; + + var script = document.createElement('script'); + + if ( true && 'noModule' in script) { + script.type = 'module'; // Only page bundle scripts need to have .module added to url, + // dependencies already have it added during build manifest creation + + if (isPage) url = url.replace(/\.js$/, '.module.js'); + } + + script.crossOrigin = "anonymous"; + script.src = url; + + script.onerror = function () { + var error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + + _this5.pageRegisterEvents.emit(route, { + error: error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. }, { key: "registerPage", value: function registerPage(route, regFn) { - var _this5 = this; + var _this6 = this; var register = function register() { try { @@ -1309,21 +1263,21 @@ function () { error = _regFn.error, page = _regFn.page; - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error, page: page }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error, page: page }); } catch (error) { - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error }); } @@ -1335,17 +1289,21 @@ function () { } }, { key: "prefetch", - value: function prefetch(route) { + value: function prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee2() { - var scriptRoute, cn; + var scriptRoute, url, cn; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: + _context2.next = 2; + return _this2.promisedBuildId; + + case 2: route = _this2.normalizeRoute(route); scriptRoute = (route === '/' ? '/index' : route) + ".js"; @@ -1353,51 +1311,72 @@ function () { scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); } - if (!(_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route))) { - _context2.next = 5; + url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. + + if (!(document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route))) { + _context2.next = 8; break; } return _context2.abrupt("return"); - case 5: - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE - - + case 8: if (!(cn = navigator.connection)) { - _context2.next = 9; + _context2.next = 11; break; } if (!((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData)) { - _context2.next = 9; + _context2.next = 11; break; } return _context2.abrupt("return"); - case 9: + case 11: + if (true) { + _context2.next = 17; + break; + } + + ; + _context2.next = 15; + return _this2.getDependencies(route); + + case 15: + _context2.t0 = function (url) { + _this2.prefetch(url, true); + }; + + _context2.sent.forEach(_context2.t0); + + case 17: if (!hasPreload) { - _context2.next = 14; + _context2.next = 20; break; } - _context2.next = 12; - return _this2.promisedBuildId; + preloadScript(url); + return _context2.abrupt("return"); + + case 20: + if (!isDependency) { + _context2.next = 22; + break; + } - case 12: - preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute); return _context2.abrupt("return"); - case 14: + case 22: if (!(document.readyState === 'complete')) { - _context2.next = 18; + _context2.next = 26; break; } return _context2.abrupt("return", _this2.loadPage(route)["catch"](function () {})); - case 18: + case 26: return _context2.abrupt("return", new _promise["default"](function (resolve) { window.addEventListener('load', function () { _this2.loadPage(route).then(function () { @@ -1408,7 +1387,7 @@ function () { }); })); - case 19: + case 27: case "end": return _context2.stop(); } ```
Diff for mainModern.js ```diff @@ -1,20 +1,5 @@ (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), - /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,28 +54,6 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; - -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); - - -/***/ }), - /***/ "BMP1": /***/ (function(module, exports, __webpack_require__) { @@ -729,15 +692,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -792,17 +746,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -878,22 +821,6 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { @@ -909,12 +836,10 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ +/* global document, window */ function supportsPreload(el) { @@ -941,10 +866,23 @@ class PageLoader { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set.default(); this.pageRegisterEvents = (0, _mitt.default)(); this.loadingRoutes = {}; this.promisedBuildId = _promise.default.resolve(); + this.promisedBuildManifest = new _promise.default(resolve => { + if (window.__BUILD_MANIFEST) { + resolve(window.__BUILD_MANIFEST); + } else { + window.__BUILD_MANIFEST_CB = () => { + resolve(window.__BUILD_MANIFEST); + }; + } + }); + } // Returns a promise for the dependencies for a particular route + + + getDependencies(route) { + return this.promisedBuildManifest.then(man => man[route] && man[route].map(url => "/_next/" + url) || []); } normalizeRoute(route) { @@ -993,12 +931,13 @@ class PageLoader { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!this.loadingRoutes[route]) { - this.loadScript(route); - this.loadingRoutes[route] = true; + if (false) {} else { + this.loadRoute(route); + this.loadingRoutes[route] = true; + } } }); } @@ -1023,35 +962,41 @@ class PageLoader { }); } - loadScript(route) { + loadRoute(route) { var _this = this; return (0, _asyncToGenerator2.default)(function* () { yield _this.promisedBuildId; route = _this.normalizeRoute(route); let scriptRoute = route === '/' ? '/index.js' : route + ".js"; - const script = document.createElement('script'); + const url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - if ( true && 'noModule' in script) { - script.type = 'module'; - scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); - } + _this.loadScript(url, route, true); + })(); + } - const url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = "anonymous"; - script.src = url; + loadScript(url, route, isPage) { + const script = document.createElement('script'); - script.onerror = () => { - const error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; + if ( true && 'noModule' in script) { + script.type = 'module'; // Only page bundle scripts need to have .module added to url, + // dependencies already have it added during build manifest creation - _this.pageRegisterEvents.emit(route, { - error - }); - }; + if (isPage) url = url.replace(/\.js$/, '.module.js'); + } - document.body.appendChild(script); - })(); + script.crossOrigin = "anonymous"; + script.src = url; + + script.onerror = () => { + const error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + this.pageRegisterEvents.emit(route, { + error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. @@ -1085,10 +1030,11 @@ class PageLoader { register(); } - prefetch(route) { + prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2.default)(function* () { + yield _this2.promisedBuildId; route = _this2.normalizeRoute(route); let scriptRoute = (route === '/' ? '/index' : route) + ".js"; @@ -1096,11 +1042,12 @@ class PageLoader { scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); } - if (_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route)) { - return; - } + const url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE + if (document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route)) { + return; + } // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE let cn; @@ -1110,14 +1057,21 @@ class PageLoader { if ((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData) { return; } - } // Feature detection is used to see if preload is supported + } + + if (false) {} // Feature detection is used to see if preload is supported // If not fall back to loading script tags before the page is loaded // https://caniuse.com/#feat=link-rel-preload if (hasPreload) { - yield _this2.promisedBuildId; - preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute); + preloadScript(url); + return; + } + + if (isDependency) { + // loadPage will automatically handle depencies, so no need to + // preload them manually return; } ```
ijjk commented 5 years ago

Stats from current PR

Click to expand stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 22.3s | 22.1s | -191ms | | `node_modules` Size | 43.6 MB | 43.6 MB | ⚠️ +12.5 kB | | Total Bundle (main, webpack, commons) Size | 207 kB | 207 kB | -34 B | | Total Bundle (main, webpack, commons) gzip Size | 68.1 kB | 68.2 kB | ⚠️ +83 B | | Total Bundle (main, webpack, commons) Modern Size | 182 kB | 181 kB | -265 B | | Total Bundle (main, webpack, commons) Modern gzip Size | 59.9 kB | 59.9 kB | -16 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_app` Modern Size | 1.83 kB | 1.83 kB | ✓ | | Client `_app` gzip Modern Size | 890 B | 890 B | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `_error` Modern Size | 5.85 kB | 5.85 kB | ✓ | | Client `_error` gzip Modern Size | 2.33 kB | 2.33 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/index` Modern Size | 319 B | 319 B | ✓ | | Client `pages/index` gzip Modern Size | 254 B | 254 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/link` Modern Size | 3.7 kB | 3.7 kB | ✓ | | Client `pages/link` gzip Modern Size | 1.7 kB | 1.7 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/routerDirect` Modern Size | 411 B | 411 B | ✓ | | Client `pages/routerDirect` gzip Modern Size | 314 B | 314 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `pages/withRouter` Modern Size | 423 B | 423 B | ✓ | | Client `pages/withRouter` gzip Modern Size | 309 B | 309 B | ✓ | | Client `main` Size | 15.8 kB | 15.8 kB | -34 B | | Client `main` gzip Size | 5.46 kB | 5.54 kB | ⚠️ +83 B | | Client `main` Modern Size | 12.8 kB | 12.6 kB | -265 B | | Client `main` Modern gzip Size | 4.83 kB | 4.82 kB | -16 B | | Client `commons` Size | 188 kB | 188 kB | ✓ | | Client `commons` gzip Size | 61.3 kB | 61.3 kB | ✓ | | Client `commons` Modern Size | 169 kB | 169 kB | ✓ | | Client `commons` Modern gzip Size | 55.1 kB | 55.1 kB | ✓ | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Client `webpack` Modern Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` Modern gzip Size | 785 B | 785 B | ✓ | | Base Rendered Size | 2.76 kB | 2.76 kB | ✓ | | Build Dir Size | 1.39 MB | 1.39 MB | ⚠️ +2.41 kB |
Click to expand serverless stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 23s | 23.6s | ⚠️ +661ms | | `node_modules` Size | 43.6 MB | 43.6 MB | ⚠️ +12.5 kB | | Total Bundle (main, webpack, commons) Size | 207 kB | 207 kB | -34 B | | Total Bundle (main, webpack, commons) gzip Size | 68.1 kB | 68.2 kB | ⚠️ +83 B | | Total Bundle (main, webpack, commons) Modern Size | 182 kB | 181 kB | -265 B | | Total Bundle (main, webpack, commons) Modern gzip Size | 59.9 kB | 59.9 kB | -16 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_app` Modern Size | 1.83 kB | 1.83 kB | ✓ | | Client `_app` gzip Modern Size | 890 B | 890 B | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `_error` Modern Size | 5.85 kB | 5.85 kB | ✓ | | Client `_error` gzip Modern Size | 2.33 kB | 2.33 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/index` Modern Size | 319 B | 319 B | ✓ | | Client `pages/index` gzip Modern Size | 254 B | 254 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/link` Modern Size | 3.7 kB | 3.7 kB | ✓ | | Client `pages/link` gzip Modern Size | 1.7 kB | 1.7 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/routerDirect` Modern Size | 411 B | 411 B | ✓ | | Client `pages/routerDirect` gzip Modern Size | 314 B | 314 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `pages/withRouter` Modern Size | 423 B | 423 B | ✓ | | Client `pages/withRouter` gzip Modern Size | 309 B | 309 B | ✓ | | Client `main` Size | 15.8 kB | 15.8 kB | -34 B | | Client `main` gzip Size | 5.46 kB | 5.54 kB | ⚠️ +83 B | | Client `main` Modern Size | 12.8 kB | 12.6 kB | -265 B | | Client `main` Modern gzip Size | 4.83 kB | 4.82 kB | -16 B | | Client `commons` Size | 188 kB | 188 kB | ✓ | | Client `commons` gzip Size | 61.3 kB | 61.3 kB | ✓ | | Client `commons` Modern Size | 169 kB | 169 kB | ✓ | | Client `commons` Modern gzip Size | 55.1 kB | 55.1 kB | ✓ | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Client `webpack` Modern Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` Modern gzip Size | 785 B | 785 B | ✓ | | Serverless `pages/link` Size | 255 kB | 255 kB | ✓ | | Serverless `pages/link` gzip Size | 68.6 kB | 68.6 kB | ⚠️ +2 B | | Serverless `pages/index` Size | 248 kB | 248 kB | ✓ | | Serverless `pages/index` gzip Size | 66.4 kB | 66.4 kB | ⚠️ +3 B | | Serverless `pages/_error` Size | 247 kB | 247 kB | ✓ | | Serverless `pages/_error` gzip Size | 66.1 kB | 66.1 kB | ⚠️ +3 B | | Serverless `pages/routerDirect` Size | 248 kB | 248 kB | ✓ | | Serverless `pages/routerDirect` gzip Size | 66.3 kB | 66.3 kB | ⚠️ +2 B | | Serverless `pages/withRouter` Size | 248 kB | 248 kB | ✓ | | Serverless `pages/withRouter` gzip Size | 66.4 kB | 66.4 kB | ⚠️ +2 B | | Build Dir Size | 2.59 MB | 2.6 MB | ⚠️ +2.41 kB |
Diff for main.js ```diff @@ -1,20 +1,5 @@ (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), - /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,28 +54,6 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; - -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); - - -/***/ }), - /***/ "BMP1": /***/ (function(module, exports, __webpack_require__) { @@ -919,15 +882,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -995,17 +949,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -1083,22 +1026,6 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { @@ -1122,12 +1049,10 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ +/* global document, window */ function supportsPreload(el) { @@ -1157,13 +1082,31 @@ function () { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set["default"](); this.pageRegisterEvents = (0, _mitt["default"])(); this.loadingRoutes = {}; this.promisedBuildId = _promise["default"].resolve(); - } + this.promisedBuildManifest = new _promise["default"](function (resolve) { + if (window.__BUILD_MANIFEST) { + resolve(window.__BUILD_MANIFEST); + } else { + window.__BUILD_MANIFEST_CB = function () { + resolve(window.__BUILD_MANIFEST); + }; + } + }); + } // Returns a promise for the dependencies for a particular route + (0, _createClass2["default"])(PageLoader, [{ + key: "getDependencies", + value: function getDependencies(route) { + return this.promisedBuildManifest.then(function (man) { + return man[route] && man[route].map(function (url) { + return "/_next/" + url; + }) || []; + }); + } + }, { key: "normalizeRoute", value: function normalizeRoute(route) { if (route[0] !== '/') { @@ -1213,13 +1156,14 @@ function () { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!_this3.loadingRoutes[route]) { - _this3.loadScript(route); + if (false) {} else { + _this3.loadRoute(route); - _this3.loadingRoutes[route] = true; + _this3.loadingRoutes[route] = true; + } } }); } @@ -1249,14 +1193,14 @@ function () { }); } }, { - key: "loadScript", - value: function loadScript(route) { + key: "loadRoute", + value: function loadRoute(route) { var _this = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee() { - var scriptRoute, script, url; + var scriptRoute, url; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { @@ -1267,41 +1211,51 @@ function () { case 2: route = _this.normalizeRoute(route); scriptRoute = route === '/' ? '/index.js' : route + ".js"; - script = document.createElement('script'); - - if ( true && 'noModule' in script) { - script.type = 'module'; - scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); - } - url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = "anonymous"; - script.src = url; - - script.onerror = function () { - var error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; - _this.pageRegisterEvents.emit(route, { - error: error - }); - }; + _this.loadScript(url, route, true); - document.body.appendChild(script); - - case 11: + case 6: case "end": return _context.stop(); } } }, _callee); }))(); + } + }, { + key: "loadScript", + value: function loadScript(url, route, isPage) { + var _this5 = this; + + var script = document.createElement('script'); + + if ( true && 'noModule' in script) { + script.type = 'module'; // Only page bundle scripts need to have .module added to url, + // dependencies already have it added during build manifest creation + + if (isPage) url = url.replace(/\.js$/, '.module.js'); + } + + script.crossOrigin = "anonymous"; + script.src = url; + + script.onerror = function () { + var error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + + _this5.pageRegisterEvents.emit(route, { + error: error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. }, { key: "registerPage", value: function registerPage(route, regFn) { - var _this5 = this; + var _this6 = this; var register = function register() { try { @@ -1309,21 +1263,21 @@ function () { error = _regFn.error, page = _regFn.page; - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error, page: page }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error, page: page }); } catch (error) { - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error }); } @@ -1335,17 +1289,21 @@ function () { } }, { key: "prefetch", - value: function prefetch(route) { + value: function prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee2() { - var scriptRoute, cn; + var scriptRoute, url, cn; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: + _context2.next = 2; + return _this2.promisedBuildId; + + case 2: route = _this2.normalizeRoute(route); scriptRoute = (route === '/' ? '/index' : route) + ".js"; @@ -1353,51 +1311,72 @@ function () { scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); } - if (!(_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route))) { - _context2.next = 5; + url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. + + if (!(document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route))) { + _context2.next = 8; break; } return _context2.abrupt("return"); - case 5: - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE - - + case 8: if (!(cn = navigator.connection)) { - _context2.next = 9; + _context2.next = 11; break; } if (!((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData)) { - _context2.next = 9; + _context2.next = 11; break; } return _context2.abrupt("return"); - case 9: + case 11: + if (true) { + _context2.next = 17; + break; + } + + ; + _context2.next = 15; + return _this2.getDependencies(route); + + case 15: + _context2.t0 = function (url) { + _this2.prefetch(url, true); + }; + + _context2.sent.forEach(_context2.t0); + + case 17: if (!hasPreload) { - _context2.next = 14; + _context2.next = 20; break; } - _context2.next = 12; - return _this2.promisedBuildId; + preloadScript(url); + return _context2.abrupt("return"); + + case 20: + if (!isDependency) { + _context2.next = 22; + break; + } - case 12: - preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute); return _context2.abrupt("return"); - case 14: + case 22: if (!(document.readyState === 'complete')) { - _context2.next = 18; + _context2.next = 26; break; } return _context2.abrupt("return", _this2.loadPage(route)["catch"](function () {})); - case 18: + case 26: return _context2.abrupt("return", new _promise["default"](function (resolve) { window.addEventListener('load', function () { _this2.loadPage(route).then(function () { @@ -1408,7 +1387,7 @@ function () { }); })); - case 19: + case 27: case "end": return _context2.stop(); } ```
Diff for mainModern.js ```diff @@ -1,20 +1,5 @@ (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), - /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,28 +54,6 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; - -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); - - -/***/ }), - /***/ "BMP1": /***/ (function(module, exports, __webpack_require__) { @@ -729,15 +692,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -792,17 +746,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -878,22 +821,6 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { @@ -909,12 +836,10 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ +/* global document, window */ function supportsPreload(el) { @@ -941,10 +866,23 @@ class PageLoader { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set.default(); this.pageRegisterEvents = (0, _mitt.default)(); this.loadingRoutes = {}; this.promisedBuildId = _promise.default.resolve(); + this.promisedBuildManifest = new _promise.default(resolve => { + if (window.__BUILD_MANIFEST) { + resolve(window.__BUILD_MANIFEST); + } else { + window.__BUILD_MANIFEST_CB = () => { + resolve(window.__BUILD_MANIFEST); + }; + } + }); + } // Returns a promise for the dependencies for a particular route + + + getDependencies(route) { + return this.promisedBuildManifest.then(man => man[route] && man[route].map(url => "/_next/" + url) || []); } normalizeRoute(route) { @@ -993,12 +931,13 @@ class PageLoader { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!this.loadingRoutes[route]) { - this.loadScript(route); - this.loadingRoutes[route] = true; + if (false) {} else { + this.loadRoute(route); + this.loadingRoutes[route] = true; + } } }); } @@ -1023,35 +962,41 @@ class PageLoader { }); } - loadScript(route) { + loadRoute(route) { var _this = this; return (0, _asyncToGenerator2.default)(function* () { yield _this.promisedBuildId; route = _this.normalizeRoute(route); let scriptRoute = route === '/' ? '/index.js' : route + ".js"; - const script = document.createElement('script'); + const url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - if ( true && 'noModule' in script) { - script.type = 'module'; - scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); - } + _this.loadScript(url, route, true); + })(); + } - const url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = "anonymous"; - script.src = url; + loadScript(url, route, isPage) { + const script = document.createElement('script'); - script.onerror = () => { - const error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; + if ( true && 'noModule' in script) { + script.type = 'module'; // Only page bundle scripts need to have .module added to url, + // dependencies already have it added during build manifest creation - _this.pageRegisterEvents.emit(route, { - error - }); - }; + if (isPage) url = url.replace(/\.js$/, '.module.js'); + } - document.body.appendChild(script); - })(); + script.crossOrigin = "anonymous"; + script.src = url; + + script.onerror = () => { + const error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + this.pageRegisterEvents.emit(route, { + error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. @@ -1085,10 +1030,11 @@ class PageLoader { register(); } - prefetch(route) { + prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2.default)(function* () { + yield _this2.promisedBuildId; route = _this2.normalizeRoute(route); let scriptRoute = (route === '/' ? '/index' : route) + ".js"; @@ -1096,11 +1042,12 @@ class PageLoader { scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); } - if (_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route)) { - return; - } + const url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE + if (document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route)) { + return; + } // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE let cn; @@ -1110,14 +1057,21 @@ class PageLoader { if ((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData) { return; } - } // Feature detection is used to see if preload is supported + } + + if (false) {} // Feature detection is used to see if preload is supported // If not fall back to loading script tags before the page is loaded // https://caniuse.com/#feat=link-rel-preload if (hasPreload) { - yield _this2.promisedBuildId; - preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute); + preloadScript(url); + return; + } + + if (isDependency) { + // loadPage will automatically handle depencies, so no need to + // preload them manually return; } ```
ijjk commented 5 years ago

Stats from current PR

Click to expand stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 20.1s | 19.9s | -179ms | | `node_modules` Size | 43.6 MB | 43.6 MB | ⚠️ +12.5 kB | | Total Bundle (main, webpack, commons) Size | 207 kB | 207 kB | -34 B | | Total Bundle (main, webpack, commons) gzip Size | 68.1 kB | 68.2 kB | ⚠️ +83 B | | Total Bundle (main, webpack, commons) Modern Size | 182 kB | 181 kB | -265 B | | Total Bundle (main, webpack, commons) Modern gzip Size | 59.9 kB | 59.9 kB | -16 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_app` Modern Size | 1.83 kB | 1.83 kB | ✓ | | Client `_app` gzip Modern Size | 890 B | 890 B | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `_error` Modern Size | 5.85 kB | 5.85 kB | ✓ | | Client `_error` gzip Modern Size | 2.33 kB | 2.33 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/index` Modern Size | 319 B | 319 B | ✓ | | Client `pages/index` gzip Modern Size | 254 B | 254 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/link` Modern Size | 3.7 kB | 3.7 kB | ✓ | | Client `pages/link` gzip Modern Size | 1.7 kB | 1.7 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/routerDirect` Modern Size | 411 B | 411 B | ✓ | | Client `pages/routerDirect` gzip Modern Size | 314 B | 314 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `pages/withRouter` Modern Size | 423 B | 423 B | ✓ | | Client `pages/withRouter` gzip Modern Size | 309 B | 309 B | ✓ | | Client `main` Size | 15.8 kB | 15.8 kB | -34 B | | Client `main` gzip Size | 5.46 kB | 5.54 kB | ⚠️ +83 B | | Client `main` Modern Size | 12.8 kB | 12.6 kB | -265 B | | Client `main` Modern gzip Size | 4.83 kB | 4.82 kB | -16 B | | Client `commons` Size | 188 kB | 188 kB | ✓ | | Client `commons` gzip Size | 61.3 kB | 61.3 kB | ✓ | | Client `commons` Modern Size | 169 kB | 169 kB | ✓ | | Client `commons` Modern gzip Size | 55.1 kB | 55.1 kB | ✓ | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Client `webpack` Modern Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` Modern gzip Size | 785 B | 785 B | ✓ | | Base Rendered Size | 2.76 kB | 2.76 kB | ✓ | | Build Dir Size | 1.39 MB | 1.39 MB | ⚠️ +2.41 kB |
Click to expand serverless stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 20.8s | 21.2s | ⚠️ +363ms | | `node_modules` Size | 43.6 MB | 43.6 MB | ⚠️ +12.5 kB | | Total Bundle (main, webpack, commons) Size | 207 kB | 207 kB | -34 B | | Total Bundle (main, webpack, commons) gzip Size | 68.1 kB | 68.2 kB | ⚠️ +83 B | | Total Bundle (main, webpack, commons) Modern Size | 182 kB | 181 kB | -265 B | | Total Bundle (main, webpack, commons) Modern gzip Size | 59.9 kB | 59.9 kB | -16 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_app` Modern Size | 1.83 kB | 1.83 kB | ✓ | | Client `_app` gzip Modern Size | 890 B | 890 B | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `_error` Modern Size | 5.85 kB | 5.85 kB | ✓ | | Client `_error` gzip Modern Size | 2.33 kB | 2.33 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/index` Modern Size | 319 B | 319 B | ✓ | | Client `pages/index` gzip Modern Size | 254 B | 254 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/link` Modern Size | 3.7 kB | 3.7 kB | ✓ | | Client `pages/link` gzip Modern Size | 1.7 kB | 1.7 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/routerDirect` Modern Size | 411 B | 411 B | ✓ | | Client `pages/routerDirect` gzip Modern Size | 314 B | 314 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `pages/withRouter` Modern Size | 423 B | 423 B | ✓ | | Client `pages/withRouter` gzip Modern Size | 309 B | 309 B | ✓ | | Client `main` Size | 15.8 kB | 15.8 kB | -34 B | | Client `main` gzip Size | 5.46 kB | 5.54 kB | ⚠️ +83 B | | Client `main` Modern Size | 12.8 kB | 12.6 kB | -265 B | | Client `main` Modern gzip Size | 4.83 kB | 4.82 kB | -16 B | | Client `commons` Size | 188 kB | 188 kB | ✓ | | Client `commons` gzip Size | 61.3 kB | 61.3 kB | ✓ | | Client `commons` Modern Size | 169 kB | 169 kB | ✓ | | Client `commons` Modern gzip Size | 55.1 kB | 55.1 kB | ✓ | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Client `webpack` Modern Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` Modern gzip Size | 785 B | 785 B | ✓ | | Serverless `pages/link` Size | 255 kB | 255 kB | ✓ | | Serverless `pages/link` gzip Size | 68.6 kB | 68.6 kB | ⚠️ +3 B | | Serverless `pages/index` Size | 248 kB | 248 kB | ✓ | | Serverless `pages/index` gzip Size | 66.4 kB | 66.4 kB | ⚠️ +3 B | | Serverless `pages/_error` Size | 247 kB | 247 kB | ✓ | | Serverless `pages/_error` gzip Size | 66.1 kB | 66.1 kB | ⚠️ +3 B | | Serverless `pages/routerDirect` Size | 248 kB | 248 kB | ✓ | | Serverless `pages/routerDirect` gzip Size | 66.3 kB | 66.3 kB | ⚠️ +3 B | | Serverless `pages/withRouter` Size | 248 kB | 248 kB | ✓ | | Serverless `pages/withRouter` gzip Size | 66.4 kB | 66.4 kB | ⚠️ +1 B | | Build Dir Size | 2.59 MB | 2.6 MB | ⚠️ +2.41 kB |
Diff for main.js ```diff @@ -1,20 +1,5 @@ (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), - /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,28 +54,6 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; - -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); - - -/***/ }), - /***/ "BMP1": /***/ (function(module, exports, __webpack_require__) { @@ -919,15 +882,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -995,17 +949,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -1083,22 +1026,6 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { @@ -1122,12 +1049,10 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ +/* global document, window */ function supportsPreload(el) { @@ -1157,13 +1082,31 @@ function () { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set["default"](); this.pageRegisterEvents = (0, _mitt["default"])(); this.loadingRoutes = {}; this.promisedBuildId = _promise["default"].resolve(); - } + this.promisedBuildManifest = new _promise["default"](function (resolve) { + if (window.__BUILD_MANIFEST) { + resolve(window.__BUILD_MANIFEST); + } else { + window.__BUILD_MANIFEST_CB = function () { + resolve(window.__BUILD_MANIFEST); + }; + } + }); + } // Returns a promise for the dependencies for a particular route + (0, _createClass2["default"])(PageLoader, [{ + key: "getDependencies", + value: function getDependencies(route) { + return this.promisedBuildManifest.then(function (man) { + return man[route] && man[route].map(function (url) { + return "/_next/" + url; + }) || []; + }); + } + }, { key: "normalizeRoute", value: function normalizeRoute(route) { if (route[0] !== '/') { @@ -1213,13 +1156,14 @@ function () { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!_this3.loadingRoutes[route]) { - _this3.loadScript(route); + if (false) {} else { + _this3.loadRoute(route); - _this3.loadingRoutes[route] = true; + _this3.loadingRoutes[route] = true; + } } }); } @@ -1249,14 +1193,14 @@ function () { }); } }, { - key: "loadScript", - value: function loadScript(route) { + key: "loadRoute", + value: function loadRoute(route) { var _this = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee() { - var scriptRoute, script, url; + var scriptRoute, url; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { @@ -1267,41 +1211,51 @@ function () { case 2: route = _this.normalizeRoute(route); scriptRoute = route === '/' ? '/index.js' : route + ".js"; - script = document.createElement('script'); - - if ( true && 'noModule' in script) { - script.type = 'module'; - scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); - } - url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = "anonymous"; - script.src = url; - - script.onerror = function () { - var error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; - _this.pageRegisterEvents.emit(route, { - error: error - }); - }; + _this.loadScript(url, route, true); - document.body.appendChild(script); - - case 11: + case 6: case "end": return _context.stop(); } } }, _callee); }))(); + } + }, { + key: "loadScript", + value: function loadScript(url, route, isPage) { + var _this5 = this; + + var script = document.createElement('script'); + + if ( true && 'noModule' in script) { + script.type = 'module'; // Only page bundle scripts need to have .module added to url, + // dependencies already have it added during build manifest creation + + if (isPage) url = url.replace(/\.js$/, '.module.js'); + } + + script.crossOrigin = "anonymous"; + script.src = url; + + script.onerror = function () { + var error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + + _this5.pageRegisterEvents.emit(route, { + error: error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. }, { key: "registerPage", value: function registerPage(route, regFn) { - var _this5 = this; + var _this6 = this; var register = function register() { try { @@ -1309,21 +1263,21 @@ function () { error = _regFn.error, page = _regFn.page; - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error, page: page }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error, page: page }); } catch (error) { - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error }); } @@ -1335,17 +1289,21 @@ function () { } }, { key: "prefetch", - value: function prefetch(route) { + value: function prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee2() { - var scriptRoute, cn; + var scriptRoute, url, cn; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: + _context2.next = 2; + return _this2.promisedBuildId; + + case 2: route = _this2.normalizeRoute(route); scriptRoute = (route === '/' ? '/index' : route) + ".js"; @@ -1353,51 +1311,72 @@ function () { scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); } - if (!(_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route))) { - _context2.next = 5; + url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. + + if (!(document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route))) { + _context2.next = 8; break; } return _context2.abrupt("return"); - case 5: - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE - - + case 8: if (!(cn = navigator.connection)) { - _context2.next = 9; + _context2.next = 11; break; } if (!((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData)) { - _context2.next = 9; + _context2.next = 11; break; } return _context2.abrupt("return"); - case 9: + case 11: + if (true) { + _context2.next = 17; + break; + } + + ; + _context2.next = 15; + return _this2.getDependencies(route); + + case 15: + _context2.t0 = function (url) { + _this2.prefetch(url, true); + }; + + _context2.sent.forEach(_context2.t0); + + case 17: if (!hasPreload) { - _context2.next = 14; + _context2.next = 20; break; } - _context2.next = 12; - return _this2.promisedBuildId; + preloadScript(url); + return _context2.abrupt("return"); + + case 20: + if (!isDependency) { + _context2.next = 22; + break; + } - case 12: - preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute); return _context2.abrupt("return"); - case 14: + case 22: if (!(document.readyState === 'complete')) { - _context2.next = 18; + _context2.next = 26; break; } return _context2.abrupt("return", _this2.loadPage(route)["catch"](function () {})); - case 18: + case 26: return _context2.abrupt("return", new _promise["default"](function (resolve) { window.addEventListener('load', function () { _this2.loadPage(route).then(function () { @@ -1408,7 +1387,7 @@ function () { }); })); - case 19: + case 27: case "end": return _context2.stop(); } ```
Diff for mainModern.js ```diff @@ -1,20 +1,5 @@ (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), - /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,28 +54,6 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; - -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); - - -/***/ }), - /***/ "BMP1": /***/ (function(module, exports, __webpack_require__) { @@ -729,15 +692,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -792,17 +746,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -878,22 +821,6 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { @@ -909,12 +836,10 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ +/* global document, window */ function supportsPreload(el) { @@ -941,10 +866,23 @@ class PageLoader { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set.default(); this.pageRegisterEvents = (0, _mitt.default)(); this.loadingRoutes = {}; this.promisedBuildId = _promise.default.resolve(); + this.promisedBuildManifest = new _promise.default(resolve => { + if (window.__BUILD_MANIFEST) { + resolve(window.__BUILD_MANIFEST); + } else { + window.__BUILD_MANIFEST_CB = () => { + resolve(window.__BUILD_MANIFEST); + }; + } + }); + } // Returns a promise for the dependencies for a particular route + + + getDependencies(route) { + return this.promisedBuildManifest.then(man => man[route] && man[route].map(url => "/_next/" + url) || []); } normalizeRoute(route) { @@ -993,12 +931,13 @@ class PageLoader { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!this.loadingRoutes[route]) { - this.loadScript(route); - this.loadingRoutes[route] = true; + if (false) {} else { + this.loadRoute(route); + this.loadingRoutes[route] = true; + } } }); } @@ -1023,35 +962,41 @@ class PageLoader { }); } - loadScript(route) { + loadRoute(route) { var _this = this; return (0, _asyncToGenerator2.default)(function* () { yield _this.promisedBuildId; route = _this.normalizeRoute(route); let scriptRoute = route === '/' ? '/index.js' : route + ".js"; - const script = document.createElement('script'); + const url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - if ( true && 'noModule' in script) { - script.type = 'module'; - scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); - } + _this.loadScript(url, route, true); + })(); + } - const url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = "anonymous"; - script.src = url; + loadScript(url, route, isPage) { + const script = document.createElement('script'); - script.onerror = () => { - const error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; + if ( true && 'noModule' in script) { + script.type = 'module'; // Only page bundle scripts need to have .module added to url, + // dependencies already have it added during build manifest creation - _this.pageRegisterEvents.emit(route, { - error - }); - }; + if (isPage) url = url.replace(/\.js$/, '.module.js'); + } - document.body.appendChild(script); - })(); + script.crossOrigin = "anonymous"; + script.src = url; + + script.onerror = () => { + const error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + this.pageRegisterEvents.emit(route, { + error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. @@ -1085,10 +1030,11 @@ class PageLoader { register(); } - prefetch(route) { + prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2.default)(function* () { + yield _this2.promisedBuildId; route = _this2.normalizeRoute(route); let scriptRoute = (route === '/' ? '/index' : route) + ".js"; @@ -1096,11 +1042,12 @@ class PageLoader { scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); } - if (_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route)) { - return; - } + const url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE + if (document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route)) { + return; + } // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE let cn; @@ -1110,14 +1057,21 @@ class PageLoader { if ((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData) { return; } - } // Feature detection is used to see if preload is supported + } + + if (false) {} // Feature detection is used to see if preload is supported // If not fall back to loading script tags before the page is loaded // https://caniuse.com/#feat=link-rel-preload if (hasPreload) { - yield _this2.promisedBuildId; - preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute); + preloadScript(url); + return; + } + + if (isDependency) { + // loadPage will automatically handle depencies, so no need to + // preload them manually return; } ```
ijjk commented 5 years ago

Stats from current PR

Click to expand stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 20.7s | 20.2s | -498ms | | `node_modules` Size | 43.6 MB | 43.6 MB | ⚠️ +12.6 kB | | Total Bundle (main, webpack, commons) Size | 207 kB | 206 kB | -206 B | | Total Bundle (main, webpack, commons) gzip Size | 68.1 kB | 68.2 kB | ⚠️ +40 B | | Total Bundle (main, webpack, commons) Modern Size | 182 kB | 181 kB | -423 B | | Total Bundle (main, webpack, commons) Modern gzip Size | 59.9 kB | 59.9 kB | -53 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_app` Modern Size | 1.83 kB | 1.83 kB | ✓ | | Client `_app` gzip Modern Size | 890 B | 890 B | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `_error` Modern Size | 5.85 kB | 5.85 kB | ✓ | | Client `_error` gzip Modern Size | 2.33 kB | 2.33 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/index` Modern Size | 319 B | 319 B | ✓ | | Client `pages/index` gzip Modern Size | 254 B | 254 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/link` Modern Size | 3.7 kB | 3.7 kB | ✓ | | Client `pages/link` gzip Modern Size | 1.7 kB | 1.7 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/routerDirect` Modern Size | 411 B | 411 B | ✓ | | Client `pages/routerDirect` gzip Modern Size | 314 B | 314 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `pages/withRouter` Modern Size | 423 B | 423 B | ✓ | | Client `pages/withRouter` gzip Modern Size | 309 B | 309 B | ✓ | | Client `main` Size | 15.8 kB | 15.6 kB | -206 B | | Client `main` gzip Size | 5.46 kB | 5.5 kB | ⚠️ +40 B | | Client `main` Modern Size | 12.8 kB | 12.4 kB | -423 B | | Client `main` Modern gzip Size | 4.83 kB | 4.78 kB | -53 B | | Client `commons` Size | 188 kB | 188 kB | ✓ | | Client `commons` gzip Size | 61.3 kB | 61.3 kB | ✓ | | Client `commons` Modern Size | 169 kB | 169 kB | ✓ | | Client `commons` Modern gzip Size | 55.1 kB | 55.1 kB | ✓ | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Client `webpack` Modern Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` Modern gzip Size | 785 B | 785 B | ✓ | | Base Rendered Size | 2.76 kB | 2.76 kB | ✓ | | Build Dir Size | 1.39 MB | 1.39 MB | ⚠️ +1.74 kB |
Click to expand serverless stats ✅ Total Bundle Size Decrease ✅ | | zeit/next.js canary | atcastle/next.js implement-granular-chunks | Change | | - | - | - | - | | Build Duration | 22s | 22.2s | ⚠️ +268ms | | `node_modules` Size | 43.6 MB | 43.6 MB | ⚠️ +12.6 kB | | Total Bundle (main, webpack, commons) Size | 207 kB | 206 kB | -206 B | | Total Bundle (main, webpack, commons) gzip Size | 68.1 kB | 68.2 kB | ⚠️ +40 B | | Total Bundle (main, webpack, commons) Modern Size | 182 kB | 181 kB | -423 B | | Total Bundle (main, webpack, commons) Modern gzip Size | 59.9 kB | 59.9 kB | -53 B | | Client `_app` Size | 2.39 kB | 2.39 kB | ✓ | | Client `_app` gzip Size | 1.08 kB | 1.08 kB | ✓ | | Client `_app` Modern Size | 1.83 kB | 1.83 kB | ✓ | | Client `_app` gzip Modern Size | 890 B | 890 B | ✓ | | Client `_error` Size | 8.22 kB | 8.22 kB | ✓ | | Client `_error` gzip Size | 3.16 kB | 3.16 kB | ✓ | | Client `_error` Modern Size | 5.85 kB | 5.85 kB | ✓ | | Client `_error` gzip Modern Size | 2.33 kB | 2.33 kB | ✓ | | Client `pages/index` Size | 343 B | 343 B | ✓ | | Client `pages/index` gzip Size | 246 B | 246 B | ✓ | | Client `pages/index` Modern Size | 319 B | 319 B | ✓ | | Client `pages/index` gzip Modern Size | 254 B | 254 B | ✓ | | Client `pages/link` Size | 4.08 kB | 4.08 kB | ✓ | | Client `pages/link` gzip Size | 1.8 kB | 1.8 kB | ✓ | | Client `pages/link` Modern Size | 3.7 kB | 3.7 kB | ✓ | | Client `pages/link` gzip Modern Size | 1.7 kB | 1.7 kB | ✓ | | Client `pages/routerDirect` Size | 423 B | 423 B | ✓ | | Client `pages/routerDirect` gzip Size | 306 B | 306 B | ✓ | | Client `pages/routerDirect` Modern Size | 411 B | 411 B | ✓ | | Client `pages/routerDirect` gzip Modern Size | 314 B | 314 B | ✓ | | Client `pages/withRouter` Size | 435 B | 435 B | ✓ | | Client `pages/withRouter` gzip Size | 301 B | 301 B | ✓ | | Client `pages/withRouter` Modern Size | 423 B | 423 B | ✓ | | Client `pages/withRouter` gzip Modern Size | 309 B | 309 B | ✓ | | Client `main` Size | 15.8 kB | 15.6 kB | -206 B | | Client `main` gzip Size | 5.46 kB | 5.5 kB | ⚠️ +40 B | | Client `main` Modern Size | 12.8 kB | 12.4 kB | -423 B | | Client `main` Modern gzip Size | 4.83 kB | 4.78 kB | -53 B | | Client `commons` Size | 188 kB | 188 kB | ✓ | | Client `commons` gzip Size | 61.3 kB | 61.3 kB | ✓ | | Client `commons` Modern Size | 169 kB | 169 kB | ✓ | | Client `commons` Modern gzip Size | 55.1 kB | 55.1 kB | ✓ | | Client `webpack` Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` gzip Size | 778 B | 778 B | ✓ | | Client `webpack` Modern Size | 1.53 kB | 1.53 kB | ✓ | | Client `webpack` Modern gzip Size | 785 B | 785 B | ✓ | | Serverless `pages/link` Size | 255 kB | 255 kB | ✓ | | Serverless `pages/link` gzip Size | 68.6 kB | 68.6 kB | ⚠️ +2 B | | Serverless `pages/index` Size | 248 kB | 248 kB | ✓ | | Serverless `pages/index` gzip Size | 66.4 kB | 66.4 kB | ⚠️ +2 B | | Serverless `pages/_error` Size | 247 kB | 247 kB | ✓ | | Serverless `pages/_error` gzip Size | 66.1 kB | 66.1 kB | ✓ | | Serverless `pages/routerDirect` Size | 248 kB | 248 kB | ✓ | | Serverless `pages/routerDirect` gzip Size | 66.3 kB | 66.3 kB | ⚠️ +1 B | | Serverless `pages/withRouter` Size | 248 kB | 248 kB | ✓ | | Serverless `pages/withRouter` gzip Size | 66.4 kB | 66.4 kB | ⚠️ +2 B | | Build Dir Size | 2.59 MB | 2.6 MB | ⚠️ +1.74 kB |
Diff for main.js ```diff @@ -1,19 +1,4 @@ -(window["webpackJsonp"] = window["webpackJsonp"] || []).push([[2],{ - -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), +(window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,28 +54,6 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; - -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); - - -/***/ }), - /***/ "BMP1": /***/ (function(module, exports, __webpack_require__) { @@ -919,15 +882,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -995,17 +949,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -1083,22 +1026,6 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { @@ -1122,12 +1049,10 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ +/* global document, window */ function supportsPreload(el) { @@ -1157,13 +1082,24 @@ function () { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set["default"](); this.pageRegisterEvents = (0, _mitt["default"])(); this.loadingRoutes = {}; this.promisedBuildId = _promise["default"].resolve(); - } + + if (false) {} + } // Returns a promise for the dependencies for a particular route + (0, _createClass2["default"])(PageLoader, [{ + key: "getDependencies", + value: function getDependencies(route) { + return this.promisedBuildManifest.then(function (man) { + return man[route] && man[route].map(function (url) { + return "/_next/" + url; + }) || []; + }); + } + }, { key: "normalizeRoute", value: function normalizeRoute(route) { if (route[0] !== '/') { @@ -1213,13 +1149,14 @@ function () { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!_this3.loadingRoutes[route]) { - _this3.loadScript(route); + if (false) {} else { + _this3.loadRoute(route); - _this3.loadingRoutes[route] = true; + _this3.loadingRoutes[route] = true; + } } }); } @@ -1249,14 +1186,14 @@ function () { }); } }, { - key: "loadScript", - value: function loadScript(route) { + key: "loadRoute", + value: function loadRoute(route) { var _this = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee() { - var scriptRoute, script, url; + var scriptRoute, url; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { @@ -1267,41 +1204,51 @@ function () { case 2: route = _this.normalizeRoute(route); scriptRoute = route === '/' ? '/index.js' : route + ".js"; - script = document.createElement('script'); - - if ( true && 'noModule' in script) { - script.type = 'module'; - scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); - } - url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = "anonymous"; - script.src = url; - - script.onerror = function () { - var error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; - _this.pageRegisterEvents.emit(route, { - error: error - }); - }; + _this.loadScript(url, route, true); - document.body.appendChild(script); - - case 11: + case 6: case "end": return _context.stop(); } } }, _callee); }))(); + } + }, { + key: "loadScript", + value: function loadScript(url, route, isPage) { + var _this5 = this; + + var script = document.createElement('script'); + + if ( true && 'noModule' in script) { + script.type = 'module'; // Only page bundle scripts need to have .module added to url, + // dependencies already have it added during build manifest creation + + if (isPage) url = url.replace(/\.js$/, '.module.js'); + } + + script.crossOrigin = "anonymous"; + script.src = url; + + script.onerror = function () { + var error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + + _this5.pageRegisterEvents.emit(route, { + error: error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. }, { key: "registerPage", value: function registerPage(route, regFn) { - var _this5 = this; + var _this6 = this; var register = function register() { try { @@ -1309,21 +1256,21 @@ function () { error = _regFn.error, page = _regFn.page; - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error, page: page }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error, page: page }); } catch (error) { - _this5.pageCache[route] = { + _this6.pageCache[route] = { error: error }; - _this5.pageRegisterEvents.emit(route, { + _this6.pageRegisterEvents.emit(route, { error: error }); } @@ -1335,17 +1282,21 @@ function () { } }, { key: "prefetch", - value: function prefetch(route) { + value: function prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2["default"])( /*#__PURE__*/ _regenerator["default"].mark(function _callee2() { - var scriptRoute, cn; + var scriptRoute, url, cn; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: + _context2.next = 2; + return _this2.promisedBuildId; + + case 2: route = _this2.normalizeRoute(route); scriptRoute = (route === '/' ? '/index' : route) + ".js"; @@ -1353,51 +1304,72 @@ function () { scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); } - if (!(_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route))) { - _context2.next = 5; + url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. + + if (!(document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route))) { + _context2.next = 8; break; } return _context2.abrupt("return"); - case 5: - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE - - + case 8: if (!(cn = navigator.connection)) { - _context2.next = 9; + _context2.next = 11; break; } if (!((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData)) { - _context2.next = 9; + _context2.next = 11; break; } return _context2.abrupt("return"); - case 9: + case 11: + if (true) { + _context2.next = 17; + break; + } + + ; + _context2.next = 15; + return _this2.getDependencies(route); + + case 15: + _context2.t0 = function (url) { + _this2.prefetch(url, true); + }; + + _context2.sent.forEach(_context2.t0); + + case 17: if (!hasPreload) { - _context2.next = 14; + _context2.next = 20; break; } - _context2.next = 12; - return _this2.promisedBuildId; + preloadScript(url); + return _context2.abrupt("return"); + + case 20: + if (!isDependency) { + _context2.next = 22; + break; + } - case 12: - preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute); return _context2.abrupt("return"); - case 14: + case 22: if (!(document.readyState === 'complete')) { - _context2.next = 18; + _context2.next = 26; break; } return _context2.abrupt("return", _this2.loadPage(route)["catch"](function () {})); - case 18: + case 26: return _context2.abrupt("return", new _promise["default"](function (resolve) { window.addEventListener('load', function () { _this2.loadPage(route).then(function () { @@ -1408,7 +1380,7 @@ function () { }); })); - case 19: + case 27: case "end": return _context2.stop(); } ```
Diff for mainModern.js ```diff @@ -1,19 +1,4 @@ -(window["webpackJsonp"] = window["webpackJsonp"] || []).push([[2],{ - -/***/ "+iuc": -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__("wgeU"); -__webpack_require__("FlQf"); -__webpack_require__("bBy9"); -__webpack_require__("B9jh"); -__webpack_require__("dL40"); -__webpack_require__("xvv9"); -__webpack_require__("V+O7"); -module.exports = __webpack_require__("WEpk").Set; - - -/***/ }), +(window["webpackJsonp"] = window["webpackJsonp"] || []).push([[8],{ /***/ "+oT+": /***/ (function(module, exports, __webpack_require__) { @@ -69,28 +54,6 @@ __webpack_require__("cHUd")('Map'); /***/ }), -/***/ "B9jh": -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var strong = __webpack_require__("Wu5q"); -var validate = __webpack_require__("n3ko"); -var SET = 'Set'; - -// 23.2 Set Objects -module.exports = __webpack_require__("raTm")(SET, function (get) { - return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.2.3.1 Set.prototype.add(value) - add: function add(value) { - return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value); - } -}, strong); - - -/***/ }), - /***/ "BMP1": /***/ (function(module, exports, __webpack_require__) { @@ -729,15 +692,6 @@ module.exports = __webpack_require__("WEpk").Map; /***/ }), -/***/ "V+O7": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from -__webpack_require__("aPfg")('Set'); - - -/***/ }), - /***/ "XLbu": /***/ (function(module, exports, __webpack_require__) { @@ -792,17 +746,6 @@ exports.DataManager = DataManager; /***/ }), -/***/ "dL40": -/***/ (function(module, exports, __webpack_require__) { - -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = __webpack_require__("Y7ZC"); - -$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__("8iia")('Set') }); - - -/***/ }), - /***/ "dVTT": /***/ (function(module, exports, __webpack_require__) { @@ -878,22 +821,6 @@ exports.DataManagerContext = React.createContext(null); /***/ }), -/***/ "ttDY": -/***/ (function(module, exports, __webpack_require__) { - -module.exports = __webpack_require__("+iuc"); - -/***/ }), - -/***/ "xvv9": -/***/ (function(module, exports, __webpack_require__) { - -// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of -__webpack_require__("cHUd")('Set'); - - -/***/ }), - /***/ "zmvN": /***/ (function(module, exports, __webpack_require__) { @@ -909,12 +836,10 @@ var _asyncToGenerator2 = _interopRequireDefault(__webpack_require__("+oT+")); var _promise = _interopRequireDefault(__webpack_require__("eVuF")); -var _set = _interopRequireDefault(__webpack_require__("ttDY")); - var _mitt = _interopRequireDefault(__webpack_require__("kiME")); var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl")); -/* global document */ +/* global document, window */ function supportsPreload(el) { @@ -941,10 +866,16 @@ class PageLoader { this.buildId = buildId; this.assetPrefix = assetPrefix; this.pageCache = {}; - this.prefetchCache = new _set.default(); this.pageRegisterEvents = (0, _mitt.default)(); this.loadingRoutes = {}; this.promisedBuildId = _promise.default.resolve(); + + if (false) {} + } // Returns a promise for the dependencies for a particular route + + + getDependencies(route) { + return this.promisedBuildManifest.then(man => man[route] && man[route].map(url => "/_next/" + url) || []); } normalizeRoute(route) { @@ -993,12 +924,13 @@ class PageLoader { if (document.getElementById("__NEXT_PAGE__" + route)) { return; - } // Load the script if not asked to load yet. - + } if (!this.loadingRoutes[route]) { - this.loadScript(route); - this.loadingRoutes[route] = true; + if (false) {} else { + this.loadRoute(route); + this.loadingRoutes[route] = true; + } } }); } @@ -1023,35 +955,41 @@ class PageLoader { }); } - loadScript(route) { + loadRoute(route) { var _this = this; return (0, _asyncToGenerator2.default)(function* () { yield _this.promisedBuildId; route = _this.normalizeRoute(route); let scriptRoute = route === '/' ? '/index.js' : route + ".js"; - const script = document.createElement('script'); + const url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - if ( true && 'noModule' in script) { - script.type = 'module'; - scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); - } + _this.loadScript(url, route, true); + })(); + } - const url = _this.assetPrefix + "/_next/static/" + encodeURIComponent(_this.buildId) + "/pages" + scriptRoute; - script.crossOrigin = "anonymous"; - script.src = url; + loadScript(url, route, isPage) { + const script = document.createElement('script'); - script.onerror = () => { - const error = new Error("Error loading script " + url); - error.code = 'PAGE_LOAD_ERROR'; + if ( true && 'noModule' in script) { + script.type = 'module'; // Only page bundle scripts need to have .module added to url, + // dependencies already have it added during build manifest creation - _this.pageRegisterEvents.emit(route, { - error - }); - }; + if (isPage) url = url.replace(/\.js$/, '.module.js'); + } - document.body.appendChild(script); - })(); + script.crossOrigin = "anonymous"; + script.src = url; + + script.onerror = () => { + const error = new Error("Error loading script " + url); + error.code = 'PAGE_LOAD_ERROR'; + this.pageRegisterEvents.emit(route, { + error + }); + }; + + document.body.appendChild(script); } // This method if called by the route code. @@ -1085,10 +1023,11 @@ class PageLoader { register(); } - prefetch(route) { + prefetch(route, isDependency) { var _this2 = this; return (0, _asyncToGenerator2.default)(function* () { + yield _this2.promisedBuildId; route = _this2.normalizeRoute(route); let scriptRoute = (route === '/' ? '/index' : route) + ".js"; @@ -1096,11 +1035,12 @@ class PageLoader { scriptRoute = scriptRoute.replace(/\.js$/, '.module.js'); } - if (_this2.prefetchCache.has(scriptRoute) || document.getElementById("__NEXT_PAGE__" + route)) { - return; - } + const url = isDependency ? route : _this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute; // n.b. If preload is not supported, we fall back to `loadPage` which has + // its own deduping mechanism. - _this2.prefetchCache.add(scriptRoute); // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE + if (document.querySelector("link[rel=\"preload\"][href^=\"" + url + "\"]") || document.getElementById("__NEXT_PAGE__" + route)) { + return; + } // Inspired by quicklink, license: https://github.com/GoogleChromeLabs/quicklink/blob/master/LICENSE let cn; @@ -1110,14 +1050,21 @@ class PageLoader { if ((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData) { return; } - } // Feature detection is used to see if preload is supported + } + + if (false) {} // Feature detection is used to see if preload is supported // If not fall back to loading script tags before the page is loaded // https://caniuse.com/#feat=link-rel-preload if (hasPreload) { - yield _this2.promisedBuildId; - preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute); + preloadScript(url); + return; + } + + if (isDependency) { + // loadPage will automatically handle depencies, so no need to + // preload them manually return; } ```
timneutkens commented 5 years ago

So excited for this 🚀❤️

slorber commented 5 years ago

Hi,

Just wanted to ask, has anyone done any benchmark and see an improvement with this new config? I'd like to explore the same kind of setup for Gatsby, I guess the heuristics make sense for both Next and Gatsby (https://github.com/gatsbyjs/gatsby/issues/16661)

stubbornella commented 5 years ago

@slorber we are in the process of benchmarking the improvements against https://zeit.co. It will take a few more weeks to get that finished, but we're happy to share. @atcastle can you share the data you have so far?

Tom910 commented 5 years ago

@stubbornella Hi, any updates?

abraxxas commented 5 years ago

We tried this feature on our project and discovered some weird problem with css chunks. When loading the page via ssr everything works. When navigating to the page via csr we get following error unexpected token .

I checked and bot the name and content of the css chunks are the same in csr and ssr (_next/static/css/1whVq9IAqZiB1lomB8S8Pbp4uA=.14c83442.chunk.css) but chrome somehow complains about the css file when it is loaded via client side render

stubbornella commented 4 years ago

@abraxxas we think we cleared up this bug. If you see it in latest can you let @atcastle and I know?

abraxxas commented 4 years ago

@stubbornella just checked with 9.1.2-canary.7 still getting the same error as described above. Is there anything i can do to provide more information for you?