Skip to content

Commit

Permalink
Use react-dom/server.browser in Node.js (#33950)
Browse files Browse the repository at this point in the history
Instead of branching rendering based on Node.js and browser/web runtimes, we should just use the web version for now, which can run as-is on versions >=16.5.0 of Node.js, polyfilling `ReadableStream` on older versions when necessary.

There are a few potential downsides to this, as React is less able to optimize flushing and execution. We can revisit that in the future though if desired.
  • Loading branch information
devknoll committed Feb 4, 2022
1 parent 502a869 commit 0b1d5e1
Show file tree
Hide file tree
Showing 9 changed files with 201 additions and 286 deletions.
8 changes: 0 additions & 8 deletions packages/next/build/webpack-config.ts
Expand Up @@ -610,14 +610,6 @@ export default async function getBaseWebpackConfig(
}
: {}),

...(webServerRuntime
? {
'react-dom/server': dev
? 'react-dom/cjs/react-dom-server.browser.development'
: 'react-dom/cjs/react-dom-server.browser.production.min',
}
: {}),

setimmediate: 'next/dist/compiled/setimmediate',
},
...(targetWeb
Expand Down
6 changes: 6 additions & 0 deletions packages/next/server/node-polyfill-readable-stream.js
@@ -0,0 +1,6 @@
import { ReadableStream } from './web/sandbox/readable-stream'

// Polyfill ReadableStream in the Node.js environment
if (!global.ReadableStream) {
global.ReadableStream = ReadableStream
}
38 changes: 32 additions & 6 deletions packages/next/server/render-result.ts
@@ -1,15 +1,14 @@
import type { ServerResponse } from 'http'
import type { Writable } from 'stream'

export type NodeWritablePiper = (
res: Writable,
export type ResultPiper = (
push: (chunks: Uint8Array[]) => void,
next: (err?: Error) => void
) => void

export default class RenderResult {
_result: string | NodeWritablePiper
_result: string | ResultPiper

constructor(response: string | NodeWritablePiper) {
constructor(response: string | ResultPiper) {
this._result = response
}

Expand All @@ -29,8 +28,35 @@ export default class RenderResult {
)
}
const response = this._result
const flush =
typeof (res as any).flush === 'function'
? () => (res as any).flush()
: () => {}

return new Promise((resolve, reject) => {
response(res, (err) => (err ? reject(err) : resolve()))
let fatalError = false
response(
(chunks) => {
// The state of the stream is non-deterministic after
// writing, so any error becomes fatal.
fatalError = true
res.cork()
chunks.forEach((chunk) => res.write(chunk))
res.uncork()
flush()
},
(err) => {
if (err) {
if (fatalError) {
res.destroy(err)
}
reject(err)
} else {
res.end()
resolve()
}
}
)
})
}

Expand Down

1 comment on commit 0b1d5e1

@ijjk
Copy link
Member

@ijjk ijjk commented on 0b1d5e1 Feb 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stats from current release

Default Build (Increase detected ⚠️)
General Overall increase ⚠️
vercel/next.js canary v12.0.10 vercel/next.js refs/heads/canary Change
buildDuration 15.6s 19.3s ⚠️ +3.7s
buildDurationCached 3.9s 7.5s ⚠️ +3.7s
nodeModulesSize 359 MB 359 MB ⚠️ +20.7 kB
Page Load Tests Overall increase ✓
vercel/next.js canary v12.0.10 vercel/next.js refs/heads/canary Change
/ failed reqs 0 0
/ total time (seconds) 3.913 3.586 -0.33
/ avg req/sec 638.97 697.21 +58.24
/error-in-render failed reqs 0 0
/error-in-render total time (seconds) 2.09 2.091 0
/error-in-render avg req/sec 1196.42 1195.52 ⚠️ -0.9
Client Bundles (main, webpack, commons) Overall increase ⚠️
vercel/next.js canary v12.0.10 vercel/next.js refs/heads/canary Change
450.HASH.js gzip 179 B 179 B
framework-HASH.js gzip 42.2 kB 42.2 kB
main-HASH.js gzip 27.2 kB 27.3 kB ⚠️ +140 B
webpack-HASH.js gzip 1.44 kB 1.44 kB
Overall change 71 kB 71.2 kB ⚠️ +140 B
Legacy Client Bundles (polyfills)
vercel/next.js canary v12.0.10 vercel/next.js refs/heads/canary Change
polyfills-HASH.js gzip 31 kB 31 kB
Overall change 31 kB 31 kB
Client Pages Overall decrease ✓
vercel/next.js canary v12.0.10 vercel/next.js refs/heads/canary Change
_app-HASH.js gzip 1.37 kB 1.37 kB
_error-HASH.js gzip 194 B 194 B
amp-HASH.js gzip 312 B 312 B
css-HASH.js gzip 326 B 326 B
dynamic-HASH.js gzip 2.37 kB 2.37 kB
head-HASH.js gzip 350 B 350 B
hooks-HASH.js gzip 919 B 919 B
image-HASH.js gzip 4.94 kB 4.94 kB -1 B
index-HASH.js gzip 263 B 263 B
link-HASH.js gzip 2.19 kB 2.19 kB
routerDirect..HASH.js gzip 321 B 321 B
script-HASH.js gzip 383 B 383 B
withRouter-HASH.js gzip 318 B 318 B
85e02e95b279..7e3.css gzip 107 B 107 B
Overall change 14.4 kB 14.3 kB -1 B
Client Build Manifests
vercel/next.js canary v12.0.10 vercel/next.js refs/heads/canary Change
_buildManifest.js gzip 459 B 459 B
Overall change 459 B 459 B
Rendered Page Sizes Overall decrease ✓
vercel/next.js canary v12.0.10 vercel/next.js refs/heads/canary Change
index.html gzip 530 B 528 B -2 B
link.html gzip 543 B 543 B
withRouter.html gzip 525 B 524 B -1 B
Overall change 1.6 kB 1.59 kB -3 B

Diffs

Diff for _buildManifest.js
@@ -12,7 +12,7 @@ self.__BUILD_MANIFEST = {
   ],
   "/head": ["static\u002Fchunks\u002Fpages\u002Fhead-7100d3b2a548f0e4.js"],
   "/hooks": ["static\u002Fchunks\u002Fpages\u002Fhooks-538d621a0e670391.js"],
-  "/image": ["static\u002Fchunks\u002Fpages\u002Fimage-53463827ccaef972.js"],
+  "/image": ["static\u002Fchunks\u002Fpages\u002Fimage-f97943edf7ae3dd3.js"],
   "/link": ["static\u002Fchunks\u002Fpages\u002Flink-f0a2c3bb0706d8b2.js"],
   "/routerDirect": [
     "static\u002Fchunks\u002Fpages\u002FrouterDirect-76232dd6bc335a24.js"
Diff for image-HASH.js
@@ -9,7 +9,7 @@
       (window.__NEXT_P = window.__NEXT_P || []).push([
         "/image",
         function() {
-          return __webpack_require__(5924);
+          return __webpack_require__(3155);
         }
       ]);
       if (false) {
@@ -1087,7 +1087,7 @@
       /***/
     },
 
-    /***/ 5924: /***/ function(
+    /***/ 3155: /***/ function(
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
Diff for main-HASH.js
@@ -474,8 +474,8 @@
       var _routeAnnouncer = __webpack_require__(8982);
       var _router1 = __webpack_require__(387);
       var _isError = __webpack_require__(676);
-      var _vitals = __webpack_require__(7813);
-      var _refresh = __webpack_require__(7739);
+      var _vitals = __webpack_require__(5834);
+      var _refresh = __webpack_require__(9831);
       function asyncGeneratorStep(
         gen,
         resolve,
@@ -628,7 +628,7 @@
         document.getElementById("__NEXT_DATA__").textContent
       );
       window.__NEXT_DATA__ = data;
-      var version = "12.0.10";
+      var version = "12.0.11-canary.5";
       exports.version = version;
       var looseToArray = function(input) {
         return [].slice.call(input);
@@ -980,16 +980,15 @@
                         props: hydrateProps,
                         err: initialErr
                       };
-                      if (false) {
+                      if (!opts.beforeRender) {
+                        _ctx.next = 42;
+                        break;
                       }
+                      _ctx.next = 42;
+                      return opts.beforeRender();
+                    case 42:
                       render(renderCtx);
-                      return _ctx.abrupt("return", emitter);
-                    case 44:
-                      return _ctx.abrupt("return", {
-                        emitter: emitter,
-                        renderCtx: renderCtx
-                      });
-                    case 45:
+                    case 43:
                     case "end":
                       return _ctx.stop();
                   }
@@ -1464,6 +1463,7 @@
         // don't cause any hydration delay:
         _react.default.useEffect(function() {
           (0, _performanceRelayer).default(onPerfEntry);
+          (0, _vitals).flushBufferedVitalsMetrics();
         }, []);
         return children;
       }
@@ -2768,28 +2768,6 @@
       /***/
     },
 
-    /***/ 7739: /***/ function(
-      __unused_webpack_module,
-      exports,
-      __webpack_require__
-    ) {
-      "use strict";
-
-      Object.defineProperty(exports, "__esModule", {
-        value: true
-      });
-      exports.useRefreshRoot = useRefreshRoot;
-      exports.RefreshContext = void 0;
-      var _react = __webpack_require__(7294);
-      var RefreshContext = (0, _react).createContext(function(_) {});
-      exports.RefreshContext = RefreshContext;
-      function useRefreshRoot() {
-        return (0, _react).useContext(RefreshContext);
-      } //# sourceMappingURL=refresh.js.map
-
-      /***/
-    },
-
     /***/ 699: /***/ function(
       __unused_webpack_module,
       exports,
@@ -3146,7 +3124,7 @@
       /***/
     },
 
-    /***/ 7813: /***/ function(
+    /***/ 9831: /***/ function(
       __unused_webpack_module,
       exports,
       __webpack_require__
@@ -3156,13 +3134,45 @@
       Object.defineProperty(exports, "__esModule", {
         value: true
       });
+      exports.useRefreshRoot = useRefreshRoot;
+      exports.RefreshContext = void 0;
+      var _react = __webpack_require__(7294);
+      var RefreshContext = (0, _react).createContext(function(_) {});
+      exports.RefreshContext = RefreshContext;
+      function useRefreshRoot() {
+        return (0, _react).useContext(RefreshContext);
+      } //# sourceMappingURL=refresh.js.map
+
+      /***/
+    },
+
+    /***/ 5834: /***/ function(
+      __unused_webpack_module,
+      exports,
+      __webpack_require__
+    ) {
+      "use strict";
+
+      Object.defineProperty(exports, "__esModule", {
+        value: true
+      });
+      exports.getBufferedVitalsMetrics = getBufferedVitalsMetrics;
+      exports.flushBufferedVitalsMetrics = flushBufferedVitalsMetrics;
       exports.trackWebVitalMetric = trackWebVitalMetric;
       exports.useWebVitalsReport = useWebVitalsReport;
       exports.webVitalsCallbacks = void 0;
       var _react = __webpack_require__(7294);
       var webVitalsCallbacks = new Set();
       exports.webVitalsCallbacks = webVitalsCallbacks;
+      var flushed = false;
       var metrics = [];
+      function getBufferedVitalsMetrics() {
+        return metrics;
+      }
+      function flushBufferedVitalsMetrics() {
+        flushed = true;
+        metrics.length = 0;
+      }
       function trackWebVitalMetric(metric) {
         metrics.push(metric);
         webVitalsCallbacks.forEach(function(callback) {
@@ -3171,6 +3181,8 @@
       }
       function useWebVitalsReport(callback) {
         var metricIndexRef = (0, _react).useRef(0);
+        if (false) {
+        }
         (0, _react).useEffect(
           function() {
             // Flush calculated metrics
@@ -3814,6 +3826,9 @@
                 return /*#__PURE__*/ _react.default.cloneElement(c, newProps);
               }
             }
+            // TODO(kara): warn for stylesheets as well as scripts
+            if (false) {
+            }
             return /*#__PURE__*/ _react.default.cloneElement(c, {
               key: key
             });
@@ -5052,29 +5067,65 @@
                                   delBasePath(pathname)
                                 )
                               : pathname;
-                            if (shouldResolveHref && pathname !== "/_error") {
-                              options._shouldResolveHref = true;
-                              if (false) {
-                              } else {
-                                parsed.pathname = resolveDynamicRoute(
-                                  pathname,
-                                  pages
-                                );
-                                if (parsed.pathname !== pathname) {
-                                  pathname = parsed.pathname;
-                                  parsed.pathname = addBasePath(pathname);
-                                  url = (0, _utils).formatWithValidation(
-                                    parsed
-                                  );
-                                }
-                              }
+                            if (
+                              !(shouldResolveHref && pathname !== "/_error")
+                            ) {
+                              _ctx.next = 69;
+                              break;
+                            }
+                            options._shouldResolveHref = true;
+                            if (true) {
+                              _ctx.next = 68;
+                              break;
                             }
+                            rewritesResult = (0, _resolveRewrites).default(
+                              addBasePath(addLocale(cleanedAs, _this.locale)),
+                              pages,
+                              rewrites,
+                              query,
+                              function(p) {
+                                return resolveDynamicRoute(p, pages);
+                              },
+                              _this.locales
+                            );
+                            if (!rewritesResult.externalDest) {
+                              _ctx.next = 64;
+                              break;
+                            }
+                            location.href = as;
+                            return _ctx.abrupt("return", true);
+                          case 64:
+                            resolvedAs = rewritesResult.asPath;
+                            if (
+                              rewritesResult.matchedPage &&
+                              rewritesResult.resolvedHref
+                            ) {
+                              // if this directly matches a page we need to update the href to
+                              // allow the correct page chunk to be loaded
+                              pathname = rewritesResult.resolvedHref;
+                              parsed.pathname = addBasePath(pathname);
+                              url = (0, _utils).formatWithValidation(parsed);
+                            }
+                            _ctx.next = 69;
+                            break;
+                          case 68: {
+                            parsed.pathname = resolveDynamicRoute(
+                              pathname,
+                              pages
+                            );
+                            if (parsed.pathname !== pathname) {
+                              pathname = parsed.pathname;
+                              parsed.pathname = addBasePath(pathname);
+                              url = (0, _utils).formatWithValidation(parsed);
+                            }
+                          }
+                          case 69:
                             if (isLocalURL(as)) {
-                              _ctx.next = 63;
+                              _ctx.next = 74;
                               break;
                             }
                             if (true) {
-                              _ctx.next = 61;
+                              _ctx.next = 72;
                               break;
                             }
                             throw new Error(
@@ -5086,10 +5137,10 @@
                                 ) +
                                 "\nSee more info: https://nextjs.org/docs/messages/invalid-relative-url-external-as"
                             );
-                          case 61:
+                          case 72:
                             window.location.href = as;
                             return _ctx.abrupt("return", false);
-                          case 63:
+                          case 74:
                             resolvedAs = delLocale(
                               delBasePath(resolvedAs),
                               _this.locale
@@ -5105,10 +5156,10 @@
                                 )
                               )
                             ) {
-                              _ctx.next = 84;
+                              _ctx.next = 95;
                               break;
                             }
-                            _ctx.next = 67;
+                            _ctx.next = 78;
                             return _this._preflightRequest({
                               as: as,
                               cache: "production" === "production",
@@ -5116,10 +5167,10 @@
                               pathname: pathname,
                               query: query
                             });
-                          case 67:
+                          case 78:
                             effect = _ctx.sent;
                             if (!(effect.type === "rewrite")) {
-                              _ctx.next = 72;
+                              _ctx.next = 83;
                               break;
                             }
                             {
@@ -5133,11 +5184,11 @@
                               parsed.pathname = effect.resolvedHref;
                               url = (0, _utils).formatWithValidation(parsed);
                             }
-                            _ctx.next = 84;
+                            _ctx.next = 95;
                             break;
-                          case 72:
+                          case 83:
                             if (!(effect.type === "redirect" && effect.newAs)) {
-                              _ctx.next = 76;
+                              _ctx.next = 87;
                               break;
                             }
                             return _ctx.abrupt(
@@ -5149,13 +5200,13 @@
                                 options
                               )
                             );
-                          case 76:
+                          case 87:
                             if (
                               !(
                                 effect.type === "redirect" && effect.destination
                               )
                             ) {
-                              _ctx.next = 81;
+                              _ctx.next = 92;
                               break;
                             }
                             window.location.href = effect.destination;
@@ -5163,14 +5214,14 @@
                               "return",
                               new Promise(function() {})
                             );
-                          case 81:
+                          case 92:
                             if (
                               !(
                                 effect.type === "refresh" &&
                                 as !== window.location.pathname
                               )
                             ) {
-                              _ctx.next = 84;
+                              _ctx.next = 95;
                               break;
                             }
                             window.location.href = as;
@@ -5178,13 +5229,13 @@
                               "return",
                               new Promise(function() {})
                             );
-                          case 84:
+                          case 95:
                             route = (0,
                             _normalizeTrailingSlash).removePathTrailingSlash(
                               pathname
                             );
                             if (!(0, _isDynamic).isDynamicRoute(route)) {
-                              _ctx.next = 100;
+                              _ctx.next = 111;
                               break;
                             }
                             parsedAs1 = (0, _parseRelativeUrl).parseRelativeUrl(
@@ -5205,7 +5256,7 @@
                                 (shouldInterpolate && !interpolatedAs.result)
                               )
                             ) {
-                              _ctx.next = 99;
+                              _ctx.next = 110;
                               break;
                             }
                             missingParams = Object.keys(
@@ -5214,7 +5265,7 @@
                               return !query[param];
                             });
                             if (!(missingParams.length > 0)) {
-                              _ctx.next = 97;
+                              _ctx.next = 108;
                               break;
                             }
                             if (false) {
@@ -5242,10 +5293,10 @@
                                     : "incompatible-href-as"
                                 )
                             );
-                          case 97:
-                            _ctx.next = 100;
+                          case 108:
+                            _ctx.next = 111;
                             break;
-                          case 99:
+                          case 110:
                             if (shouldInterpolate) {
                               as = (0, _utils).formatWithValidation(
                                 Object.assign({}, parsedAs1, {
@@ -5260,14 +5311,14 @@
                               // Merge params into `query`, overwriting any specified in search
                               Object.assign(query, routeMatch);
                             }
-                          case 100:
+                          case 111:
                             Router.events.emit(
                               "routeChangeStart",
                               as,
                               routeProps
                             );
-                            _ctx.prev = 101;
-                            _ctx.next = 105;
+                            _ctx.prev = 112;
+                            _ctx.next = 116;
                             return _this.getRouteInfo(
                               route,
                               pathname,
@@ -5276,20 +5327,20 @@
                               resolvedAs,
                               routeProps
                             );
-                          case 105:
+                          case 116:
                             routeInfo = _ctx.sent;
                             (error = routeInfo.error),
                               (props = routeInfo.props),
                               (__N_SSG = routeInfo.__N_SSG),
                               (__N_SSP = routeInfo.__N_SSP);
                             if (!((__N_SSG || __N_SSP) && props)) {
-                              _ctx.next = 132;
+                              _ctx.next = 143;
                               break;
                             }
                             if (
                               !(props.pageProps && props.pageProps.__N_REDIRECT)
                             ) {
-                              _ctx.next = 117;
+                              _ctx.next = 128;
                               break;
                             }
                             destination = props.pageProps.__N_REDIRECT;
@@ -5299,7 +5350,7 @@
                                 props.pageProps.__N_REDIRECT_BASE_PATH !== false
                               )
                             ) {
-                              _ctx.next = 115;
+                              _ctx.next = 126;
                               break;
                             }
                             parsedHref = (0,
@@ -5319,31 +5370,31 @@
                               "return",
                               _this.change(method, newUrl, newAs, options)
                             );
-                          case 115:
+                          case 126:
                             window.location.href = destination;
                             return _ctx.abrupt(
                               "return",
                               new Promise(function() {})
                             );
-                          case 117:
+                          case 128:
                             _this.isPreview = !!props.__N_PREVIEW;
                             if (!(props.notFound === SSG_DATA_NOT_FOUND)) {
-                              _ctx.next = 132;
+                              _ctx.next = 143;
                               break;
                             }
-                            _ctx.prev = 120;
-                            _ctx.next = 123;
+                            _ctx.prev = 131;
+                            _ctx.next = 134;
                             return _this.fetchComponent("/404");
-                          case 123:
+                          case 134:
                             notFoundRoute = "/404";
-                            _ctx.next = 129;
+                            _ctx.next = 140;
                             break;
-                          case 126:
-                            _ctx.prev = 126;
-                            _ctx.t3 = _ctx["catch"](120);
+                          case 137:
+                            _ctx.prev = 137;
+                            _ctx.t3 = _ctx["catch"](131);
                             notFoundRoute = "/_error";
-                          case 129:
-                            _ctx.next = 131;
+                          case 140:
+                            _ctx.next = 142;
                             return _this.getRouteInfo(
                               notFoundRoute,
                               notFoundRoute,
@@ -5354,9 +5405,9 @@
                                 shallow: false
                               }
                             );
-                          case 131:
+                          case 142:
                             routeInfo = _ctx.sent;
-                          case 132:
+                          case 143:
                             Router.events.emit(
                               "beforeHistoryChange",
                               as,
@@ -5394,7 +5445,7 @@
                                   y: 0
                                 }
                               : null;
-                            _ctx.next = 141;
+                            _ctx.next = 152;
                             return _this
                               .set(
                                 route,
@@ -5410,9 +5461,9 @@
                                 if (e.cancelled) error = error || e;
                                 else throw e;
                               });
-                          case 141:
+                          case 152:
                             if (!error) {
-                              _ctx.next = 144;
+                              _ctx.next = 155;
                               break;
                             }
                             Router.events.emit(
@@ -5422,7 +5473,7 @@
                               routeProps
                             );
                             throw error;
-                          case 144:
+                          case 155:
                             if (false) {
                             }
                             Router.events.emit(
@@ -5431,22 +5482,22 @@
                               routeProps
                             );
                             return _ctx.abrupt("return", true);
-                          case 149:
-                            _ctx.prev = 149;
-                            _ctx.t4 = _ctx["catch"](101);
+                          case 160:
+                            _ctx.prev = 160;
+                            _ctx.t4 = _ctx["catch"](112);
                             if (
                               !(
                                 (0, _isError).default(_ctx.t4) &&
                                 _ctx.t4.cancelled
                               )
                             ) {
-                              _ctx.next = 153;
+                              _ctx.next = 164;
                               break;
                             }
                             return _ctx.abrupt("return", false);
-                          case 153:
+                          case 164:
                             throw _ctx.t4;
-                          case 154:
+                          case 165:
                           case "end":
                             return _ctx.stop();
                         }
@@ -5455,8 +5506,8 @@
                     null,
                     [
                       [38, 50],
-                      [101, 149],
-                      [120, 126]
+                      [112, 160],
+                      [131, 137]
                     ]
                   );
                 })
@@ -5932,7 +5983,7 @@
                           pages = _ctx.sent;
                           resolvedAs = asPath;
                           if (true) {
-                            _ctx.next = 20;
+                            _ctx.next = 22;
                             break;
                           }
                           _ctx.next = 12;
@@ -5951,6 +6002,12 @@
                             },
                             _this.locales
                           );
+                          if (!rewritesResult.externalDest) {
+                            _ctx.next = 18;
+                            break;
+                          }
+                          return _ctx.abrupt("return");
+                        case 18:
                           resolvedAs = delLocale(
                             delBasePath(rewritesResult.asPath),
                             _this.locale
@@ -5965,9 +6022,9 @@
                             parsed.pathname = pathname;
                             url = (0, _utils).formatWithValidation(parsed);
                           }
-                          _ctx.next = 21;
+                          _ctx.next = 23;
                           break;
-                        case 20: {
+                        case 22: {
                           parsed.pathname = resolveDynamicRoute(
                             parsed.pathname,
                             pages
@@ -5978,14 +6035,14 @@
                             url = (0, _utils).formatWithValidation(parsed);
                           }
                         }
-                        case 21:
+                        case 23:
                           if (true) {
-                            _ctx.next = 23;
+                            _ctx.next = 25;
                             break;
                           }
                           return _ctx.abrupt("return");
-                        case 23:
-                          _ctx.next = 25;
+                        case 25:
+                          _ctx.next = 27;
                           return _this._preflightRequest({
                             as: addBasePath(asPath),
                             cache: true,
@@ -5993,7 +6050,7 @@
                             pathname: pathname,
                             query: query
                           });
-                        case 25:
+                        case 27:
                           effects = _ctx.sent;
                           if (effects.type === "rewrite") {
                             parsed.pathname = effects.resolvedHref;
@@ -6010,7 +6067,7 @@
                           _normalizeTrailingSlash).removePathTrailingSlash(
                             pathname
                           );
-                          _ctx.next = 30;
+                          _ctx.next = 32;
                           return Promise.all([
                             _this.pageLoader
                               ._isSsg(route)
@@ -6037,7 +6094,7 @@
                               options.priority ? "loadPage" : "prefetch"
                             ](route)
                           ]);
-                        case 30:
+                        case 32:
                         case "end":
                           return _ctx.stop();
                       }
Diff for index.html
@@ -19,7 +19,7 @@
       defer=""
     ></script>
     <script
-      src="/_next/static/chunks/main-c6fc133fe313f8ea.js"
+      src="/_next/static/chunks/main-2487a9a50a9f7dd4.js"
       defer=""
     ></script>
     <script
Diff for link.html
@@ -19,7 +19,7 @@
       defer=""
     ></script>
     <script
-      src="/_next/static/chunks/main-c6fc133fe313f8ea.js"
+      src="/_next/static/chunks/main-2487a9a50a9f7dd4.js"
       defer=""
     ></script>
     <script
Diff for withRouter.html
@@ -19,7 +19,7 @@
       defer=""
     ></script>
     <script
-      src="/_next/static/chunks/main-c6fc133fe313f8ea.js"
+      src="/_next/static/chunks/main-2487a9a50a9f7dd4.js"
       defer=""
     ></script>
     <script

Default Build with SWC (Increase detected ⚠️)
General Overall increase ⚠️
vercel/next.js canary v12.0.10 vercel/next.js refs/heads/canary Change
buildDuration 20s 24.2s ⚠️ +4.2s
buildDurationCached 3.8s 7.6s ⚠️ +3.8s
nodeModulesSize 359 MB 359 MB ⚠️ +20.7 kB
Page Load Tests Overall increase ✓
vercel/next.js canary v12.0.10 vercel/next.js refs/heads/canary Change
/ failed reqs 0 0
/ total time (seconds) 3.931 3.681 -0.25
/ avg req/sec 635.94 679.24 +43.3
/error-in-render failed reqs 0 0
/error-in-render total time (seconds) 2.12 2.101 -0.02
/error-in-render avg req/sec 1179.34 1190.13 +10.79
Client Bundles (main, webpack, commons) Overall increase ⚠️
vercel/next.js canary v12.0.10 vercel/next.js refs/heads/canary Change
450.HASH.js gzip 179 B 179 B
framework-HASH.js gzip 42.3 kB 42.3 kB
main-HASH.js gzip 27.3 kB 27.4 kB ⚠️ +144 B
webpack-HASH.js gzip 1.44 kB 1.44 kB
Overall change 71.2 kB 71.3 kB ⚠️ +144 B
Legacy Client Bundles (polyfills)
vercel/next.js canary v12.0.10 vercel/next.js refs/heads/canary Change
polyfills-HASH.js gzip 31 kB 31 kB
Overall change 31 kB 31 kB
Client Pages Overall decrease ✓
vercel/next.js canary v12.0.10 vercel/next.js refs/heads/canary Change
_app-HASH.js gzip 1.35 kB 1.35 kB
_error-HASH.js gzip 180 B 180 B
amp-HASH.js gzip 305 B 305 B
css-HASH.js gzip 321 B 321 B
dynamic-HASH.js gzip 2.36 kB 2.36 kB
head-HASH.js gzip 342 B 342 B
hooks-HASH.js gzip 911 B 911 B
image-HASH.js gzip 4.98 kB 4.97 kB -1 B
index-HASH.js gzip 256 B 256 B
link-HASH.js gzip 2.21 kB 2.21 kB
routerDirect..HASH.js gzip 314 B 314 B
script-HASH.js gzip 375 B 375 B
withRouter-HASH.js gzip 309 B 309 B
85e02e95b279..7e3.css gzip 107 B 107 B
Overall change 14.3 kB 14.3 kB -1 B
Client Build Manifests
vercel/next.js canary v12.0.10 vercel/next.js refs/heads/canary Change
_buildManifest.js gzip 459 B 459 B
Overall change 459 B 459 B
Rendered Page Sizes Overall decrease ✓
vercel/next.js canary v12.0.10 vercel/next.js refs/heads/canary Change
index.html gzip 532 B 532 B
link.html gzip 546 B 545 B -1 B
withRouter.html gzip 527 B 526 B -1 B
Overall change 1.6 kB 1.6 kB -2 B

Diffs

Diff for _buildManifest.js
@@ -12,7 +12,7 @@ self.__BUILD_MANIFEST = {
   ],
   "/head": ["static\u002Fchunks\u002Fpages\u002Fhead-7100d3b2a548f0e4.js"],
   "/hooks": ["static\u002Fchunks\u002Fpages\u002Fhooks-538d621a0e670391.js"],
-  "/image": ["static\u002Fchunks\u002Fpages\u002Fimage-53463827ccaef972.js"],
+  "/image": ["static\u002Fchunks\u002Fpages\u002Fimage-f97943edf7ae3dd3.js"],
   "/link": ["static\u002Fchunks\u002Fpages\u002Flink-f0a2c3bb0706d8b2.js"],
   "/routerDirect": [
     "static\u002Fchunks\u002Fpages\u002FrouterDirect-76232dd6bc335a24.js"
Diff for image-HASH.js
@@ -9,7 +9,7 @@
       (window.__NEXT_P = window.__NEXT_P || []).push([
         "/image",
         function() {
-          return __webpack_require__(5924);
+          return __webpack_require__(3155);
         }
       ]);
       if (false) {
@@ -1087,7 +1087,7 @@
       /***/
     },
 
-    /***/ 5924: /***/ function(
+    /***/ 3155: /***/ function(
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
Diff for main-HASH.js
@@ -474,8 +474,8 @@
       var _routeAnnouncer = __webpack_require__(8982);
       var _router1 = __webpack_require__(387);
       var _isError = __webpack_require__(676);
-      var _vitals = __webpack_require__(7813);
-      var _refresh = __webpack_require__(7739);
+      var _vitals = __webpack_require__(5834);
+      var _refresh = __webpack_require__(9831);
       function asyncGeneratorStep(
         gen,
         resolve,
@@ -628,7 +628,7 @@
         document.getElementById("__NEXT_DATA__").textContent
       );
       window.__NEXT_DATA__ = data;
-      var version = "12.0.10";
+      var version = "12.0.11-canary.5";
       exports.version = version;
       var looseToArray = function(input) {
         return [].slice.call(input);
@@ -980,16 +980,15 @@
                         props: hydrateProps,
                         err: initialErr
                       };
-                      if (false) {
+                      if (!opts.beforeRender) {
+                        _ctx.next = 42;
+                        break;
                       }
+                      _ctx.next = 42;
+                      return opts.beforeRender();
+                    case 42:
                       render(renderCtx);
-                      return _ctx.abrupt("return", emitter);
-                    case 44:
-                      return _ctx.abrupt("return", {
-                        emitter: emitter,
-                        renderCtx: renderCtx
-                      });
-                    case 45:
+                    case 43:
                     case "end":
                       return _ctx.stop();
                   }
@@ -1464,6 +1463,7 @@
         // don't cause any hydration delay:
         _react.default.useEffect(function() {
           (0, _performanceRelayer).default(onPerfEntry);
+          (0, _vitals).flushBufferedVitalsMetrics();
         }, []);
         return children;
       }
@@ -2768,28 +2768,6 @@
       /***/
     },
 
-    /***/ 7739: /***/ function(
-      __unused_webpack_module,
-      exports,
-      __webpack_require__
-    ) {
-      "use strict";
-
-      Object.defineProperty(exports, "__esModule", {
-        value: true
-      });
-      exports.useRefreshRoot = useRefreshRoot;
-      exports.RefreshContext = void 0;
-      var _react = __webpack_require__(7294);
-      var RefreshContext = (0, _react).createContext(function(_) {});
-      exports.RefreshContext = RefreshContext;
-      function useRefreshRoot() {
-        return (0, _react).useContext(RefreshContext);
-      } //# sourceMappingURL=refresh.js.map
-
-      /***/
-    },
-
     /***/ 699: /***/ function(
       __unused_webpack_module,
       exports,
@@ -3146,7 +3124,7 @@
       /***/
     },
 
-    /***/ 7813: /***/ function(
+    /***/ 9831: /***/ function(
       __unused_webpack_module,
       exports,
       __webpack_require__
@@ -3156,13 +3134,45 @@
       Object.defineProperty(exports, "__esModule", {
         value: true
       });
+      exports.useRefreshRoot = useRefreshRoot;
+      exports.RefreshContext = void 0;
+      var _react = __webpack_require__(7294);
+      var RefreshContext = (0, _react).createContext(function(_) {});
+      exports.RefreshContext = RefreshContext;
+      function useRefreshRoot() {
+        return (0, _react).useContext(RefreshContext);
+      } //# sourceMappingURL=refresh.js.map
+
+      /***/
+    },
+
+    /***/ 5834: /***/ function(
+      __unused_webpack_module,
+      exports,
+      __webpack_require__
+    ) {
+      "use strict";
+
+      Object.defineProperty(exports, "__esModule", {
+        value: true
+      });
+      exports.getBufferedVitalsMetrics = getBufferedVitalsMetrics;
+      exports.flushBufferedVitalsMetrics = flushBufferedVitalsMetrics;
       exports.trackWebVitalMetric = trackWebVitalMetric;
       exports.useWebVitalsReport = useWebVitalsReport;
       exports.webVitalsCallbacks = void 0;
       var _react = __webpack_require__(7294);
       var webVitalsCallbacks = new Set();
       exports.webVitalsCallbacks = webVitalsCallbacks;
+      var flushed = false;
       var metrics = [];
+      function getBufferedVitalsMetrics() {
+        return metrics;
+      }
+      function flushBufferedVitalsMetrics() {
+        flushed = true;
+        metrics.length = 0;
+      }
       function trackWebVitalMetric(metric) {
         metrics.push(metric);
         webVitalsCallbacks.forEach(function(callback) {
@@ -3171,6 +3181,8 @@
       }
       function useWebVitalsReport(callback) {
         var metricIndexRef = (0, _react).useRef(0);
+        if (false) {
+        }
         (0, _react).useEffect(
           function() {
             // Flush calculated metrics
@@ -3814,6 +3826,9 @@
                 return /*#__PURE__*/ _react.default.cloneElement(c, newProps);
               }
             }
+            // TODO(kara): warn for stylesheets as well as scripts
+            if (false) {
+            }
             return /*#__PURE__*/ _react.default.cloneElement(c, {
               key: key
             });
@@ -5052,29 +5067,65 @@
                                   delBasePath(pathname)
                                 )
                               : pathname;
-                            if (shouldResolveHref && pathname !== "/_error") {
-                              options._shouldResolveHref = true;
-                              if (false) {
-                              } else {
-                                parsed.pathname = resolveDynamicRoute(
-                                  pathname,
-                                  pages
-                                );
-                                if (parsed.pathname !== pathname) {
-                                  pathname = parsed.pathname;
-                                  parsed.pathname = addBasePath(pathname);
-                                  url = (0, _utils).formatWithValidation(
-                                    parsed
-                                  );
-                                }
-                              }
+                            if (
+                              !(shouldResolveHref && pathname !== "/_error")
+                            ) {
+                              _ctx.next = 69;
+                              break;
+                            }
+                            options._shouldResolveHref = true;
+                            if (true) {
+                              _ctx.next = 68;
+                              break;
                             }
+                            rewritesResult = (0, _resolveRewrites).default(
+                              addBasePath(addLocale(cleanedAs, _this.locale)),
+                              pages,
+                              rewrites,
+                              query,
+                              function(p) {
+                                return resolveDynamicRoute(p, pages);
+                              },
+                              _this.locales
+                            );
+                            if (!rewritesResult.externalDest) {
+                              _ctx.next = 64;
+                              break;
+                            }
+                            location.href = as;
+                            return _ctx.abrupt("return", true);
+                          case 64:
+                            resolvedAs = rewritesResult.asPath;
+                            if (
+                              rewritesResult.matchedPage &&
+                              rewritesResult.resolvedHref
+                            ) {
+                              // if this directly matches a page we need to update the href to
+                              // allow the correct page chunk to be loaded
+                              pathname = rewritesResult.resolvedHref;
+                              parsed.pathname = addBasePath(pathname);
+                              url = (0, _utils).formatWithValidation(parsed);
+                            }
+                            _ctx.next = 69;
+                            break;
+                          case 68: {
+                            parsed.pathname = resolveDynamicRoute(
+                              pathname,
+                              pages
+                            );
+                            if (parsed.pathname !== pathname) {
+                              pathname = parsed.pathname;
+                              parsed.pathname = addBasePath(pathname);
+                              url = (0, _utils).formatWithValidation(parsed);
+                            }
+                          }
+                          case 69:
                             if (isLocalURL(as)) {
-                              _ctx.next = 63;
+                              _ctx.next = 74;
                               break;
                             }
                             if (true) {
-                              _ctx.next = 61;
+                              _ctx.next = 72;
                               break;
                             }
                             throw new Error(
@@ -5086,10 +5137,10 @@
                                 ) +
                                 "\nSee more info: https://nextjs.org/docs/messages/invalid-relative-url-external-as"
                             );
-                          case 61:
+                          case 72:
                             window.location.href = as;
                             return _ctx.abrupt("return", false);
-                          case 63:
+                          case 74:
                             resolvedAs = delLocale(
                               delBasePath(resolvedAs),
                               _this.locale
@@ -5105,10 +5156,10 @@
                                 )
                               )
                             ) {
-                              _ctx.next = 84;
+                              _ctx.next = 95;
                               break;
                             }
-                            _ctx.next = 67;
+                            _ctx.next = 78;
                             return _this._preflightRequest({
                               as: as,
                               cache: "production" === "production",
@@ -5116,10 +5167,10 @@
                               pathname: pathname,
                               query: query
                             });
-                          case 67:
+                          case 78:
                             effect = _ctx.sent;
                             if (!(effect.type === "rewrite")) {
-                              _ctx.next = 72;
+                              _ctx.next = 83;
                               break;
                             }
                             {
@@ -5133,11 +5184,11 @@
                               parsed.pathname = effect.resolvedHref;
                               url = (0, _utils).formatWithValidation(parsed);
                             }
-                            _ctx.next = 84;
+                            _ctx.next = 95;
                             break;
-                          case 72:
+                          case 83:
                             if (!(effect.type === "redirect" && effect.newAs)) {
-                              _ctx.next = 76;
+                              _ctx.next = 87;
                               break;
                             }
                             return _ctx.abrupt(
@@ -5149,13 +5200,13 @@
                                 options
                               )
                             );
-                          case 76:
+                          case 87:
                             if (
                               !(
                                 effect.type === "redirect" && effect.destination
                               )
                             ) {
-                              _ctx.next = 81;
+                              _ctx.next = 92;
                               break;
                             }
                             window.location.href = effect.destination;
@@ -5163,14 +5214,14 @@
                               "return",
                               new Promise(function() {})
                             );
-                          case 81:
+                          case 92:
                             if (
                               !(
                                 effect.type === "refresh" &&
                                 as !== window.location.pathname
                               )
                             ) {
-                              _ctx.next = 84;
+                              _ctx.next = 95;
                               break;
                             }
                             window.location.href = as;
@@ -5178,13 +5229,13 @@
                               "return",
                               new Promise(function() {})
                             );
-                          case 84:
+                          case 95:
                             route = (0,
                             _normalizeTrailingSlash).removePathTrailingSlash(
                               pathname
                             );
                             if (!(0, _isDynamic).isDynamicRoute(route)) {
-                              _ctx.next = 100;
+                              _ctx.next = 111;
                               break;
                             }
                             parsedAs1 = (0, _parseRelativeUrl).parseRelativeUrl(
@@ -5205,7 +5256,7 @@
                                 (shouldInterpolate && !interpolatedAs.result)
                               )
                             ) {
-                              _ctx.next = 99;
+                              _ctx.next = 110;
                               break;
                             }
                             missingParams = Object.keys(
@@ -5214,7 +5265,7 @@
                               return !query[param];
                             });
                             if (!(missingParams.length > 0)) {
-                              _ctx.next = 97;
+                              _ctx.next = 108;
                               break;
                             }
                             if (false) {
@@ -5242,10 +5293,10 @@
                                     : "incompatible-href-as"
                                 )
                             );
-                          case 97:
-                            _ctx.next = 100;
+                          case 108:
+                            _ctx.next = 111;
                             break;
-                          case 99:
+                          case 110:
                             if (shouldInterpolate) {
                               as = (0, _utils).formatWithValidation(
                                 Object.assign({}, parsedAs1, {
@@ -5260,14 +5311,14 @@
                               // Merge params into `query`, overwriting any specified in search
                               Object.assign(query, routeMatch);
                             }
-                          case 100:
+                          case 111:
                             Router.events.emit(
                               "routeChangeStart",
                               as,
                               routeProps
                             );
-                            _ctx.prev = 101;
-                            _ctx.next = 105;
+                            _ctx.prev = 112;
+                            _ctx.next = 116;
                             return _this.getRouteInfo(
                               route,
                               pathname,
@@ -5276,20 +5327,20 @@
                               resolvedAs,
                               routeProps
                             );
-                          case 105:
+                          case 116:
                             routeInfo = _ctx.sent;
                             (error = routeInfo.error),
                               (props = routeInfo.props),
                               (__N_SSG = routeInfo.__N_SSG),
                               (__N_SSP = routeInfo.__N_SSP);
                             if (!((__N_SSG || __N_SSP) && props)) {
-                              _ctx.next = 132;
+                              _ctx.next = 143;
                               break;
                             }
                             if (
                               !(props.pageProps && props.pageProps.__N_REDIRECT)
                             ) {
-                              _ctx.next = 117;
+                              _ctx.next = 128;
                               break;
                             }
                             destination = props.pageProps.__N_REDIRECT;
@@ -5299,7 +5350,7 @@
                                 props.pageProps.__N_REDIRECT_BASE_PATH !== false
                               )
                             ) {
-                              _ctx.next = 115;
+                              _ctx.next = 126;
                               break;
                             }
                             parsedHref = (0,
@@ -5319,31 +5370,31 @@
                               "return",
                               _this.change(method, newUrl, newAs, options)
                             );
-                          case 115:
+                          case 126:
                             window.location.href = destination;
                             return _ctx.abrupt(
                               "return",
                               new Promise(function() {})
                             );
-                          case 117:
+                          case 128:
                             _this.isPreview = !!props.__N_PREVIEW;
                             if (!(props.notFound === SSG_DATA_NOT_FOUND)) {
-                              _ctx.next = 132;
+                              _ctx.next = 143;
                               break;
                             }
-                            _ctx.prev = 120;
-                            _ctx.next = 123;
+                            _ctx.prev = 131;
+                            _ctx.next = 134;
                             return _this.fetchComponent("/404");
-                          case 123:
+                          case 134:
                             notFoundRoute = "/404";
-                            _ctx.next = 129;
+                            _ctx.next = 140;
                             break;
-                          case 126:
-                            _ctx.prev = 126;
-                            _ctx.t3 = _ctx["catch"](120);
+                          case 137:
+                            _ctx.prev = 137;
+                            _ctx.t3 = _ctx["catch"](131);
                             notFoundRoute = "/_error";
-                          case 129:
-                            _ctx.next = 131;
+                          case 140:
+                            _ctx.next = 142;
                             return _this.getRouteInfo(
                               notFoundRoute,
                               notFoundRoute,
@@ -5354,9 +5405,9 @@
                                 shallow: false
                               }
                             );
-                          case 131:
+                          case 142:
                             routeInfo = _ctx.sent;
-                          case 132:
+                          case 143:
                             Router.events.emit(
                               "beforeHistoryChange",
                               as,
@@ -5394,7 +5445,7 @@
                                   y: 0
                                 }
                               : null;
-                            _ctx.next = 141;
+                            _ctx.next = 152;
                             return _this
                               .set(
                                 route,
@@ -5410,9 +5461,9 @@
                                 if (e.cancelled) error = error || e;
                                 else throw e;
                               });
-                          case 141:
+                          case 152:
                             if (!error) {
-                              _ctx.next = 144;
+                              _ctx.next = 155;
                               break;
                             }
                             Router.events.emit(
@@ -5422,7 +5473,7 @@
                               routeProps
                             );
                             throw error;
-                          case 144:
+                          case 155:
                             if (false) {
                             }
                             Router.events.emit(
@@ -5431,22 +5482,22 @@
                               routeProps
                             );
                             return _ctx.abrupt("return", true);
-                          case 149:
-                            _ctx.prev = 149;
-                            _ctx.t4 = _ctx["catch"](101);
+                          case 160:
+                            _ctx.prev = 160;
+                            _ctx.t4 = _ctx["catch"](112);
                             if (
                               !(
                                 (0, _isError).default(_ctx.t4) &&
                                 _ctx.t4.cancelled
                               )
                             ) {
-                              _ctx.next = 153;
+                              _ctx.next = 164;
                               break;
                             }
                             return _ctx.abrupt("return", false);
-                          case 153:
+                          case 164:
                             throw _ctx.t4;
-                          case 154:
+                          case 165:
                           case "end":
                             return _ctx.stop();
                         }
@@ -5455,8 +5506,8 @@
                     null,
                     [
                       [38, 50],
-                      [101, 149],
-                      [120, 126]
+                      [112, 160],
+                      [131, 137]
                     ]
                   );
                 })
@@ -5932,7 +5983,7 @@
                           pages = _ctx.sent;
                           resolvedAs = asPath;
                           if (true) {
-                            _ctx.next = 20;
+                            _ctx.next = 22;
                             break;
                           }
                           _ctx.next = 12;
@@ -5951,6 +6002,12 @@
                             },
                             _this.locales
                           );
+                          if (!rewritesResult.externalDest) {
+                            _ctx.next = 18;
+                            break;
+                          }
+                          return _ctx.abrupt("return");
+                        case 18:
                           resolvedAs = delLocale(
                             delBasePath(rewritesResult.asPath),
                             _this.locale
@@ -5965,9 +6022,9 @@
                             parsed.pathname = pathname;
                             url = (0, _utils).formatWithValidation(parsed);
                           }
-                          _ctx.next = 21;
+                          _ctx.next = 23;
                           break;
-                        case 20: {
+                        case 22: {
                           parsed.pathname = resolveDynamicRoute(
                             parsed.pathname,
                             pages
@@ -5978,14 +6035,14 @@
                             url = (0, _utils).formatWithValidation(parsed);
                           }
                         }
-                        case 21:
+                        case 23:
                           if (true) {
-                            _ctx.next = 23;
+                            _ctx.next = 25;
                             break;
                           }
                           return _ctx.abrupt("return");
-                        case 23:
-                          _ctx.next = 25;
+                        case 25:
+                          _ctx.next = 27;
                           return _this._preflightRequest({
                             as: addBasePath(asPath),
                             cache: true,
@@ -5993,7 +6050,7 @@
                             pathname: pathname,
                             query: query
                           });
-                        case 25:
+                        case 27:
                           effects = _ctx.sent;
                           if (effects.type === "rewrite") {
                             parsed.pathname = effects.resolvedHref;
@@ -6010,7 +6067,7 @@
                           _normalizeTrailingSlash).removePathTrailingSlash(
                             pathname
                           );
-                          _ctx.next = 30;
+                          _ctx.next = 32;
                           return Promise.all([
                             _this.pageLoader
                               ._isSsg(route)
@@ -6037,7 +6094,7 @@
                               options.priority ? "loadPage" : "prefetch"
                             ](route)
                           ]);
-                        case 30:
+                        case 32:
                         case "end":
                           return _ctx.stop();
                       }
Diff for index.html
@@ -19,7 +19,7 @@
       defer=""
     ></script>
     <script
-      src="/_next/static/chunks/main-c6fc133fe313f8ea.js"
+      src="/_next/static/chunks/main-2487a9a50a9f7dd4.js"
       defer=""
     ></script>
     <script
Diff for link.html
@@ -19,7 +19,7 @@
       defer=""
     ></script>
     <script
-      src="/_next/static/chunks/main-c6fc133fe313f8ea.js"
+      src="/_next/static/chunks/main-2487a9a50a9f7dd4.js"
       defer=""
     ></script>
     <script
Diff for withRouter.html
@@ -19,7 +19,7 @@
       defer=""
     ></script>
     <script
-      src="/_next/static/chunks/main-c6fc133fe313f8ea.js"
+      src="/_next/static/chunks/main-2487a9a50a9f7dd4.js"
       defer=""
     ></script>
     <script

Please sign in to comment.