-
Notifications
You must be signed in to change notification settings - Fork 27.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Golf page-loader #8190
Golf page-loader #8190
Conversation
Stats from current PRClick to expand stats ✅ Total Bundle Size Decrease ✅
Click to expand serverless stats ✅ Total Bundle Size Decrease ✅
Diff for main.js@@ -1103,22 +1103,26 @@ var _mitt = _interopRequireDefault(__webpack_require__("kiME"));
var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl"));
/* global document */
-// smaller version of https://gist.github.com/igrigorik/a02f2359f3bc50ca7a9c
-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 preloadScript(url) {
+ var link = document.createElement('link');
+ link.rel = 'preload';
+ link.crossOrigin = undefined;
+ link.href = url;
+ link.as = 'script';
+ document.head.appendChild(link);
+}
var PageLoader =
/*#__PURE__*/
@@ -1309,7 +1313,7 @@ function () {
return (0, _asyncToGenerator2["default"])(
/*#__PURE__*/
_regenerator["default"].mark(function _callee2() {
- var scriptRoute, link;
+ var scriptRoute, cn;
return _regenerator["default"].wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
@@ -1328,15 +1332,14 @@ function () {
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
- if (!('connection' in navigator)) {
+ if (!(cn = navigator.connection)) {
_context2.next = 9;
break;
}
- if (!((navigator.connection.effectiveType || '').indexOf('2g') !== -1 || navigator.connection.saveData)) {
+ if (!((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData)) {
_context2.next = 9;
break;
}
@@ -1345,7 +1348,7 @@ function () {
case 9:
if (!hasPreload) {
- _context2.next = 19;
+ _context2.next = 14;
break;
}
@@ -1353,23 +1356,18 @@ function () {
return _this2.promisedBuildId;
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);
+ preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute);
return _context2.abrupt("return");
- case 19:
+ case 14:
if (!(document.readyState === 'complete')) {
- _context2.next = 23;
+ _context2.next = 18;
break;
}
return _context2.abrupt("return", _this2.loadPage(route)["catch"](function () {}));
- case 23:
+ case 18:
return _context2.abrupt("return", new _promise["default"](function (resolve) {
window.addEventListener('load', function () {
_this2.loadPage(route).then(function () {
@@ -1380,7 +1378,7 @@ function () {
});
}));
- case 24:
+ case 19:
case "end":
return _context2.stop();
}
@@ -1388,18 +1386,6 @@ function () {
}, _callee2);
}))();
}
- }, {
- key: "clearCache",
- value: function clearCache(route) {
- route = this.normalizeRoute(route);
- delete this.pageCache[route];
- delete this.loadingRoutes[route];
- var script = document.getElementById("__NEXT_PAGE__" + route);
-
- if (script) {
- script.parentNode.removeChild(script);
- }
- }
}]);
return PageLoader;
}();
|
Stats from current PRClick to expand stats ✅ Total Bundle Size Decrease ✅
Click to expand serverless stats ✅ Total Bundle Size Decrease ✅
Diff for main.js@@ -1103,22 +1103,26 @@ var _mitt = _interopRequireDefault(__webpack_require__("kiME"));
var _unfetch = _interopRequireDefault(__webpack_require__("m/Gl"));
/* global document */
-// smaller version of https://gist.github.com/igrigorik/a02f2359f3bc50ca7a9c
-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 preloadScript(url) {
+ var link = document.createElement('link');
+ link.rel = 'preload';
+ link.crossOrigin = undefined;
+ link.href = url;
+ link.as = 'script';
+ document.head.appendChild(link);
+}
var PageLoader =
/*#__PURE__*/
@@ -1309,7 +1313,7 @@ function () {
return (0, _asyncToGenerator2["default"])(
/*#__PURE__*/
_regenerator["default"].mark(function _callee2() {
- var scriptRoute, link;
+ var scriptRoute, cn;
return _regenerator["default"].wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
@@ -1328,15 +1332,14 @@ function () {
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
- if (!('connection' in navigator)) {
+ if (!(cn = navigator.connection)) {
_context2.next = 9;
break;
}
- if (!((navigator.connection.effectiveType || '').indexOf('2g') !== -1 || navigator.connection.saveData)) {
+ if (!((cn.effectiveType || '').indexOf('2g') !== -1 || cn.saveData)) {
_context2.next = 9;
break;
}
@@ -1345,7 +1348,7 @@ function () {
case 9:
if (!hasPreload) {
- _context2.next = 19;
+ _context2.next = 14;
break;
}
@@ -1353,23 +1356,18 @@ function () {
return _this2.promisedBuildId;
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);
+ preloadScript(_this2.assetPrefix + "/_next/static/" + encodeURIComponent(_this2.buildId) + "/pages" + scriptRoute);
return _context2.abrupt("return");
- case 19:
+ case 14:
if (!(document.readyState === 'complete')) {
- _context2.next = 23;
+ _context2.next = 18;
break;
}
return _context2.abrupt("return", _this2.loadPage(route)["catch"](function () {}));
- case 23:
+ case 18:
return _context2.abrupt("return", new _promise["default"](function (resolve) {
window.addEventListener('load', function () {
_this2.loadPage(route).then(function () {
@@ -1380,7 +1378,7 @@ function () {
});
}));
- case 24:
+ case 19:
case "end":
return _context2.stop();
}
@@ -1388,18 +1386,6 @@ function () {
}, _callee2);
}))();
}
- }, {
- key: "clearCache",
- value: function clearCache(route) {
- route = this.normalizeRoute(route);
- delete this.pageCache[route];
- delete this.loadingRoutes[route];
- var script = document.getElementById("__NEXT_PAGE__" + route);
-
- if (script) {
- script.parentNode.removeChild(script);
- }
- }
}]);
return PageLoader;
}();
|
@Timer Just something to keep in mind with this sort of optimizations, while it may result in less bytes over the wire, this |
@Janpot I believe you're referring to v8 engine deoptimizing While this may "deoptimize" the code in legacy browsers, it only has a measurable effect on code with high cyclomatic complexity. In this specific case, "execution speed" is irrelevant because this code path is not in the hot-path (to hydration, or even rendering). So minimal bytes will always be preferred. edit: this also prevents dual-access to a DOM property ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice bundle savings 👍
Note: CI failures are un-related to this PR, confirmed locally
@Timer I didn't mean the deoptimization, throwing and catching exceptions is generally slower than testing properties. But as you said, execution speed is irrelevant in this context, and as I said before, the impact is probably negligible anyway. |
Ah, sure -- |
The bad performance code path would only happen on outdated browsers anyway. So nothing to worry about in the end I think. |
Yeah, I checked the perf for curiosity -- only a 4% +- 2% difference on modern browsers. |
* Refactor SplitChunksPlugin configs and add experimental chunking strategy * Use typeDefs for SplitChunksConfig * Modify build manifest plugin to create runtime build manifest * Add support for granular chunks to page-loader * Ensure normal behavior if experimental granularChunks flag is false * Update client build manifest to remove iife & implicit global * Factor out '/_next/' prepending into getDependencies * Update packages/next/build/webpack-config.ts filepath regex Co-Authored-By: Jason Miller <developit@users.noreply.github.com> * Simplify dependency load ordering in page-loader.js * Use SHA1 hash to shorten filenames for dependency modules * Add scheduler to framework cacheGroup in webpack-config * Update page loader to not duplicate script tags with query parameters * Ensure no slashes end up in the file hashes * Add prop-types to framework chunk * Fix issue with mis-attributed events * Increase modern build size budget--possibly decrement after consulting with @janicklasralph * Use module.rawRequest for lib chunks Co-Authored-By: Daniel Stockman <daniel.stockman@gmail.com> * Dasherize lib chunk names Co-Authored-By: Daniel Stockman <daniel.stockman@gmail.com> * Fix typescript errors, reorganize lib name logic * Dasherize rawRequest, short circuit name logic when rawRequest found * Add `scheduler` package to test regex * Fix a nit * Adjust build manifest plugin * Shorten key name * Extract createPreloadLink helper * Extract getDependencies helper * Move method * Minimize diff * Minimize diff x2 * Fix Array.from polyfill * Simplify page loader code * Remove async=false for script tags * Code golf `getDependencies` implementation * Require lib chunks be in node_modules * Update packages/next/build/webpack-config.ts Co-Authored-By: Joe Haddad <timer150@gmail.com> * Replace remaining missed windows compat regex * Trim client manifest * Prevent duplicate link preload tags * Revert size test changes * Squash manifest size even further * Add comment for clarity * Code golfing 🏌️♂️ * Correctly select modern dependencies * Ship separate modern client manifest when module/module enabled * Update packages/next/build/webpack/plugins/build-manifest-plugin.ts Co-Authored-By: Joe Haddad <timer150@gmail.com> * Remove unneccessary filter from page-loader * Add lookbehind to file extension regex in page-loader * v9.0.3 * Update examples for Apollo with AppTree (#8180) * Update examples for Apollo with AppTree * Fix apolloClient being overwritten when rendering AppTree * Golf page-loader (#8190) * Remove lookbehind for module replacement * Wait for build manifest promise before page load or prefetch * Updating modern-only chunks inside the right entry point * Fixing ts errors * Rename variable * Revert "Wait for build manifest promise before page load or prefetch" This reverts commit c370528. * Use proper typedef for webpack chunk * Re-enable promisified client build manifest * Fix bug in getDependencies map * Insert check for granularChunks in page-loader * Increase size limit temporarily for granular chunks * Add 50ms delay to flaky test * Set env.__NEXT_GRANULAR_CHUNKS in webpack config * Reset size limit to 187 * Set process.env.__NEXT_GRANULAR_CHUNKS to false if selectivePageBuilding * Update test/integration/production/test/index.test.js Co-Authored-By: Joe Haddad <timer150@gmail.com> * Do not create promise if not using chunking PR
clearCache
is an unused functiontry
/catch
can be used for safe property access👋 1.11 kB