Skip to content

Commit

Permalink
v9.5.4-canary.25
Browse files Browse the repository at this point in the history
  • Loading branch information
ijjk committed Oct 7, 2020
1 parent 5d79a8c commit 7108567
Show file tree
Hide file tree
Showing 15 changed files with 20 additions and 20 deletions.
2 changes: 1 addition & 1 deletion lerna.json
Expand Up @@ -17,5 +17,5 @@
"registry": "https://registry.npmjs.org/"
}
},
"version": "9.5.4-canary.24"
"version": "9.5.4-canary.25"
}
2 changes: 1 addition & 1 deletion packages/create-next-app/package.json
@@ -1,6 +1,6 @@
{
"name": "create-next-app",
"version": "9.5.4-canary.24",
"version": "9.5.4-canary.25",
"keywords": [
"react",
"next",
Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-plugin-next/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/eslint-plugin-next",
"version": "9.5.4-canary.24",
"version": "9.5.4-canary.25",
"description": "ESLint plugin for NextJS.",
"main": "lib/index.js",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/next-bundle-analyzer/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/bundle-analyzer",
"version": "9.5.4-canary.24",
"version": "9.5.4-canary.25",
"main": "index.js",
"license": "MIT",
"repository": {
Expand Down
2 changes: 1 addition & 1 deletion packages/next-codemod/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/codemod",
"version": "9.5.4-canary.24",
"version": "9.5.4-canary.25",
"license": "MIT",
"dependencies": {
"chalk": "4.1.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/next-env/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/env",
"version": "9.5.4-canary.24",
"version": "9.5.4-canary.25",
"keywords": [
"react",
"next",
Expand Down
2 changes: 1 addition & 1 deletion packages/next-mdx/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/mdx",
"version": "9.5.4-canary.24",
"version": "9.5.4-canary.25",
"main": "index.js",
"license": "MIT",
"repository": {
Expand Down
2 changes: 1 addition & 1 deletion packages/next-plugin-google-analytics/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/plugin-google-analytics",
"version": "9.5.4-canary.24",
"version": "9.5.4-canary.25",
"repository": {
"url": "vercel/next.js",
"directory": "packages/next-plugin-google-analytics"
Expand Down
2 changes: 1 addition & 1 deletion packages/next-plugin-sentry/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/plugin-sentry",
"version": "9.5.4-canary.24",
"version": "9.5.4-canary.25",
"repository": {
"url": "vercel/next.js",
"directory": "packages/next-plugin-sentry"
Expand Down
2 changes: 1 addition & 1 deletion packages/next-plugin-storybook/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/plugin-storybook",
"version": "9.5.4-canary.24",
"version": "9.5.4-canary.25",
"repository": {
"url": "vercel/next.js",
"directory": "packages/next-plugin-storybook"
Expand Down
2 changes: 1 addition & 1 deletion packages/next-polyfill-module/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/polyfill-module",
"version": "9.5.4-canary.24",
"version": "9.5.4-canary.25",
"description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)",
"main": "dist/polyfill-module.js",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/next-polyfill-nomodule/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/polyfill-nomodule",
"version": "9.5.4-canary.24",
"version": "9.5.4-canary.25",
"description": "A polyfill for non-dead, nomodule browsers.",
"main": "dist/polyfill-nomodule.js",
"license": "MIT",
Expand Down
12 changes: 6 additions & 6 deletions packages/next/package.json
@@ -1,6 +1,6 @@
{
"name": "next",
"version": "9.5.4-canary.24",
"version": "9.5.4-canary.25",
"description": "The React Framework",
"main": "./dist/server/next.js",
"license": "MIT",
Expand Down Expand Up @@ -76,10 +76,10 @@
"@babel/preset-typescript": "7.10.4",
"@babel/runtime": "7.11.2",
"@babel/types": "7.11.5",
"@next/env": "9.5.4-canary.24",
"@next/polyfill-module": "9.5.4-canary.24",
"@next/react-dev-overlay": "9.5.4-canary.24",
"@next/react-refresh-utils": "9.5.4-canary.24",
"@next/env": "9.5.4-canary.25",
"@next/polyfill-module": "9.5.4-canary.25",
"@next/react-dev-overlay": "9.5.4-canary.25",
"@next/react-refresh-utils": "9.5.4-canary.25",
"ast-types": "0.13.2",
"babel-plugin-transform-define": "2.0.0",
"babel-plugin-transform-react-remove-prop-types": "0.4.24",
Expand Down Expand Up @@ -123,7 +123,7 @@
"react-dom": "^16.6.0"
},
"devDependencies": {
"@next/polyfill-nomodule": "9.5.4-canary.24",
"@next/polyfill-nomodule": "9.5.4-canary.25",
"@taskr/clear": "1.1.0",
"@taskr/esnext": "1.1.0",
"@taskr/watch": "1.1.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/react-dev-overlay/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/react-dev-overlay",
"version": "9.5.4-canary.24",
"version": "9.5.4-canary.25",
"description": "A development-only overlay for developing React applications.",
"repository": {
"url": "vercel/next.js",
Expand Down
2 changes: 1 addition & 1 deletion packages/react-refresh-utils/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/react-refresh-utils",
"version": "9.5.4-canary.24",
"version": "9.5.4-canary.25",
"description": "An experimental package providing utilities for React Refresh.",
"repository": {
"url": "vercel/next.js",
Expand Down

1 comment on commit 7108567

@ijjk
Copy link
Member Author

@ijjk ijjk commented on 7108567 Oct 7, 2020

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 Server Mode (Increase detected ⚠️)
General Overall increase ⚠️
vercel/next.js canary v9.5.3 vercel/next.js refs/heads/canary Change
buildDuration 12.8s 12.9s ⚠️ +125ms
nodeModulesSize 63.1 MB 63.2 MB ⚠️ +149 kB
Page Load Tests Overall increase ✓
vercel/next.js canary v9.5.3 vercel/next.js refs/heads/canary Change
/ failed reqs 0 0
/ total time (seconds) 2.332 2.349 ⚠️ +0.02
/ avg req/sec 1072.13 1064.22 ⚠️ -7.91
/error-in-render failed reqs 0 0
/error-in-render total time (seconds) 1.283 1.235 -0.05
/error-in-render avg req/sec 1948.31 2023.6 +75.29
Client Bundles (main, webpack, commons) Overall increase ⚠️
vercel/next.js canary v9.5.3 vercel/next.js refs/heads/canary Change
677f882d2ed8..9ff9.js gzip 10.3 kB 10.9 kB ⚠️ +635 B
framework.HASH.js gzip 39 kB 39 kB
main-b338f5a..3500.js gzip 7.31 kB 7.17 kB -140 B
webpack-e067..f178.js gzip 751 B 751 B
Overall change 57.3 kB 57.8 kB ⚠️ +495 B
Client Bundles (main, webpack, commons) Modern Overall increase ⚠️
vercel/next.js canary v9.5.3 vercel/next.js refs/heads/canary Change
677f882d2ed8..dule.js gzip 6.13 kB 6.77 kB ⚠️ +639 B
framework.HA..dule.js gzip 39 kB 39 kB
main-830c506..dule.js gzip 6.37 kB 6.24 kB -129 B
webpack-07c5..dule.js gzip 751 B 751 B
Overall change 52.2 kB 52.7 kB ⚠️ +510 B
Legacy Client Bundles (polyfills)
vercel/next.js canary v9.5.3 vercel/next.js refs/heads/canary Change
polyfills-4b..e242.js gzip 31 kB 31 kB
Overall change 31 kB 31 kB
Client Pages Overall increase ⚠️
vercel/next.js canary v9.5.3 vercel/next.js refs/heads/canary Change
_app-9a0b9e1..b37e.js gzip 1.28 kB 1.28 kB
_error-ed1b0..8fbd.js gzip 3.44 kB 3.44 kB
hooks-89731c..c609.js gzip 887 B 887 B
index-17468f..5d83.js gzip 227 B 227 B
link-ae98065..267e.js gzip 1.29 kB 1.3 kB ⚠️ +16 B
routerDirect..924c.js gzip 284 B 284 B
withRouter-7..c13d.js gzip 284 B 284 B
Overall change 7.69 kB 7.71 kB ⚠️ +16 B
Client Pages Modern Overall increase ⚠️
vercel/next.js canary v9.5.3 vercel/next.js refs/heads/canary Change
_app-75d3a82..dule.js gzip 625 B 625 B
_error-4469a..dule.js gzip 2.29 kB 2.29 kB
hooks-cbf13f..dule.js gzip 387 B 387 B
index-b9a643..dule.js gzip 226 B 226 B
link-cb244c4..dule.js gzip 1.26 kB 1.26 kB ⚠️ +5 B
routerDirect..dule.js gzip 284 B 284 B
withRouter-f..dule.js gzip 282 B 282 B
Overall change 5.35 kB 5.36 kB ⚠️ +5 B
Client Build Manifests Overall decrease ✓
vercel/next.js canary v9.5.3 vercel/next.js refs/heads/canary Change
_buildManifest.js gzip 323 B 322 B -1 B
_buildManife..dule.js gzip 329 B 329 B
Overall change 652 B 651 B -1 B
Rendered Page Sizes Overall increase ⚠️
vercel/next.js canary v9.5.3 vercel/next.js refs/heads/canary Change
index.html gzip 971 B 1 kB ⚠️ +32 B
link.html gzip 976 B 1.01 kB ⚠️ +32 B
withRouter.html gzip 965 B 995 B ⚠️ +30 B
Overall change 2.91 kB 3.01 kB ⚠️ +94 B

Diffs

Diff for _buildManifest.js
@@ -7,7 +7,7 @@ self.__BUILD_MANIFEST = {
   "/hooks": [
     "static\u002Fchunks\u002Fpages\u002Fhooks-8001dc76075832ee8949.js"
   ],
-  "/link": ["static\u002Fchunks\u002Fpages\u002Flink-46fd48c0b73b2f2d75a4.js"],
+  "/link": ["static\u002Fchunks\u002Fpages\u002Flink-32658e75d53af2daa2e0.js"],
   "/routerDirect": [
     "static\u002Fchunks\u002Fpages\u002FrouterDirect-2e9bfd441bd88cd3382e.js"
   ],
Diff for _buildManifest.module.js
@@ -10,7 +10,7 @@ self.__BUILD_MANIFEST = {
     "static\u002Fchunks\u002Fpages\u002Fhooks-56fa58a6f0993d7d36d7.module.js"
   ],
   "/link": [
-    "static\u002Fchunks\u002Fpages\u002Flink-e2f1e0e7ed02569239da.module.js"
+    "static\u002Fchunks\u002Fpages\u002Flink-cb038f0ac2e648ce4861.module.js"
   ],
   "/routerDirect": [
     "static\u002Fchunks\u002Fpages\u002FrouterDirect-368af3dfef3c9cd99dc3.module.js"
Diff for link-46fd48c..b2f2d75a4.js
@@ -216,12 +216,16 @@ _N_E = (window["webpackJsonp_N_E"] = window["webpackJsonp_N_E"] || []).push([
 
         var _react$default$useMem = _react["default"].useMemo(
             function() {
-              var resolvedHref = (0, _router.resolveHref)(pathname, props.href);
+              var _ref = (0, _router.resolveHref)(pathname, props.href, true),
+                _ref2 = _slicedToArray(_ref, 2),
+                resolvedHref = _ref2[0],
+                resolvedAs = _ref2[1];
+
               return {
                 href: resolvedHref,
                 as: props.as
                   ? (0, _router.resolveHref)(pathname, props.as)
-                  : resolvedHref
+                  : resolvedAs || resolvedHref
               };
             },
             [pathname, props.href, props.as]
Diff for link-e2f1e0e..da.module.js
@@ -207,12 +207,16 @@
         var pathname = (router && router.pathname) || "/";
 
         var { href, as } = _react.default.useMemo(() => {
-          var resolvedHref = (0, _router.resolveHref)(pathname, props.href);
+          var [resolvedHref, resolvedAs] = (0, _router.resolveHref)(
+            pathname,
+            props.href,
+            true
+          );
           return {
             href: resolvedHref,
             as: props.as
               ? (0, _router.resolveHref)(pathname, props.as)
-              : resolvedHref
+              : resolvedAs || resolvedHref
           };
         }, [pathname, props.href, props.as]);
Diff for 677f882d2ed8..7000fca82.js
@@ -145,6 +145,18 @@
         return query;
       }
 
+      function stringifyUrlQueryParam(param) {
+        if (
+          typeof param === "string" ||
+          (typeof param === "number" && !isNaN(param)) ||
+          typeof param === "boolean"
+        ) {
+          return String(param);
+        } else {
+          return "";
+        }
+      }
+
       function urlQueryToSearchParams(urlQuery) {
         var result = new URLSearchParams();
         Object.entries(urlQuery).forEach(function(_ref) {
@@ -154,10 +166,10 @@
 
           if (Array.isArray(value)) {
             value.forEach(function(item) {
-              return result.append(key, item);
+              return result.append(key, stringifyUrlQueryParam(item));
             });
           } else {
-            result.set(key, value);
+            result.set(key, stringifyUrlQueryParam(value));
           }
         });
         return result;
@@ -683,6 +695,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
       exports.addBasePath = addBasePath;
       exports.delBasePath = delBasePath;
       exports.isLocalURL = isLocalURL;
+      exports.interpolateAs = interpolateAs;
       exports.resolveHref = resolveHref;
       exports.markLoadingError = markLoadingError;
       exports["default"] = void 0;
@@ -709,6 +722,10 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
 
       var _routeRegex = __webpack_require__("YTqd");
 
+      var _escapePathDelimiters = _interopRequireDefault(
+        __webpack_require__("fcRV")
+      );
+
       function _interopRequireDefault(obj) {
         return obj && obj.__esModule
           ? obj
@@ -761,12 +778,75 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
           return false;
         }
       }
+
+      function interpolateAs(route, asPathname, query) {
+        var interpolatedRoute = "";
+        var dynamicRegex = (0, _routeRegex.getRouteRegex)(route);
+        var dynamicGroups = dynamicRegex.groups;
+        var dynamicMatches = // Try to match the dynamic route against the asPath
+          (asPathname !== route
+            ? (0, _routeMatcher.getRouteMatcher)(dynamicRegex)(asPathname)
+            : "") || // Fall back to reading the values from the href
+          // TODO: should this take priority; also need to change in the router.
+          query;
+        interpolatedRoute = route;
+        var params = Object.keys(dynamicGroups);
+
+        if (
+          !params.every(function(param) {
+            var value = dynamicMatches[param] || "";
+            var _dynamicGroups$param = dynamicGroups[param],
+              repeat = _dynamicGroups$param.repeat,
+              optional = _dynamicGroups$param.optional; // support single-level catch-all
+            // TODO: more robust handling for user-error (passing `/`)
+
+            var replaced = "[".concat(repeat ? "..." : "").concat(param, "]");
+
+            if (optional) {
+              replaced = ""
+                .concat(!value ? "/" : "", "[")
+                .concat(replaced, "]");
+            }
+
+            if (repeat && !Array.isArray(value)) value = [value];
+            return (
+              (optional || param in dynamicMatches) && // Interpolate group into data URL if present
+              (interpolatedRoute =
+                interpolatedRoute.replace(
+                  replaced,
+                  repeat
+                    ? value.map(_escapePathDelimiters["default"]).join("/")
+                    : (0, _escapePathDelimiters["default"])(value)
+                ) || "/")
+            );
+          })
+        ) {
+          interpolatedRoute = ""; // did not satisfy all requirements
+          // n.b. We ignore this error because we handle warning for this case in
+          // development in the `<Link>` component directly.
+        }
+
+        return {
+          params: params,
+          result: interpolatedRoute
+        };
+      }
+
+      function omitParmsFromQuery(query, params) {
+        var filteredQuery = {};
+        Object.keys(query).forEach(function(key) {
+          if (!params.includes(key)) {
+            filteredQuery[key] = query[key];
+          }
+        });
+        return filteredQuery;
+      }
       /**
        * Resolves a given hyperlink with a certain router state (basePath not included).
        * Preserves absolute urls.
        */
 
-      function resolveHref(currentPath, href) {
+      function resolveHref(currentPath, href, resolveAs) {
         // we use a dummy base url for relative urls
         var base = new URL(currentPath, "http://n");
         var urlAsString =
@@ -779,13 +859,44 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
           finalUrl.pathname = (0,
           _normalizeTrailingSlash.normalizePathTrailingSlash)(
             finalUrl.pathname
-          ); // if the origin didn't change, it means we received a relative href
+          );
+          var interpolatedAs = "";
 
-          return finalUrl.origin === base.origin
-            ? finalUrl.href.slice(finalUrl.origin.length)
-            : finalUrl.href;
+          if (
+            (0, _isDynamic.isDynamicRoute)(finalUrl.pathname) &&
+            finalUrl.searchParams &&
+            resolveAs
+          ) {
+            var query = (0, _querystring.searchParamsToUrlQuery)(
+              finalUrl.searchParams
+            );
+
+            var _interpolateAs = interpolateAs(
+                finalUrl.pathname,
+                finalUrl.pathname,
+                query
+              ),
+              result = _interpolateAs.result,
+              params = _interpolateAs.params;
+
+            if (result) {
+              interpolatedAs = (0, _utils.formatWithValidation)({
+                pathname: result,
+                hash: finalUrl.hash,
+                query: omitParmsFromQuery(query, params)
+              });
+            }
+          } // if the origin didn't change, it means we received a relative href
+
+          var resolvedHref =
+            finalUrl.origin === base.origin
+              ? finalUrl.href.slice(finalUrl.origin.length)
+              : finalUrl.href;
+          return resolveAs
+            ? [resolvedHref, interpolatedAs || resolvedHref]
+            : resolvedHref;
         } catch (_) {
-          return urlAsString;
+          return resolveAs ? [urlAsString] : urlAsString;
         }
       }
 
@@ -1104,19 +1215,26 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
                     parsed,
                     _parsed,
                     pathname,
-                    searchParams,
                     query,
                     route,
                     _options$shallow,
                     shallow,
                     resolvedAs,
-                    _ref3,
+                    potentialHref,
+                    parsedAs,
                     asPathname,
                     routeRegex,
                     routeMatch,
+                    shouldInterpolate,
+                    interpolatedAs,
                     missingParams,
                     routeInfo,
                     error,
+                    props,
+                    __N_SSG,
+                    __N_SSP,
+                    destination,
+                    parsedHref,
                     appComp;
 
                   return _regeneratorRuntime.wrap(
@@ -1185,17 +1303,13 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
                             );
                             (_parsed = parsed),
                               (pathname = _parsed.pathname),
-                              (searchParams = _parsed.searchParams);
+                              (query = _parsed.query);
                             parsed = this._resolveHref(parsed, pages);
 
                             if (parsed.pathname !== pathname) {
                               pathname = parsed.pathname;
                               url = (0, _utils.formatWithValidation)(parsed);
-                            }
-
-                            query = (0, _querystring.searchParamsToUrlQuery)(
-                              searchParams
-                            ); // url and as should always be prefixed with basePath by this
+                            } // url and as should always be prefixed with basePath by this
                             // point by either next/link or router.push/replace so strip the
                             // basePath from the pathname to match the pages dir 1-to-1
 
@@ -1233,21 +1347,30 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
                             resolvedAs = delBasePath(resolvedAs);
 
                             if (!(0, _isDynamic.isDynamicRoute)(route)) {
-                              _context.next = 47;
+                              _context.next = 49;
                               break;
                             }
 
-                            (_ref3 = (0, _parseRelativeUrl.parseRelativeUrl)(
+                            parsedAs = (0, _parseRelativeUrl.parseRelativeUrl)(
                               resolvedAs
-                            )),
-                              (asPathname = _ref3.pathname);
+                            );
+                            asPathname = parsedAs.pathname;
                             routeRegex = (0, _routeRegex.getRouteRegex)(route);
                             routeMatch = (0, _routeMatcher.getRouteMatcher)(
                               routeRegex
                             )(asPathname);
+                            shouldInterpolate = route === asPathname;
+                            interpolatedAs = shouldInterpolate
+                              ? interpolateAs(route, asPathname, query)
+                              : {};
 
-                            if (routeMatch) {
-                              _context.next = 46;
+                            if (
+                              !(
+                                !routeMatch ||
+                                (shouldInterpolate && !interpolatedAs.result)
+                              )
+                            ) {
+                              _context.next = 48;
                               break;
                             }
 
@@ -1258,7 +1381,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
                             });
 
                             if (!(missingParams.length > 0)) {
-                              _context.next = 44;
+                              _context.next = 46;
                               break;
                             }
 
@@ -1266,27 +1389,53 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
                             }
 
                             throw new Error(
-                              "The provided `as` value ("
-                                .concat(
-                                  asPathname,
-                                  ") is incompatible with the `href` value ("
+                              (shouldInterpolate
+                                ? "The provided `href` ("
+                                    .concat(
+                                      url,
+                                      ") value is missing query values ("
+                                    )
+                                    .concat(
+                                      missingParams.join(", "),
+                                      ") to be interpolated properly. "
+                                    )
+                                : "The provided `as` value ("
+                                    .concat(
+                                      asPathname,
+                                      ") is incompatible with the `href` value ("
+                                    )
+                                    .concat(route, "). ")) +
+                                "Read more: https://err.sh/vercel/next.js/".concat(
+                                  shouldInterpolate
+                                    ? "href-interpolation-failed"
+                                    : "incompatible-href-as"
                                 )
-                                .concat(route, "). ") +
-                                "Read more: https://err.sh/vercel/next.js/incompatible-href-as"
                             );
 
-                          case 44:
-                            _context.next = 47;
+                          case 46:
+                            _context.next = 49;
                             break;
 
-                          case 46:
-                            // Merge params into `query`, overwriting any specified in search
-                            Object.assign(query, routeMatch);
+                          case 48:
+                            if (shouldInterpolate) {
+                              as = (0, _utils.formatWithValidation)(
+                                Object.assign({}, parsedAs, {
+                                  pathname: interpolatedAs.result,
+                                  query: omitParmsFromQuery(
+                                    query,
+                                    interpolatedAs.params
+                                  )
+                                })
+                              );
+                            } else {
+                              // Merge params into `query`, overwriting any specified in search
+                              Object.assign(query, routeMatch);
+                            }
 
-                          case 47:
+                          case 49:
                             Router.events.emit("routeChangeStart", as);
-                            _context.prev = 48;
-                            _context.next = 51;
+                            _context.prev = 50;
+                            _context.next = 53;
                             return this.getRouteInfo(
                               route,
                               pathname,
@@ -1295,16 +1444,69 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
                               shallow
                             );
 
-                          case 51:
+                          case 53:
                             routeInfo = _context.sent;
-                            error = routeInfo.error;
+                            (error = routeInfo.error),
+                              (props = routeInfo.props),
+                              (__N_SSG = routeInfo.__N_SSG),
+                              (__N_SSP = routeInfo.__N_SSP); // handle redirect on client-transition
+
+                            if (
+                              !(
+                                (__N_SSG || __N_SSP) &&
+                                props &&
+                                props.pageProps &&
+                                props.pageProps.__N_REDIRECT
+                              )
+                            ) {
+                              _context.next = 64;
+                              break;
+                            }
+
+                            destination = props.pageProps.__N_REDIRECT; // check if destination is internal (resolves to a page) and attempt
+                            // client-navigation if it is falling back to hard navigation if
+                            // it's not
+
+                            if (!destination.startsWith("/")) {
+                              _context.next = 62;
+                              break;
+                            }
+
+                            parsedHref = (0,
+                            _parseRelativeUrl.parseRelativeUrl)(destination);
+
+                            this._resolveHref(parsedHref, pages);
+
+                            if (!pages.includes(parsedHref.pathname)) {
+                              _context.next = 62;
+                              break;
+                            }
+
+                            return _context.abrupt(
+                              "return",
+                              this.change(
+                                "replaceState",
+                                destination,
+                                destination,
+                                options
+                              )
+                            );
+
+                          case 62:
+                            window.location.href = destination;
+                            return _context.abrupt(
+                              "return",
+                              new Promise(function() {})
+                            );
+
+                          case 64:
                             Router.events.emit("beforeHistoryChange", as);
                             this.changeState(method, url, as, options);
 
                             if (false) {
                             }
 
-                            _context.next = 58;
+                            _context.next = 69;
                             return this.set(
                               route,
                               pathname,
@@ -1316,9 +1518,9 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
                               else throw e;
                             });
 
-                          case 58:
+                          case 69:
                             if (!error) {
-                              _context.next = 61;
+                              _context.next = 72;
                               break;
                             }
 
@@ -1329,28 +1531,28 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
                             );
                             throw error;
 
-                          case 61:
+                          case 72:
                             if (false) {
                             }
 
                             Router.events.emit("routeChangeComplete", as);
                             return _context.abrupt("return", true);
 
-                          case 66:
-                            _context.prev = 66;
-                            _context.t0 = _context["catch"](48);
+                          case 77:
+                            _context.prev = 77;
+                            _context.t0 = _context["catch"](50);
 
                             if (!_context.t0.cancelled) {
-                              _context.next = 70;
+                              _context.next = 81;
                               break;
                             }
 
                             return _context.abrupt("return", false);
 
-                          case 70:
+                          case 81:
                             throw _context.t0;
 
-                          case 71:
+                          case 82:
                           case "end":
                             return _context.stop();
                         }
@@ -1358,7 +1560,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
                     },
                     _callee,
                     this,
-                    [[48, 66]]
+                    [[50, 77]]
                   );
                 })
               );
@@ -1784,9 +1986,16 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
           {
             key: "_resolveHref",
             value: function _resolveHref(parsedHref, pages) {
+              var applyBasePath =
+                arguments.length > 2 && arguments[2] !== undefined
+                  ? arguments[2]
+                  : true;
               var pathname = parsedHref.pathname;
-              var cleanPathname = (0, _denormalizePagePath.denormalizePagePath)(
-                delBasePath(pathname)
+              var cleanPathname = (0,
+              _normalizeTrailingSlash.removePathTrailingSlash)(
+                (0, _denormalizePagePath.denormalizePagePath)(
+                  applyBasePath ? delBasePath(pathname) : pathname
+                )
               );
 
               if (cleanPathname === "/404" || cleanPathname === "/_error") {
@@ -1800,7 +2009,9 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
                     (0, _isDynamic.isDynamicRoute)(page) &&
                     (0, _routeRegex.getRouteRegex)(page).re.test(cleanPathname)
                   ) {
-                    parsedHref.pathname = addBasePath(page);
+                    parsedHref.pathname = applyBasePath
+                      ? addBasePath(page)
+                      : page;
                     return true;
                   }
                 });
@@ -2060,6 +2271,21 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
       /***/
     },
 
+    /***/ fcRV: /***/ function(module, exports, __webpack_require__) {
+      "use strict";
+
+      exports.__esModule = true;
+      exports["default"] = escapePathDelimiters; // escape delimiters used by path-to-regexp
+
+      function escapePathDelimiters(segment) {
+        return segment.replace(/[/#?]/g, function(_char) {
+          return encodeURIComponent(_char);
+        });
+      }
+
+      /***/
+    },
+
     /***/ "g/15": /***/ function(module, exports, __webpack_require__) {
       "use strict";
 
@@ -2141,8 +2367,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
                     }
 
                     if (
-                      !((_App$prototype = App.prototype) === null ||
-                      _App$prototype === void 0
+                      !((_App$prototype = App.prototype) == null
                         ? void 0
                         : _App$prototype.getInitialProps)
                     ) {
@@ -2317,6 +2542,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
 
       var _utils = __webpack_require__("g/15");
 
+      var _querystring = __webpack_require__("3WeD");
+
       var DUMMY_BASE = new URL(
         false ? undefined : (0, _utils.getLocationOrigin)()
       );
@@ -2348,7 +2575,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
 
         return {
           pathname: pathname,
-          searchParams: searchParams,
+          query: (0, _querystring.searchParamsToUrlQuery)(searchParams),
           search: search,
           hash: hash,
           href: href.slice(DUMMY_BASE.origin.length)
Diff for 677f882d2ed8..87.module.js
@@ -143,15 +143,29 @@
         return query;
       }
 
+      function stringifyUrlQueryParam(param) {
+        if (
+          typeof param === "string" ||
+          (typeof param === "number" && !isNaN(param)) ||
+          typeof param === "boolean"
+        ) {
+          return String(param);
+        } else {
+          return "";
+        }
+      }
+
       function urlQueryToSearchParams(urlQuery) {
         var result = new URLSearchParams();
         Object.entries(urlQuery).forEach(_ref => {
           var [key, value] = _ref;
 
           if (Array.isArray(value)) {
-            value.forEach(item => result.append(key, item));
+            value.forEach(item =>
+              result.append(key, stringifyUrlQueryParam(item))
+            );
           } else {
-            result.set(key, value);
+            result.set(key, stringifyUrlQueryParam(value));
           }
         });
         return result;
@@ -542,6 +556,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
       exports.addBasePath = addBasePath;
       exports.delBasePath = delBasePath;
       exports.isLocalURL = isLocalURL;
+      exports.interpolateAs = interpolateAs;
       exports.resolveHref = resolveHref;
       exports.markLoadingError = markLoadingError;
       exports.default = void 0;
@@ -568,6 +583,10 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
 
       var _routeRegex = __webpack_require__("YTqd");
 
+      var _escapePathDelimiters = _interopRequireDefault(
+        __webpack_require__("fcRV")
+      );
+
       function _interopRequireDefault(obj) {
         return obj && obj.__esModule
           ? obj
@@ -620,12 +639,73 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
           return false;
         }
       }
+
+      function interpolateAs(route, asPathname, query) {
+        var interpolatedRoute = "";
+        var dynamicRegex = (0, _routeRegex.getRouteRegex)(route);
+        var dynamicGroups = dynamicRegex.groups;
+        var dynamicMatches = // Try to match the dynamic route against the asPath
+          (asPathname !== route
+            ? (0, _routeMatcher.getRouteMatcher)(dynamicRegex)(asPathname)
+            : "") || // Fall back to reading the values from the href
+          // TODO: should this take priority; also need to change in the router.
+          query;
+        interpolatedRoute = route;
+        var params = Object.keys(dynamicGroups);
+
+        if (
+          !params.every(param => {
+            var value = dynamicMatches[param] || "";
+            var { repeat, optional } = dynamicGroups[param]; // support single-level catch-all
+            // TODO: more robust handling for user-error (passing `/`)
+
+            var replaced = "[".concat(repeat ? "..." : "").concat(param, "]");
+
+            if (optional) {
+              replaced = ""
+                .concat(!value ? "/" : "", "[")
+                .concat(replaced, "]");
+            }
+
+            if (repeat && !Array.isArray(value)) value = [value];
+            return (
+              (optional || param in dynamicMatches) && // Interpolate group into data URL if present
+              (interpolatedRoute =
+                interpolatedRoute.replace(
+                  replaced,
+                  repeat
+                    ? value.map(_escapePathDelimiters.default).join("/")
+                    : (0, _escapePathDelimiters.default)(value)
+                ) || "/")
+            );
+          })
+        ) {
+          interpolatedRoute = ""; // did not satisfy all requirements
+          // n.b. We ignore this error because we handle warning for this case in
+          // development in the `<Link>` component directly.
+        }
+
+        return {
+          params,
+          result: interpolatedRoute
+        };
+      }
+
+      function omitParmsFromQuery(query, params) {
+        var filteredQuery = {};
+        Object.keys(query).forEach(key => {
+          if (!params.includes(key)) {
+            filteredQuery[key] = query[key];
+          }
+        });
+        return filteredQuery;
+      }
       /**
        * Resolves a given hyperlink with a certain router state (basePath not included).
        * Preserves absolute urls.
        */
 
-      function resolveHref(currentPath, href) {
+      function resolveHref(currentPath, href, resolveAs) {
         // we use a dummy base url for relative urls
         var base = new URL(currentPath, "http://n");
         var urlAsString =
@@ -638,13 +718,41 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
           finalUrl.pathname = (0,
           _normalizeTrailingSlash.normalizePathTrailingSlash)(
             finalUrl.pathname
-          ); // if the origin didn't change, it means we received a relative href
+          );
+          var interpolatedAs = "";
+
+          if (
+            (0, _isDynamic.isDynamicRoute)(finalUrl.pathname) &&
+            finalUrl.searchParams &&
+            resolveAs
+          ) {
+            var query = (0, _querystring.searchParamsToUrlQuery)(
+              finalUrl.searchParams
+            );
+            var { result, params } = interpolateAs(
+              finalUrl.pathname,
+              finalUrl.pathname,
+              query
+            );
 
-          return finalUrl.origin === base.origin
-            ? finalUrl.href.slice(finalUrl.origin.length)
-            : finalUrl.href;
+            if (result) {
+              interpolatedAs = (0, _utils.formatWithValidation)({
+                pathname: result,
+                hash: finalUrl.hash,
+                query: omitParmsFromQuery(query, params)
+              });
+            }
+          } // if the origin didn't change, it means we received a relative href
+
+          var resolvedHref =
+            finalUrl.origin === base.origin
+              ? finalUrl.href.slice(finalUrl.origin.length)
+              : finalUrl.href;
+          return resolveAs
+            ? [resolvedHref, interpolatedAs || resolvedHref]
+            : resolvedHref;
         } catch (_) {
-          return urlAsString;
+          return resolveAs ? [urlAsString] : urlAsString;
         }
       }
 
@@ -959,15 +1067,13 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
           var { __rewrites: rewrites } = await this.pageLoader
             .promisedBuildManifest;
           var parsed = (0, _parseRelativeUrl.parseRelativeUrl)(url);
-          var { pathname, searchParams } = parsed;
+          var { pathname, query } = parsed;
           parsed = this._resolveHref(parsed, pages);
 
           if (parsed.pathname !== pathname) {
             pathname = parsed.pathname;
             url = (0, _utils.formatWithValidation)(parsed);
-          }
-
-          var query = (0, _querystring.searchParamsToUrlQuery)(searchParams); // url and as should always be prefixed with basePath by this
+          } // url and as should always be prefixed with basePath by this
           // point by either next/link or router.push/replace so strip the
           // basePath from the pathname to match the pages dir 1-to-1
 
@@ -994,19 +1100,24 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
           var resolvedAs = as;
 
           if (false) {
+            var potentialHref;
           }
 
           resolvedAs = delBasePath(resolvedAs);
 
           if ((0, _isDynamic.isDynamicRoute)(route)) {
-            var { pathname: asPathname } = (0,
-            _parseRelativeUrl.parseRelativeUrl)(resolvedAs);
+            var parsedAs = (0, _parseRelativeUrl.parseRelativeUrl)(resolvedAs);
+            var asPathname = parsedAs.pathname;
             var routeRegex = (0, _routeRegex.getRouteRegex)(route);
             var routeMatch = (0, _routeMatcher.getRouteMatcher)(routeRegex)(
               asPathname
             );
+            var shouldInterpolate = route === asPathname;
+            var interpolatedAs = shouldInterpolate
+              ? interpolateAs(route, asPathname, query)
+              : {};
 
-            if (!routeMatch) {
+            if (!routeMatch || (shouldInterpolate && !interpolatedAs.result)) {
               var missingParams = Object.keys(routeRegex.groups).filter(
                 param => !query[param]
               );
@@ -1016,15 +1127,33 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
                 }
 
                 throw new Error(
-                  "The provided `as` value ("
-                    .concat(
-                      asPathname,
-                      ") is incompatible with the `href` value ("
+                  (shouldInterpolate
+                    ? "The provided `href` ("
+                        .concat(url, ") value is missing query values (")
+                        .concat(
+                          missingParams.join(", "),
+                          ") to be interpolated properly. "
+                        )
+                    : "The provided `as` value ("
+                        .concat(
+                          asPathname,
+                          ") is incompatible with the `href` value ("
+                        )
+                        .concat(route, "). ")) +
+                    "Read more: https://err.sh/vercel/next.js/".concat(
+                      shouldInterpolate
+                        ? "href-interpolation-failed"
+                        : "incompatible-href-as"
                     )
-                    .concat(route, "). ") +
-                    "Read more: https://err.sh/vercel/next.js/incompatible-href-as"
                 );
               }
+            } else if (shouldInterpolate) {
+              as = (0, _utils.formatWithValidation)(
+                Object.assign({}, parsedAs, {
+                  pathname: interpolatedAs.result,
+                  query: omitParmsFromQuery(query, interpolatedAs.params)
+                })
+              );
             } else {
               // Merge params into `query`, overwriting any specified in search
               Object.assign(query, routeMatch);
@@ -1041,7 +1170,39 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
               as,
               shallow
             );
-            var { error } = routeInfo;
+            var { error, props, __N_SSG, __N_SSP } = routeInfo; // handle redirect on client-transition
+
+            if (
+              (__N_SSG || __N_SSP) &&
+              props &&
+              props.pageProps &&
+              props.pageProps.__N_REDIRECT
+            ) {
+              var destination = props.pageProps.__N_REDIRECT; // check if destination is internal (resolves to a page) and attempt
+              // client-navigation if it is falling back to hard navigation if
+              // it's not
+
+              if (destination.startsWith("/")) {
+                var parsedHref = (0, _parseRelativeUrl.parseRelativeUrl)(
+                  destination
+                );
+
+                this._resolveHref(parsedHref, pages);
+
+                if (pages.includes(parsedHref.pathname)) {
+                  return this.change(
+                    "replaceState",
+                    destination,
+                    destination,
+                    options
+                  );
+                }
+              }
+
+              window.location.href = destination;
+              return new Promise(() => {});
+            }
+
             Router.events.emit("beforeHistoryChange", as);
             this.changeState(method, url, as, options);
 
@@ -1280,9 +1441,16 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
         }
 
         _resolveHref(parsedHref, pages) {
+          var applyBasePath =
+            arguments.length > 2 && arguments[2] !== undefined
+              ? arguments[2]
+              : true;
           var { pathname } = parsedHref;
-          var cleanPathname = (0, _denormalizePagePath.denormalizePagePath)(
-            delBasePath(pathname)
+          var cleanPathname = (0,
+          _normalizeTrailingSlash.removePathTrailingSlash)(
+            (0, _denormalizePagePath.denormalizePagePath)(
+              applyBasePath ? delBasePath(pathname) : pathname
+            )
           );
 
           if (cleanPathname === "/404" || cleanPathname === "/_error") {
@@ -1296,7 +1464,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
                 (0, _isDynamic.isDynamicRoute)(page) &&
                 (0, _routeRegex.getRouteRegex)(page).re.test(cleanPathname)
               ) {
-                parsedHref.pathname = addBasePath(page);
+                parsedHref.pathname = applyBasePath ? addBasePath(page) : page;
                 return true;
               }
             });
@@ -1443,6 +1611,19 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
       /***/
     },
 
+    /***/ fcRV: /***/ function(module, exports, __webpack_require__) {
+      "use strict";
+
+      exports.__esModule = true;
+      exports.default = escapePathDelimiters; // escape delimiters used by path-to-regexp
+
+      function escapePathDelimiters(segment) {
+        return segment.replace(/[/#?]/g, char => encodeURIComponent(char));
+      }
+
+      /***/
+    },
+
     /***/ "g/15": /***/ function(module, exports, __webpack_require__) {
       "use strict";
 
@@ -1626,6 +1807,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
 
       var _utils = __webpack_require__("g/15");
 
+      var _querystring = __webpack_require__("3WeD");
+
       var DUMMY_BASE = new URL(
         false ? undefined : (0, _utils.getLocationOrigin)()
       );
@@ -1657,7 +1840,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
 
         return {
           pathname,
-          searchParams,
+          query: (0, _querystring.searchParamsToUrlQuery)(searchParams),
           search,
           hash,
           href: href.slice(DUMMY_BASE.origin.length)
Diff for main-0d31828..94.module.js
@@ -1,6 +1,48 @@
 (window["webpackJsonp_N_E"] = window["webpackJsonp_N_E"] || []).push([
   [3],
   {
+    /***/ "0sNQ": /***/ function(module, exports) {
+      "trimStart" in String.prototype ||
+        (String.prototype.trimStart = String.prototype.trimLeft),
+        "trimEnd" in String.prototype ||
+          (String.prototype.trimEnd = String.prototype.trimRight),
+        "description" in Symbol.prototype ||
+          Object.defineProperty(Symbol.prototype, "description", {
+            get: function() {
+              return /\((.+)\)/.exec(this)[1];
+            }
+          }),
+        Array.prototype.flat ||
+          ((Array.prototype.flat = function(t, r) {
+            return (
+              (r = this.concat.apply([], this)),
+              t > 1 && r.some(Array.isArray) ? r.flat(t - 1) : r
+            );
+          }),
+          (Array.prototype.flatMap = function(t, r) {
+            return this.map(t, r).flat();
+          })),
+        Promise.prototype.finally ||
+          (Promise.prototype.finally = function(t) {
+            if ("function" != typeof t) return this.then(t, t);
+            var r = this.constructor || Promise;
+            return this.then(
+              function(o) {
+                return r.resolve(t()).then(function() {
+                  return o;
+                });
+              },
+              function(o) {
+                return r.resolve(t()).then(function() {
+                  throw o;
+                });
+              }
+            );
+          });
+
+      /***/
+    },
+
     /***/ BMP1: /***/ function(module, exports, __webpack_require__) {
       "use strict";
 
@@ -19,6 +61,9 @@
 
       exports.__esModule = true;
       exports.default = initHeadManager;
+
+      var _react = __webpack_require__("q1tI");
+
       var DOMAttributeNames = {
         acceptCharset: "accept-charset",
         className: "class",
@@ -45,54 +90,77 @@
           el.innerHTML = dangerouslySetInnerHTML.__html || "";
         } else if (children) {
           el.textContent =
-            typeof children === "string" ? children : children.join("");
+            typeof children === "string"
+              ? children
+              : Array.isArray(children)
+              ? children.join("")
+              : "";
         }
 
         return el;
       }
 
-      function updateElements(type, components) {
+      function updateElements(elements, components, removeOldTags) {
         var headEl = document.getElementsByTagName("head")[0];
-        var headCountEl = headEl.querySelector("meta[name=next-head-count]");
+        var oldTags = new Set(elements);
+        components.forEach(tag => {
+          if (tag.type === "title") {
+            var title = "";
+
+            if (tag) {
+              var { children } = tag.props;
+              title =
+                typeof children === "string"
+                  ? children
+                  : Array.isArray(children)
+                  ? children.join("")
+                  : "";
+            }
 
-        if (false) {
-        }
+            if (title !== document.title) document.title = title;
+            return;
+          }
 
-        var headCount = Number(headCountEl.content);
-        var oldTags = [];
+          var newTag = reactElementToDOM(tag);
+          var elementIter = elements.values();
 
-        for (
-          var i = 0, j = headCountEl.previousElementSibling;
-          i < headCount;
-          i++, j = j.previousElementSibling
-        ) {
-          if (j.tagName.toLowerCase() === type) {
-            oldTags.push(j);
-          }
-        }
+          while (true) {
+            // Note: We don't use for-of here to avoid needing to polyfill it.
+            var { done, value } = elementIter.next();
 
-        var newTags = components.map(reactElementToDOM).filter(newTag => {
-          for (var k = 0, len = oldTags.length; k < len; k++) {
-            var oldTag = oldTags[k];
+            if (value == null ? void 0 : value.isEqualNode(newTag)) {
+              oldTags.delete(value);
+              return;
+            }
 
-            if (oldTag.isEqualNode(newTag)) {
-              oldTags.splice(k, 1);
-              return false;
+            if (done) {
+              break;
             }
           }
 
-          return true;
+          elements.add(newTag);
+          headEl.appendChild(newTag);
+        });
+        oldTags.forEach(oldTag => {
+          if (removeOldTags) {
+            oldTag.parentNode.removeChild(oldTag);
+          }
+
+          elements.delete(oldTag);
         });
-        oldTags.forEach(t => t.parentNode.removeChild(t));
-        newTags.forEach(t => headEl.insertBefore(t, headCountEl));
-        headCountEl.content = (
-          headCount -
-          oldTags.length +
-          newTags.length
-        ).toString();
       }
 
-      function initHeadManager() {
+      function initHeadManager(initialHeadEntries) {
+        var headEl = document.getElementsByTagName("head")[0];
+        var elements = new Set(headEl.children);
+        updateElements(
+          elements,
+          initialHeadEntries.map(_ref2 => {
+            var [type, props] = _ref2;
+            return /*#__PURE__*/ (0, _react.createElement)(type, props);
+          }),
+          false
+        );
         var updatePromise = null;
         return {
           mountedInstances: new Set(),
@@ -100,25 +168,7 @@
             var promise = (updatePromise = Promise.resolve().then(() => {
               if (promise !== updatePromise) return;
               updatePromise = null;
-              var tags = {};
-              head.forEach(h => {
-                var components = tags[h.type] || [];
-                components.push(h);
-                tags[h.type] = components;
-              });
-              var titleComponent = tags.title ? tags.title[0] : null;
-              var title = "";
-
-              if (titleComponent) {
-                var { children } = titleComponent.props;
-                title =
-                  typeof children === "string" ? children : children.join("");
-              }
-
-              if (title !== document.title) document.title = title;
-              ["meta", "base", "link", "style", "script"].forEach(type => {
-                updateElements(type, tags[type] || []);
-              });
+              updateElements(elements, head, true);
             }));
           }
         };
@@ -171,6 +221,8 @@
         __webpack_require__("284h")
       );
 
+      __webpack_require__("0sNQ");
+
       var _react = _interopRequireDefault(__webpack_require__("q1tI"));
 
       var _reactDom = _interopRequireDefault(__webpack_require__("i8i4"));
@@ -202,15 +254,11 @@
       var _router2 = __webpack_require__("nOHt");
       /* global location */
 
-      if (!("finally" in Promise.prototype)) {
-        Promise.prototype.finally = __webpack_require__("Z577");
-      }
-
       var data = JSON.parse(
         document.getElementById("__NEXT_DATA__").textContent
       );
       window.__NEXT_DATA__ = data;
-      var version = "9.5.3";
+      var version = "9.5.4-canary.25";
       exports.version = version;
       var {
         props: hydrateProps,
@@ -221,7 +269,8 @@
         assetPrefix,
         runtimeConfig,
         dynamicIds,
-        isFallback
+        isFallback,
+        head: initialHeadData
       } = data;
       var prefix = assetPrefix || ""; // With dynamic assetPrefix it's no longer possible to set assetPrefix at the build time
       // So, this is how we do it in the client side at runtime
@@ -254,7 +303,7 @@
 
       window.__NEXT_P = [];
       window.__NEXT_P.push = register;
-      var headManager = (0, _headManager.default)();
+      var headManager = (0, _headManager.default)(initialHeadData);
       var appElement = document.getElementById("__next");
       var lastAppProps;
       var lastRenderReject;
@@ -853,27 +902,6 @@
       /***/
     },
 
-    /***/ Z577: /***/ function(module, exports) {
-      Promise.prototype.finally = function(n) {
-        if ("function" != typeof n) return this.then(n, n);
-        var t = this.constructor || Promise;
-        return this.then(
-          function(r) {
-            return t.resolve(n()).then(function() {
-              return r;
-            });
-          },
-          function(r) {
-            return t.resolve(n()).then(function() {
-              throw r;
-            });
-          }
-        );
-      };
-
-      /***/
-    },
-
     /***/ bGXG: /***/ function(module, exports, __webpack_require__) {
       "use strict";
 
@@ -895,19 +923,6 @@
       /***/
     },
 
-    /***/ fcRV: /***/ function(module, exports, __webpack_require__) {
-      "use strict";
-
-      exports.__esModule = true;
-      exports.default = escapePathDelimiters; // escape delimiters used by path-to-regexp
-
-      function escapePathDelimiters(segment) {
-        return segment.replace(/[/#?]/g, char => encodeURIComponent(char));
-      }
-
-      /***/
-    },
-
     /***/ pVnL: /***/ function(module, exports) {
       function _extends() {
         module.exports = _extends =
@@ -952,14 +967,14 @@
         __webpack_exports__,
         "getFCP",
         function() {
-          return m;
+          return v;
         }
       );
       /* harmony export (binding) */ __webpack_require__.d(
         __webpack_exports__,
         "getFID",
         function() {
-          return v;
+          return f;
         }
       );
       /* harmony export (binding) */ __webpack_require__.d(
@@ -1012,7 +1027,7 @@
         },
         u = function() {
           addEventListener("pagehide", s),
-            addEventListener("unload", function() {});
+            addEventListener("beforeunload", function() {});
         },
         c = function(t) {
           var n =
@@ -1040,19 +1055,20 @@
           };
         },
         p = function(t) {
-          var n =
-              arguments.length > 1 && void 0 !== arguments[1] && arguments[1],
-            e = i("CLS", 0),
-            r = function(t) {
+          var n,
+            e = arguments.length > 1 && void 0 !== arguments[1] && arguments[1],
+            r = i("CLS", 0),
+            o = function(t) {
               t.hadRecentInput ||
-                ((e.value += t.value), e.entries.push(t), s());
+                ((r.value += t.value), r.entries.push(t), n());
             },
-            o = a("layout-shift", r),
-            s = l(t, e, o, n);
-          c(function(t) {
-            var n = t.isUnloading;
-            o && o.takeRecords().map(r), n && (e.isFinal = !0), s();
-          });
+            s = a("layout-shift", o);
+          s &&
+            ((n = l(t, r, s, e)),
+            c(function(t) {
+              var e = t.isUnloading;
+              s.takeRecords().map(o), e && (r.isFinal = !0), n();
+            }));
         },
         d = function() {
           return (
@@ -1069,20 +1085,21 @@
             }
           );
         },
-        m = function(t) {
-          var n = i("FCP"),
-            e = d(),
-            r = a("paint", function(t) {
+        v = function(t) {
+          var n,
+            e = i("FCP"),
+            r = d(),
+            o = a("paint", function(t) {
               "first-contentful-paint" === t.name &&
-                t.startTime < e.timeStamp &&
-                ((n.value = t.startTime),
-                (n.isFinal = !0),
-                n.entries.push(t),
-                o());
-            }),
-            o = l(t, n, r);
+                t.startTime < r.timeStamp &&
+                ((e.value = t.startTime),
+                (e.isFinal = !0),
+                e.entries.push(t),
+                n());
+            });
+          o && (n = l(t, e, o));
         },
-        v = function(t) {
+        f = function(t) {
           var n = i("FID"),
             e = d(),
             r = function(t) {
@@ -1094,30 +1111,30 @@
             },
             o = a("first-input", r),
             s = l(t, n, o);
-          c(function() {
-            o && (o.takeRecords().map(r), o.disconnect());
-          }, !0),
-            o ||
-              (window.perfMetrics &&
-                window.perfMetrics.onFirstInputDelay &&
-                window.perfMetrics.onFirstInputDelay(function(t, i) {
-                  i.timeStamp < e.timeStamp &&
-                    ((n.value = t),
-                    (n.isFinal = !0),
-                    (n.entries = [
-                      {
-                        entryType: "first-input",
-                        name: i.type,
-                        target: i.target,
-                        cancelable: i.cancelable,
-                        startTime: i.timeStamp,
-                        processingStart: i.timeStamp + t
-                      }
-                    ]),
-                    s());
-                }));
+          o
+            ? c(function() {
+                o.takeRecords().map(r), o.disconnect();
+              }, !0)
+            : window.perfMetrics &&
+              window.perfMetrics.onFirstInputDelay &&
+              window.perfMetrics.onFirstInputDelay(function(t, i) {
+                i.timeStamp < e.timeStamp &&
+                  ((n.value = t),
+                  (n.isFinal = !0),
+                  (n.entries = [
+                    {
+                      entryType: "first-input",
+                      name: i.type,
+                      target: i.target,
+                      cancelable: i.cancelable,
+                      startTime: i.timeStamp,
+                      processingStart: i.timeStamp + t
+                    }
+                  ]),
+                  s());
+              });
         },
-        f = function() {
+        m = function() {
           return (
             n ||
               (n = new Promise(function(t) {
@@ -1133,23 +1150,25 @@
           );
         },
         g = function(t) {
-          var n =
-              arguments.length > 1 && void 0 !== arguments[1] && arguments[1],
-            e = i("LCP"),
-            r = d(),
-            o = function(t) {
-              var n = t.startTime;
-              n < r.timeStamp
-                ? ((e.value = n), e.entries.push(t))
-                : (e.isFinal = !0),
-                u();
+          var n,
+            e = arguments.length > 1 && void 0 !== arguments[1] && arguments[1],
+            r = i("LCP"),
+            o = d(),
+            s = function(t) {
+              var e = t.startTime;
+              e < o.timeStamp
+                ? ((r.value = e), r.entries.push(t))
+                : (r.isFinal = !0),
+                n();
             },
-            s = a("largest-contentful-paint", o),
-            u = l(t, e, s, n),
-            p = function() {
-              e.isFinal || (s && s.takeRecords().map(o), (e.isFinal = !0), u());
+            u = a("largest-contentful-paint", s);
+          if (u) {
+            n = l(t, r, u, e);
+            var p = function() {
+              r.isFinal || (u.takeRecords().map(s), (r.isFinal = !0), n());
             };
-          f().then(p), c(p, !0);
+            m().then(p), c(p, !0);
+          }
         },
         h = function(t) {
           var n,
@@ -1214,10 +1233,6 @@
 
       var _router = __webpack_require__("elyg");
 
-      var _escapePathDelimiters = _interopRequireDefault(
-        __webpack_require__("fcRV")
-      );
-
       var _getAssetPathFromRoute = _interopRequireDefault(
         __webpack_require__("Lab5")
       );
@@ -1226,12 +1241,6 @@
 
       var _parseRelativeUrl = __webpack_require__("hS4m");
 
-      var _querystring = __webpack_require__("3WeD");
-
-      var _routeMatcher = __webpack_require__("gguc");
-
-      var _routeRegex = __webpack_require__("YTqd");
-
       var looseToArray = input => [].slice.call(input);
 
       exports.looseToArray = looseToArray;
@@ -1390,9 +1399,8 @@
          */
 
         getDataHref(href, asPath, ssg) {
-          var { pathname: hrefPathname, searchParams, search } = (0,
+          var { pathname: hrefPathname, query, search } = (0,
           _parseRelativeUrl.parseRelativeUrl)(href);
-          var query = (0, _querystring.searchParamsToUrlQuery)(searchParams);
           var { pathname: asPathname } = (0,
           _parseRelativeUrl.parseRelativeUrl)(asPath);
           var route = normalizeRoute(hrefPathname);
@@ -1407,53 +1415,10 @@
             );
           };
 
-          var isDynamic = (0, _isDynamic.isDynamicRoute)(route),
-            interpolatedRoute;
-
-          if (isDynamic) {
-            var dynamicRegex = (0, _routeRegex.getRouteRegex)(route);
-            var dynamicGroups = dynamicRegex.groups;
-            var dynamicMatches = // Try to match the dynamic route against the asPath
-              (0, _routeMatcher.getRouteMatcher)(dynamicRegex)(asPathname) || // Fall back to reading the values from the href
-              // TODO: should this take priority; also need to change in the router.
-              query;
-            interpolatedRoute = route;
-
-            if (
-              !Object.keys(dynamicGroups).every(param => {
-                var value = dynamicMatches[param] || "";
-                var { repeat, optional } = dynamicGroups[param]; // support single-level catch-all
-                // TODO: more robust handling for user-error (passing `/`)
-
-                var replaced = "["
-                  .concat(repeat ? "..." : "")
-                  .concat(param, "]");
-
-                if (optional) {
-                  replaced = ""
-                    .concat(!value ? "/" : "", "[")
-                    .concat(replaced, "]");
-                }
-
-                if (repeat && !Array.isArray(value)) value = [value];
-                return (
-                  (optional || param in dynamicMatches) && // Interpolate group into data URL if present
-                  (interpolatedRoute =
-                    interpolatedRoute.replace(
-                      replaced,
-                      repeat
-                        ? value.map(_escapePathDelimiters.default).join("/")
-                        : (0, _escapePathDelimiters.default)(value)
-                    ) || "/")
-                );
-              })
-            ) {
-              interpolatedRoute = ""; // did not satisfy all requirements
-              // n.b. We ignore this error because we handle warning for this case in
-              // development in the `<Link>` component directly.
-            }
-          }
-
+          var isDynamic = (0, _isDynamic.isDynamicRoute)(route);
+          var interpolatedRoute = isDynamic
+            ? (0, _router.interpolateAs)(hrefPathname, asPathname, query).result
+            : "";
           return isDynamic
             ? interpolatedRoute && getHrefForSlug(interpolatedRoute)
             : getHrefForSlug(route);
Diff for main-58fe85d..fac23ae4b.js
@@ -1,6 +1,48 @@
 _N_E = (window["webpackJsonp_N_E"] = window["webpackJsonp_N_E"] || []).push([
   [3],
   {
+    /***/ "0sNQ": /***/ function(module, exports) {
+      "trimStart" in String.prototype ||
+        (String.prototype.trimStart = String.prototype.trimLeft),
+        "trimEnd" in String.prototype ||
+          (String.prototype.trimEnd = String.prototype.trimRight),
+        "description" in Symbol.prototype ||
+          Object.defineProperty(Symbol.prototype, "description", {
+            get: function() {
+              return /\((.+)\)/.exec(this)[1];
+            }
+          }),
+        Array.prototype.flat ||
+          ((Array.prototype.flat = function(t, r) {
+            return (
+              (r = this.concat.apply([], this)),
+              t > 1 && r.some(Array.isArray) ? r.flat(t - 1) : r
+            );
+          }),
+          (Array.prototype.flatMap = function(t, r) {
+            return this.map(t, r).flat();
+          })),
+        Promise.prototype.finally ||
+          (Promise.prototype.finally = function(t) {
+            if ("function" != typeof t) return this.then(t, t);
+            var r = this.constructor || Promise;
+            return this.then(
+              function(o) {
+                return r.resolve(t()).then(function() {
+                  return o;
+                });
+              },
+              function(o) {
+                return r.resolve(t()).then(function() {
+                  throw o;
+                });
+              }
+            );
+          });
+
+      /***/
+    },
+
     /***/ "7W2i": /***/ function(module, exports, __webpack_require__) {
       var setPrototypeOf = __webpack_require__("SksO");
 
@@ -42,8 +84,13 @@ _N_E = (window["webpackJsonp_N_E"] = window["webpackJsonp_N_E"] || []).push([
     /***/ DqTX: /***/ function(module, exports, __webpack_require__) {
       "use strict";
 
+      var _slicedToArray = __webpack_require__("J4zp");
+
       exports.__esModule = true;
       exports["default"] = initHeadManager;
+
+      var _react = __webpack_require__("q1tI");
+
       var DOMAttributeNames = {
         acceptCharset: "accept-charset",
         className: "class",
@@ -72,60 +119,82 @@ _N_E = (window["webpackJsonp_N_E"] = window["webpackJsonp_N_E"] || []).push([
           el.innerHTML = dangerouslySetInnerHTML.__html || "";
         } else if (children) {
           el.textContent =
-            typeof children === "string" ? children : children.join("");
+            typeof children === "string"
+              ? children
+              : Array.isArray(children)
+              ? children.join("")
+              : "";
         }
 
         return el;
       }
 
-      function updateElements(type, components) {
+      function updateElements(elements, components, removeOldTags) {
         var headEl = document.getElementsByTagName("head")[0];
-        var headCountEl = headEl.querySelector("meta[name=next-head-count]");
+        var oldTags = new Set(elements);
+        components.forEach(function(tag) {
+          if (tag.type === "title") {
+            var title = "";
+
+            if (tag) {
+              var children = tag.props.children;
+              title =
+                typeof children === "string"
+                  ? children
+                  : Array.isArray(children)
+                  ? children.join("")
+                  : "";
+            }
 
-        if (false) {
-        }
+            if (title !== document.title) document.title = title;
+            return;
+          }
 
-        var headCount = Number(headCountEl.content);
-        var oldTags = [];
+          var newTag = reactElementToDOM(tag);
+          var elementIter = elements.values();
 
-        for (
-          var i = 0, j = headCountEl.previousElementSibling;
-          i < headCount;
-          i++, j = j.previousElementSibling
-        ) {
-          if (j.tagName.toLowerCase() === type) {
-            oldTags.push(j);
-          }
-        }
+          while (true) {
+            // Note: We don't use for-of here to avoid needing to polyfill it.
+            var _elementIter$next = elementIter.next(),
+              done = _elementIter$next.done,
+              value = _elementIter$next.value;
 
-        var newTags = components
-          .map(reactElementToDOM)
-          .filter(function(newTag) {
-            for (var k = 0, len = oldTags.length; k < len; k++) {
-              var oldTag = oldTags[k];
+            if (value == null ? void 0 : value.isEqualNode(newTag)) {
+              oldTags["delete"](value);
+              return;
+            }
 
-              if (oldTag.isEqualNode(newTag)) {
-                oldTags.splice(k, 1);
-                return false;
-              }
+            if (done) {
+              break;
             }
+          }
 
-            return true;
-          });
-        oldTags.forEach(function(t) {
-          return t.parentNode.removeChild(t);
+          elements.add(newTag);
+          headEl.appendChild(newTag);
         });
-        newTags.forEach(function(t) {
-          return headEl.insertBefore(t, headCountEl);
+        oldTags.forEach(function(oldTag) {
+          if (removeOldTags) {
+            oldTag.parentNode.removeChild(oldTag);
+          }
+
+          elements["delete"](oldTag);
         });
-        headCountEl.content = (
-          headCount -
-          oldTags.length +
-          newTags.length
-        ).toString();
       }
 
-      function initHeadManager() {
+      function initHeadManager(initialHeadEntries) {
+        var headEl = document.getElementsByTagName("head")[0];
+        var elements = new Set(headEl.children);
+        updateElements(
+          elements,
+          initialHeadEntries.map(function(_ref2) {
+            var _ref3 = _slicedToArray(_ref2, 2),
+              type = _ref3[0],
+              props = _ref3[1];
+
+            return /*#__PURE__*/ (0, _react.createElement)(type, props);
+          }),
+          false
+        );
         var updatePromise = null;
         return {
           mountedInstances: new Set(),
@@ -133,27 +202,7 @@ _N_E = (window["webpackJsonp_N_E"] = window["webpackJsonp_N_E"] || []).push([
             var promise = (updatePromise = Promise.resolve().then(function() {
               if (promise !== updatePromise) return;
               updatePromise = null;
-              var tags = {};
-              head.forEach(function(h) {
-                var components = tags[h.type] || [];
-                components.push(h);
-                tags[h.type] = components;
-              });
-              var titleComponent = tags.title ? tags.title[0] : null;
-              var title = "";
-
-              if (titleComponent) {
-                var children = titleComponent.props.children;
-                title =
-                  typeof children === "string" ? children : children.join("");
-              }
-
-              if (title !== document.title) document.title = title;
-              ["meta", "base", "link", "style", "script"].forEach(function(
-                type
-              ) {
-                updateElements(type, tags[type] || []);
-              });
+              updateElements(elements, head, true);
             }));
           }
         };
@@ -255,6 +304,8 @@ _N_E = (window["webpackJsonp_N_E"] = window["webpackJsonp_N_E"] || []).push([
         __webpack_require__("284h")
       );
 
+      __webpack_require__("0sNQ");
+
       var _react = _interopRequireDefault(__webpack_require__("q1tI"));
 
       var _reactDom = _interopRequireDefault(__webpack_require__("i8i4"));
@@ -286,15 +337,11 @@ _N_E = (window["webpackJsonp_N_E"] = window["webpackJsonp_N_E"] || []).push([
       var _router2 = __webpack_require__("nOHt");
       /* global location */
 
-      if (!("finally" in Promise.prototype)) {
-        Promise.prototype["finally"] = __webpack_require__("Z577");
-      }
-
       var data = JSON.parse(
         document.getElementById("__NEXT_DATA__").textContent
       );
       window.__NEXT_DATA__ = data;
-      var version = "9.5.3";
+      var version = "9.5.4-canary.25";
       exports.version = version;
       var hydrateProps = data.props,
         hydrateErr = data.err,
@@ -304,7 +351,8 @@ _N_E = (window["webpackJsonp_N_E"] = window["webpackJsonp_N_E"] || []).push([
         assetPrefix = data.assetPrefix,
         runtimeConfig = data.runtimeConfig,
         dynamicIds = data.dynamicIds,
-        isFallback = data.isFallback;
+        isFallback = data.isFallback,
+        initialHeadData = data.head;
       var prefix = assetPrefix || ""; // With dynamic assetPrefix it's no longer possible to set assetPrefix at the build time
       // So, this is how we do it in the client side at runtime
 
@@ -343,7 +391,7 @@ _N_E = (window["webpackJsonp_N_E"] = window["webpackJsonp_N_E"] || []).push([
 
       window.__NEXT_P = [];
       window.__NEXT_P.push = register;
-      var headManager = (0, _headManager["default"])();
+      var headManager = (0, _headManager["default"])(initialHeadData);
       var appElement = document.getElementById("__next");
       var lastAppProps;
 
@@ -1162,27 +1210,6 @@ _N_E = (window["webpackJsonp_N_E"] = window["webpackJsonp_N_E"] || []).push([
       /***/
     },
 
-    /***/ Z577: /***/ function(module, exports) {
-      Promise.prototype.finally = function(n) {
-        if ("function" != typeof n) return this.then(n, n);
-        var t = this.constructor || Promise;
-        return this.then(
-          function(r) {
-            return t.resolve(n()).then(function() {
-              return r;
-            });
-          },
-          function(r) {
-            return t.resolve(n()).then(function() {
-              throw r;
-            });
-          }
-        );
-      };
-
-      /***/
-    },
-
     /***/ a1gu: /***/ function(module, exports, __webpack_require__) {
       var _typeof = __webpack_require__("cDf5");
 
@@ -1225,21 +1252,6 @@ _N_E = (window["webpackJsonp_N_E"] = window["webpackJsonp_N_E"] || []).push([
       /***/
     },
 
-    /***/ fcRV: /***/ function(module, exports, __webpack_require__) {
-      "use strict";
-
-      exports.__esModule = true;
-      exports["default"] = escapePathDelimiters; // escape delimiters used by path-to-regexp
-
-      function escapePathDelimiters(segment) {
-        return segment.replace(/[/#?]/g, function(_char) {
-          return encodeURIComponent(_char);
-        });
-      }
-
-      /***/
-    },
-
     /***/ pVnL: /***/ function(module, exports) {
       function _extends() {
         module.exports = _extends =
@@ -1284,14 +1296,14 @@ _N_E = (window["webpackJsonp_N_E"] = window["webpackJsonp_N_E"] || []).push([
         __webpack_exports__,
         "getFCP",
         function() {
-          return m;
+          return v;
         }
       );
       /* harmony export (binding) */ __webpack_require__.d(
         __webpack_exports__,
         "getFID",
         function() {
-          return v;
+          return f;
         }
       );
       /* harmony export (binding) */ __webpack_require__.d(
@@ -1344,7 +1356,7 @@ _N_E = (window["webpackJsonp_N_E"] = window["webpackJsonp_N_E"] || []).push([
         },
         u = function() {
           addEventListener("pagehide", s),
-            addEventListener("unload", function() {});
+            addEventListener("beforeunload", function() {});
         },
         c = function(t) {
           var n =
@@ -1372,19 +1384,20 @@ _N_E = (window["webpackJsonp_N_E"] = window["webpackJsonp_N_E"] || []).push([
           };
         },
         p = function(t) {
-          var n =
-              arguments.length > 1 && void 0 !== arguments[1] && arguments[1],
-            e = i("CLS", 0),
-            r = function(t) {
+          var n,
+            e = arguments.length > 1 && void 0 !== arguments[1] && arguments[1],
+            r = i("CLS", 0),
+            o = function(t) {
               t.hadRecentInput ||
-                ((e.value += t.value), e.entries.push(t), s());
+                ((r.value += t.value), r.entries.push(t), n());
             },
-            o = a("layout-shift", r),
-            s = l(t, e, o, n);
-          c(function(t) {
-            var n = t.isUnloading;
-            o && o.takeRecords().map(r), n && (e.isFinal = !0), s();
-          });
+            s = a("layout-shift", o);
+          s &&
+            ((n = l(t, r, s, e)),
+            c(function(t) {
+              var e = t.isUnloading;
+              s.takeRecords().map(o), e && (r.isFinal = !0), n();
+            }));
         },
         d = function() {
           return (
@@ -1401,20 +1414,21 @@ _N_E = (window["webpackJsonp_N_E"] = window["webpackJsonp_N_E"] || []).push([
             }
           );
         },
-        m = function(t) {
-          var n = i("FCP"),
-            e = d(),
-            r = a("paint", function(t) {
+        v = function(t) {
+          var n,
+            e = i("FCP"),
+            r = d(),
+            o = a("paint", function(t) {
               "first-contentful-paint" === t.name &&
-                t.startTime < e.timeStamp &&
-                ((n.value = t.startTime),
-                (n.isFinal = !0),
-                n.entries.push(t),
-                o());
-            }),
-            o = l(t, n, r);
+                t.startTime < r.timeStamp &&
+                ((e.value = t.startTime),
+                (e.isFinal = !0),
+                e.entries.push(t),
+                n());
+            });
+          o && (n = l(t, e, o));
         },
-        v = function(t) {
+        f = function(t) {
           var n = i("FID"),
             e = d(),
             r = function(t) {
@@ -1426,30 +1440,30 @@ _N_E = (window["webpackJsonp_N_E"] = window["webpackJsonp_N_E"] || []).push([
             },
             o = a("first-input", r),
             s = l(t, n, o);
-          c(function() {
-            o && (o.takeRecords().map(r), o.disconnect());
-          }, !0),
-            o ||
-              (window.perfMetrics &&
-                window.perfMetrics.onFirstInputDelay &&
-                window.perfMetrics.onFirstInputDelay(function(t, i) {
-                  i.timeStamp < e.timeStamp &&
-                    ((n.value = t),
-                    (n.isFinal = !0),
-                    (n.entries = [
-                      {
-                        entryType: "first-input",
-                        name: i.type,
-                        target: i.target,
-                        cancelable: i.cancelable,
-                        startTime: i.timeStamp,
-                        processingStart: i.timeStamp + t
-                      }
-                    ]),
-                    s());
-                }));
+          o
+            ? c(function() {
+                o.takeRecords().map(r), o.disconnect();
+              }, !0)
+            : window.perfMetrics &&
+              window.perfMetrics.onFirstInputDelay &&
+              window.perfMetrics.onFirstInputDelay(function(t, i) {
+                i.timeStamp < e.timeStamp &&
+                  ((n.value = t),
+                  (n.isFinal = !0),
+                  (n.entries = [
+                    {
+                      entryType: "first-input",
+                      name: i.type,
+                      target: i.target,
+                      cancelable: i.cancelable,
+                      startTime: i.timeStamp,
+                      processingStart: i.timeStamp + t
+                    }
+                  ]),
+                  s());
+              });
         },
-        f = function() {
+        m = function() {
           return (
             n ||
               (n = new Promise(function(t) {
@@ -1465,23 +1479,25 @@ _N_E = (window["webpackJsonp_N_E"] = window["webpackJsonp_N_E"] || []).push([
           );
         },
         g = function(t) {
-          var n =
-              arguments.length > 1 && void 0 !== arguments[1] && arguments[1],
-            e = i("LCP"),
-            r = d(),
-            o = function(t) {
-              var n = t.startTime;
-              n < r.timeStamp
-                ? ((e.value = n), e.entries.push(t))
-                : (e.isFinal = !0),
-                u();
+          var n,
+            e = arguments.length > 1 && void 0 !== arguments[1] && arguments[1],
+            r = i("LCP"),
+            o = d(),
+            s = function(t) {
+              var e = t.startTime;
+              e < o.timeStamp
+                ? ((r.value = e), r.entries.push(t))
+                : (r.isFinal = !0),
+                n();
             },
-            s = a("largest-contentful-paint", o),
-            u = l(t, e, s, n),
-            p = function() {
-              e.isFinal || (s && s.takeRecords().map(o), (e.isFinal = !0), u());
+            u = a("largest-contentful-paint", s);
+          if (u) {
+            n = l(t, r, u, e);
+            var p = function() {
+              r.isFinal || (u.takeRecords().map(s), (r.isFinal = !0), n());
             };
-          f().then(p), c(p, !0);
+            m().then(p), c(p, !0);
+          }
         },
         h = function(t) {
           var n,
@@ -1550,10 +1566,6 @@ _N_E = (window["webpackJsonp_N_E"] = window["webpackJsonp_N_E"] || []).push([
 
       var _router = __webpack_require__("elyg");
 
-      var _escapePathDelimiters = _interopRequireDefault(
-        __webpack_require__("fcRV")
-      );
-
       var _getAssetPathFromRoute = _interopRequireDefault(
         __webpack_require__("Lab5")
       );
@@ -1562,12 +1574,6 @@ _N_E = (window["webpackJsonp_N_E"] = window["webpackJsonp_N_E"] || []).push([
 
       var _parseRelativeUrl = __webpack_require__("hS4m");
 
-      var _querystring = __webpack_require__("3WeD");
-
-      var _routeMatcher = __webpack_require__("gguc");
-
-      var _routeRegex = __webpack_require__("YTqd");
-
       var looseToArray = function looseToArray(input) {
         return [].slice.call(input);
       };
@@ -1752,13 +1758,9 @@ _N_E = (window["webpackJsonp_N_E"] = window["webpackJsonp_N_E"] || []).push([
 
               var _ref = (0, _parseRelativeUrl.parseRelativeUrl)(href),
                 hrefPathname = _ref.pathname,
-                searchParams = _ref.searchParams,
+                query = _ref.query,
                 search = _ref.search;
 
-              var query = (0, _querystring.searchParamsToUrlQuery)(
-                searchParams
-              );
-
               var _ref2 = (0, _parseRelativeUrl.parseRelativeUrl)(asPath),
                 asPathname = _ref2.pathname;
 
@@ -1777,59 +1779,11 @@ _N_E = (window["webpackJsonp_N_E"] = window["webpackJsonp_N_E"] || []).push([
                 );
               };
 
-              var isDynamic = (0, _isDynamic.isDynamicRoute)(route),
-                interpolatedRoute;
-
-              if (isDynamic) {
-                var dynamicRegex = (0, _routeRegex.getRouteRegex)(route);
-                var dynamicGroups = dynamicRegex.groups;
-                var dynamicMatches = // Try to match the dynamic route against the asPath
-                  (0, _routeMatcher.getRouteMatcher)(dynamicRegex)(
-                    asPathname
-                  ) || // Fall back to reading the values from the href
-                  // TODO: should this take priority; also need to change in the router.
-                  query;
-                interpolatedRoute = route;
-
-                if (
-                  !Object.keys(dynamicGroups).every(function(param) {
-                    var value = dynamicMatches[param] || "";
-                    var _dynamicGroups$param = dynamicGroups[param],
-                      repeat = _dynamicGroups$param.repeat,
-                      optional = _dynamicGroups$param.optional; // support single-level catch-all
-                    // TODO: more robust handling for user-error (passing `/`)
-
-                    var replaced = "["
-                      .concat(repeat ? "..." : "")
-                      .concat(param, "]");
-
-                    if (optional) {
-                      replaced = ""
-                        .concat(!value ? "/" : "", "[")
-                        .concat(replaced, "]");
-                    }
-
-                    if (repeat && !Array.isArray(value)) value = [value];
-                    return (
-                      (optional || param in dynamicMatches) && // Interpolate group into data URL if present
-                      (interpolatedRoute =
-                        interpolatedRoute.replace(
-                          replaced,
-                          repeat
-                            ? value
-                                .map(_escapePathDelimiters["default"])
-                                .join("/")
-                            : (0, _escapePathDelimiters["default"])(value)
-                        ) || "/")
-                    );
-                  })
-                ) {
-                  interpolatedRoute = ""; // did not satisfy all requirements
-                  // n.b. We ignore this error because we handle warning for this case in
-                  // development in the `<Link>` component directly.
-                }
-              }
-
+              var isDynamic = (0, _isDynamic.isDynamicRoute)(route);
+              var interpolatedRoute = isDynamic
+                ? (0, _router.interpolateAs)(hrefPathname, asPathname, query)
+                    .result
+                : "";
               return isDynamic
                 ? interpolatedRoute && getHrefForSlug(interpolatedRoute)
                 : getHrefForSlug(route);
Diff for index.html
@@ -3,11 +3,10 @@
   <head>
     <meta charset="utf-8" />
     <meta name="viewport" content="width=device-width" />
-    <meta name="next-head-count" content="2" />
     <noscript data-n-css="true"></noscript>
     <link
       rel="preload"
-      href="/_next/static/chunks/main-0d318286e5f7c6910b94.module.js"
+      href="/_next/static/chunks/main-ffaed3c3c4df8040b048.module.js"
       as="script"
       crossorigin="anonymous"
     />
@@ -25,7 +24,7 @@
     />
     <link
       rel="preload"
-      href="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.f48d291f6d1033f6c087.module.js"
+      href="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.ed82f38c7a1994b728aa.module.js"
       as="script"
       crossorigin="anonymous"
     />
@@ -51,7 +50,11 @@
         "query": {},
         "buildId": "BUILD_ID",
         "isFallback": false,
-        "gip": true
+        "gip": true,
+        "head": [
+          ["meta", { "charSet": "utf-8" }],
+          ["meta", { "name": "viewport", "content": "width=device-width" }]
+        ]
       }
     </script>
     <script crossorigin="anonymous" nomodule="">
@@ -82,13 +85,13 @@
       src="/_next/static/chunks/polyfills-f73ba3fc145972ef83e9.js"
     ></script>
     <script
-      src="/_next/static/chunks/main-58fe85dd211fac23ae4b.js"
+      src="/_next/static/chunks/main-d0571173288672e65fbf.js"
       async=""
       crossorigin="anonymous"
       nomodule=""
     ></script>
     <script
-      src="/_next/static/chunks/main-0d318286e5f7c6910b94.module.js"
+      src="/_next/static/chunks/main-ffaed3c3c4df8040b048.module.js"
       async=""
       crossorigin="anonymous"
       type="module"
@@ -118,13 +121,13 @@
       type="module"
     ></script>
     <script
-      src="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.abb28f9c6d97000fca82.js"
+      src="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.2730f3273c05fa35cac6.js"
       async=""
       crossorigin="anonymous"
       nomodule=""
     ></script>
     <script
-      src="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.f48d291f6d1033f6c087.module.js"
+      src="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.ed82f38c7a1994b728aa.module.js"
       async=""
       crossorigin="anonymous"
       type="module"
Diff for link.html
@@ -3,11 +3,10 @@
   <head>
     <meta charset="utf-8" />
     <meta name="viewport" content="width=device-width" />
-    <meta name="next-head-count" content="2" />
     <noscript data-n-css="true"></noscript>
     <link
       rel="preload"
-      href="/_next/static/chunks/main-0d318286e5f7c6910b94.module.js"
+      href="/_next/static/chunks/main-ffaed3c3c4df8040b048.module.js"
       as="script"
       crossorigin="anonymous"
     />
@@ -25,7 +24,7 @@
     />
     <link
       rel="preload"
-      href="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.f48d291f6d1033f6c087.module.js"
+      href="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.ed82f38c7a1994b728aa.module.js"
       as="script"
       crossorigin="anonymous"
     />
@@ -37,7 +36,7 @@
     />
     <link
       rel="preload"
-      href="/_next/static/chunks/pages/link-e2f1e0e7ed02569239da.module.js"
+      href="/_next/static/chunks/pages/link-cb038f0ac2e648ce4861.module.js"
       as="script"
       crossorigin="anonymous"
     />
@@ -56,7 +55,11 @@
         "query": {},
         "buildId": "BUILD_ID",
         "isFallback": false,
-        "gip": true
+        "gip": true,
+        "head": [
+          ["meta", { "charSet": "utf-8" }],
+          ["meta", { "name": "viewport", "content": "width=device-width" }]
+        ]
       }
     </script>
     <script crossorigin="anonymous" nomodule="">
@@ -87,13 +90,13 @@
       src="/_next/static/chunks/polyfills-f73ba3fc145972ef83e9.js"
     ></script>
     <script
-      src="/_next/static/chunks/main-58fe85dd211fac23ae4b.js"
+      src="/_next/static/chunks/main-d0571173288672e65fbf.js"
       async=""
       crossorigin="anonymous"
       nomodule=""
     ></script>
     <script
-      src="/_next/static/chunks/main-0d318286e5f7c6910b94.module.js"
+      src="/_next/static/chunks/main-ffaed3c3c4df8040b048.module.js"
       async=""
       crossorigin="anonymous"
       type="module"
@@ -123,13 +126,13 @@
       type="module"
     ></script>
     <script
-      src="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.abb28f9c6d97000fca82.js"
+      src="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.2730f3273c05fa35cac6.js"
       async=""
       crossorigin="anonymous"
       nomodule=""
     ></script>
     <script
-      src="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.f48d291f6d1033f6c087.module.js"
+      src="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.ed82f38c7a1994b728aa.module.js"
       async=""
       crossorigin="anonymous"
       type="module"
@@ -147,13 +150,13 @@
       type="module"
     ></script>
     <script
-      src="/_next/static/chunks/pages/link-46fd48c0b73b2f2d75a4.js"
+      src="/_next/static/chunks/pages/link-32658e75d53af2daa2e0.js"
       async=""
       crossorigin="anonymous"
       nomodule=""
     ></script>
     <script
-      src="/_next/static/chunks/pages/link-e2f1e0e7ed02569239da.module.js"
+      src="/_next/static/chunks/pages/link-cb038f0ac2e648ce4861.module.js"
       async=""
       crossorigin="anonymous"
       type="module"
Diff for withRouter.html
@@ -3,11 +3,10 @@
   <head>
     <meta charset="utf-8" />
     <meta name="viewport" content="width=device-width" />
-    <meta name="next-head-count" content="2" />
     <noscript data-n-css="true"></noscript>
     <link
       rel="preload"
-      href="/_next/static/chunks/main-0d318286e5f7c6910b94.module.js"
+      href="/_next/static/chunks/main-ffaed3c3c4df8040b048.module.js"
       as="script"
       crossorigin="anonymous"
     />
@@ -25,7 +24,7 @@
     />
     <link
       rel="preload"
-      href="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.f48d291f6d1033f6c087.module.js"
+      href="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.ed82f38c7a1994b728aa.module.js"
       as="script"
       crossorigin="anonymous"
     />
@@ -51,7 +50,11 @@
         "query": {},
         "buildId": "BUILD_ID",
         "isFallback": false,
-        "gip": true
+        "gip": true,
+        "head": [
+          ["meta", { "charSet": "utf-8" }],
+          ["meta", { "name": "viewport", "content": "width=device-width" }]
+        ]
       }
     </script>
     <script crossorigin="anonymous" nomodule="">
@@ -82,13 +85,13 @@
       src="/_next/static/chunks/polyfills-f73ba3fc145972ef83e9.js"
     ></script>
     <script
-      src="/_next/static/chunks/main-58fe85dd211fac23ae4b.js"
+      src="/_next/static/chunks/main-d0571173288672e65fbf.js"
       async=""
       crossorigin="anonymous"
       nomodule=""
     ></script>
     <script
-      src="/_next/static/chunks/main-0d318286e5f7c6910b94.module.js"
+      src="/_next/static/chunks/main-ffaed3c3c4df8040b048.module.js"
       async=""
       crossorigin="anonymous"
       type="module"
@@ -118,13 +121,13 @@
       type="module"
     ></script>
     <script
-      src="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.abb28f9c6d97000fca82.js"
+      src="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.2730f3273c05fa35cac6.js"
       async=""
       crossorigin="anonymous"
       nomodule=""
     ></script>
     <script
-      src="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.f48d291f6d1033f6c087.module.js"
+      src="/_next/static/chunks/677f882d2ed86fa3467b8979053c1a4c3f8bc4df.ed82f38c7a1994b728aa.module.js"
       async=""
       crossorigin="anonymous"
       type="module"

Serverless Mode (Increase detected ⚠️)
General Overall increase ⚠️
vercel/next.js canary v9.5.3 vercel/next.js refs/heads/canary Change
buildDuration 14.9s 14.8s -190ms
nodeModulesSize 63.1 MB 63.2 MB ⚠️ +149 kB
Client Bundles (main, webpack, commons) Overall increase ⚠️
vercel/next.js canary v9.5.3 vercel/next.js refs/heads/canary Change
677f882d2ed8..9ff9.js gzip 10.3 kB N/A N/A
framework.HASH.js gzip 39 kB 39 kB
main-b338f5a..3500.js gzip 7.31 kB N/A N/A
webpack-e067..f178.js gzip 751 B 751 B
677f882d2ed8..9339.js gzip N/A 10.9 kB N/A
main-a4a533b..903f.js gzip N/A 7.17 kB N/A
Overall change 57.3 kB 57.8 kB ⚠️ +495 B
Client Bundles (main, webpack, commons) Modern Overall increase ⚠️
vercel/next.js canary v9.5.3 vercel/next.js refs/heads/canary Change
677f882d2ed8..dule.js gzip 6.13 kB N/A N/A
framework.HA..dule.js gzip 39 kB 39 kB
main-830c506..dule.js gzip 6.37 kB N/A N/A
webpack-07c5..dule.js gzip 751 B 751 B
677f882d2ed8..dule.js gzip N/A 6.77 kB N/A
main-cacdafa..dule.js gzip N/A 6.24 kB N/A
Overall change 52.2 kB 52.7 kB ⚠️ +510 B
Legacy Client Bundles (polyfills)
vercel/next.js canary v9.5.3 vercel/next.js refs/heads/canary Change
polyfills-4b..e242.js gzip 31 kB 31 kB
Overall change 31 kB 31 kB
Client Pages Overall increase ⚠️
vercel/next.js canary v9.5.3 vercel/next.js refs/heads/canary Change
_app-9a0b9e1..b37e.js gzip 1.28 kB 1.28 kB
_error-ed1b0..8fbd.js gzip 3.44 kB 3.44 kB
hooks-89731c..c609.js gzip 887 B 887 B
index-17468f..5d83.js gzip 227 B 227 B
link-ae98065..267e.js gzip 1.29 kB N/A N/A
routerDirect..924c.js gzip 284 B 284 B
withRouter-7..c13d.js gzip 284 B 284 B
link-d2344ce..8b36.js gzip N/A 1.3 kB N/A
Overall change 7.69 kB 7.71 kB ⚠️ +16 B
Client Pages Modern Overall increase ⚠️
vercel/next.js canary v9.5.3 vercel/next.js refs/heads/canary Change
_app-75d3a82..dule.js gzip 625 B 625 B
_error-4469a..dule.js gzip 2.29 kB 2.29 kB
hooks-cbf13f..dule.js gzip 387 B 387 B
index-b9a643..dule.js gzip 226 B 226 B
link-cb244c4..dule.js gzip 1.26 kB N/A N/A
routerDirect..dule.js gzip 284 B 284 B
withRouter-f..dule.js gzip 282 B 282 B
link-f8c0daf..dule.js gzip N/A 1.26 kB N/A
Overall change 5.35 kB 5.36 kB ⚠️ +5 B
Client Build Manifests Overall decrease ✓
vercel/next.js canary v9.5.3 vercel/next.js refs/heads/canary Change
_buildManifest.js gzip 323 B 322 B -1 B
_buildManife..dule.js gzip 329 B 329 B
Overall change 652 B 651 B -1 B
Serverless bundles Overall increase ⚠️
vercel/next.js canary v9.5.3 vercel/next.js refs/heads/canary Change
_error.js 1.05 MB 1.05 MB ⚠️ +475 B
404.html 4.22 kB 4.34 kB ⚠️ +115 B
hooks.html 3.86 kB 3.92 kB ⚠️ +56 B
index.js 1.05 MB 1.05 MB ⚠️ +475 B
link.js 1.09 MB 1.1 MB ⚠️ +4.93 kB
routerDirect.js 1.09 MB 1.09 MB ⚠️ +4.9 kB
withRouter.js 1.09 MB 1.09 MB ⚠️ +4.9 kB
Overall change 5.38 MB 5.4 MB ⚠️ +15.9 kB

Please sign in to comment.