KEMBAR78
Reuse existing `<link rel=stylesheet>` on nav by Timer · Pull Request #16537 · vercel/next.js · GitHub
Skip to content

Conversation

@Timer
Copy link
Member

@Timer Timer commented Aug 24, 2020

This pull request reuses existing <link rel=stylesheet> tags if their href matches instead of recreating it. This is in effort to fix an edge case where the browser will FOUC on the tag swap.

This behavior should be sufficiently covered by all the existing CSS cases, as misbehavior would result in the resulting CSS styles being incorrect.

@ijjk

This comment has been minimized.

@ijjk

This comment has been minimized.

@ijjk
Copy link
Member

ijjk commented Aug 25, 2020

Stats from current PR

Default Server Mode (Increase detected ⚠️)
General Overall increase ⚠️
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
buildDuration 12.3s 11.5s -811ms
nodeModulesSize 57.5 MB 57.5 MB ⚠️ +3.67 kB
Page Load Tests Overall increase ✓
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
/ failed reqs 0 0
/ total time (seconds) 2.342 2.286 -0.06
/ avg req/sec 1067.33 1093.58 +26.25
/error-in-render failed reqs 0 0
/error-in-render total time (seconds) 1.499 1.404 -0.1
/error-in-render avg req/sec 1667.31 1780.68 +113.37
Client Bundles (main, webpack, commons) Overall increase ⚠️
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
677f882d2ed8..7f47.js gzip 10.3 kB 10.3 kB
framework.HASH.js gzip 39 kB 39 kB
main-7e72e5b..8b35.js gzip 7.2 kB 7.34 kB ⚠️ +143 B
webpack-e067..f178.js gzip 751 B 751 B
Overall change 57.2 kB 57.4 kB ⚠️ +143 B
Client Bundles (main, webpack, commons) Modern Overall increase ⚠️
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
677f882d2ed8..dule.js gzip 6.15 kB 6.15 kB
framework.HA..dule.js gzip 39 kB 39 kB
main-e35d22e..dule.js gzip 6.24 kB 6.39 kB ⚠️ +150 B
webpack-07c5..dule.js gzip 751 B 751 B
Overall change 52.1 kB 52.3 kB ⚠️ +150 B
Legacy Client Bundles (polyfills)
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
polyfills-4b..e242.js gzip 31 kB 31 kB
Overall change 31 kB 31 kB
Client Pages
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
_app-9a0b9e1..b37e.js gzip 1.28 kB 1.28 kB
_error-28298..e0c9.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-000f151..65d4.js gzip 1.29 kB 1.29 kB
routerDirect..924c.js gzip 284 B 284 B
withRouter-7..c13d.js gzip 284 B 284 B
Overall change 7.69 kB 7.69 kB
Client Pages Modern
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
_app-75d3a82..dule.js gzip 625 B 625 B
_error-65c8a..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-4cfda7a..dule.js gzip 1.26 kB 1.26 kB
routerDirect..dule.js gzip 284 B 284 B
withRouter-f..dule.js gzip 282 B 282 B
Overall change 5.35 kB 5.35 kB
Client Build Manifests
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
_buildManifest.js gzip 322 B 322 B
_buildManife..dule.js gzip 330 B 330 B
Overall change 652 B 652 B
Rendered Page Sizes Overall increase ⚠️
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
index.html gzip 948 B 948 B
link.html gzip 954 B 954 B
withRouter.html gzip 939 B 940 B ⚠️ +1 B
Overall change 2.84 kB 2.84 kB ⚠️ +1 B

Diffs

Diff for main-068840f..b9.module.js
@@ -738,33 +738,52 @@
           } // Clean up previous render if canceling:
 
           [].slice
-            .call(document.querySelectorAll("link[data-n-staging]"))
+            .call(
+              document.querySelectorAll(
+                "link[data-n-staging], noscript[data-n-staging]"
+              )
+            )
             .forEach(el => {
               el.parentNode.removeChild(el);
             });
-          var referenceNode = [].slice
-            .call(document.querySelectorAll("link[data-n-g], link[data-n-p]"))
-            .pop();
+          var referenceNodes = [].slice.call(
+            document.querySelectorAll("link[data-n-g], link[data-n-p]")
+          );
+          var referenceHrefs = new Set(
+            referenceNodes.map(e => e.getAttribute("href"))
+          );
+          var referenceNode = referenceNodes[referenceNodes.length - 1];
           var required = styleSheets.map(href => {
-            var [link, promise] = (0, _pageLoader.createLink)(
-              href,
-              "stylesheet"
-            );
-            link.setAttribute("data-n-staging", ""); // Media `none` does not work in Firefox, so `print` is more
-            // cross-browser. Since this is so short lived we don't have to worry
-            // about style thrashing in a print view (where no routing is going to be
-            // happening anyway).
+            var newNode, promise;
+            var existingLink = referenceHrefs.has(href);
 
-            link.setAttribute("media", "print");
+            if (existingLink) {
+              newNode = document.createElement("noscript");
+              newNode.setAttribute("data-n-staging", href);
+              promise = true;
+            } else {
+              var [link, onload] = (0, _pageLoader.createLink)(
+                href,
+                "stylesheet"
+              );
+              link.setAttribute("data-n-staging", ""); // Media `none` does not work in Firefox, so `print` is more
+              // cross-browser. Since this is so short lived we don't have to worry
+              // about style thrashing in a print view (where no routing is going to be
+              // happening anyway).
+
+              link.setAttribute("media", "print");
+              newNode = link;
+              promise = onload;
+            }
 
             if (referenceNode) {
               referenceNode.parentNode.insertBefore(
-                link,
+                newNode,
                 referenceNode.nextSibling
               );
-              referenceNode = link;
+              referenceNode = newNode;
             } else {
-              document.head.appendChild(link);
+              document.head.appendChild(newNode);
             }
 
             return promise;
@@ -792,16 +811,41 @@
 
         function onCommit() {
           if (
-            // We can skip this during hydration. Running it wont cause any harm, but
-            // we may as well save the CPU cycles.
-            !isInitialRender && // We use `style-loader` in development, so we don't need to do anything
+            // We use `style-loader` in development, so we don't need to do anything
             // unless we're in production:
-            true
+            true && // We can skip this during hydration. Running it wont cause any harm, but
+            // we may as well save the CPU cycles:
+            !isInitialRender && // Ensure this render commit owns the currently staged stylesheets:
+            renderPromiseReject === lastRenderReject
           ) {
-            // Remove old stylesheets:
+            // Remove or relocate old stylesheets:
+            var relocatePlaceholders = [].slice.call(
+              document.querySelectorAll("noscript[data-n-staging]")
+            );
+            var relocateHrefs = relocatePlaceholders.map(e =>
+              e.getAttribute("data-n-staging")
+            );
             [].slice
               .call(document.querySelectorAll("link[data-n-p]"))
-              .forEach(el => el.parentNode.removeChild(el)); // Activate new stylesheets:
+              .forEach(el => {
+                var currentHref = el.getAttribute("href");
+                var relocateIndex = relocateHrefs.indexOf(currentHref);
+
+                if (relocateIndex !== -1) {
+                  var _placeholderElement$p;
+
+                  var placeholderElement = relocatePlaceholders[relocateIndex];
+                  (_placeholderElement$p = placeholderElement.parentNode) ==
+                  null
+                    ? void 0
+                    : _placeholderElement$p.replaceChild(
+                        el,
+                        placeholderElement
+                      );
+                } else {
+                  el.parentNode.removeChild(el);
+                }
+              }); // Activate new stylesheets:
             [].slice
               .call(document.querySelectorAll("link[data-n-staging]"))
               .forEach(el => {
Diff for main-3b9630b..7bb71a7cf.js
@@ -1003,34 +1003,55 @@ _N_E = (window["webpackJsonp_N_E"] = window["webpackJsonp_N_E"] || []).push([
           } // Clean up previous render if canceling:
 
           [].slice
-            .call(document.querySelectorAll("link[data-n-staging]"))
+            .call(
+              document.querySelectorAll(
+                "link[data-n-staging], noscript[data-n-staging]"
+              )
+            )
             .forEach(function(el) {
               el.parentNode.removeChild(el);
             });
-          var referenceNode = [].slice
-            .call(document.querySelectorAll("link[data-n-g], link[data-n-p]"))
-            .pop();
+          var referenceNodes = [].slice.call(
+            document.querySelectorAll("link[data-n-g], link[data-n-p]")
+          );
+          var referenceHrefs = new Set(
+            referenceNodes.map(function(e) {
+              return e.getAttribute("href");
+            })
+          );
+          var referenceNode = referenceNodes[referenceNodes.length - 1];
           var required = styleSheets.map(function(href) {
-            var _ref9 = (0, _pageLoader.createLink)(href, "stylesheet"),
-              _ref10 = _slicedToArray(_ref9, 2),
-              link = _ref10[0],
-              promise = _ref10[1];
-
-            link.setAttribute("data-n-staging", ""); // Media `none` does not work in Firefox, so `print` is more
-            // cross-browser. Since this is so short lived we don't have to worry
-            // about style thrashing in a print view (where no routing is going to be
-            // happening anyway).
+            var newNode, promise;
+            var existingLink = referenceHrefs.has(href);
 
-            link.setAttribute("media", "print");
+            if (existingLink) {
+              newNode = document.createElement("noscript");
+              newNode.setAttribute("data-n-staging", href);
+              promise = true;
+            } else {
+              var _ref9 = (0, _pageLoader.createLink)(href, "stylesheet"),
+                _ref10 = _slicedToArray(_ref9, 2),
+                link = _ref10[0],
+                onload = _ref10[1];
+
+              link.setAttribute("data-n-staging", ""); // Media `none` does not work in Firefox, so `print` is more
+              // cross-browser. Since this is so short lived we don't have to worry
+              // about style thrashing in a print view (where no routing is going to be
+              // happening anyway).
+
+              link.setAttribute("media", "print");
+              newNode = link;
+              promise = onload;
+            }
 
             if (referenceNode) {
               referenceNode.parentNode.insertBefore(
-                link,
+                newNode,
                 referenceNode.nextSibling
               );
-              referenceNode = link;
+              referenceNode = newNode;
             } else {
-              document.head.appendChild(link);
+              document.head.appendChild(newNode);
             }
 
             return promise;
@@ -1058,17 +1079,40 @@ _N_E = (window["webpackJsonp_N_E"] = window["webpackJsonp_N_E"] || []).push([
 
         function onCommit() {
           if (
-            // We can skip this during hydration. Running it wont cause any harm, but
-            // we may as well save the CPU cycles.
-            !isInitialRender && // We use `style-loader` in development, so we don't need to do anything
+            // We use `style-loader` in development, so we don't need to do anything
             // unless we're in production:
-            true
+            true && // We can skip this during hydration. Running it wont cause any harm, but
+            // we may as well save the CPU cycles:
+            !isInitialRender && // Ensure this render commit owns the currently staged stylesheets:
+            renderPromiseReject === _lastRenderReject
           ) {
-            // Remove old stylesheets:
+            // Remove or relocate old stylesheets:
+            var relocatePlaceholders = [].slice.call(
+              document.querySelectorAll("noscript[data-n-staging]")
+            );
+            var relocateHrefs = relocatePlaceholders.map(function(e) {
+              return e.getAttribute("data-n-staging");
+            });
             [].slice
               .call(document.querySelectorAll("link[data-n-p]"))
               .forEach(function(el) {
-                return el.parentNode.removeChild(el);
+                var currentHref = el.getAttribute("href");
+                var relocateIndex = relocateHrefs.indexOf(currentHref);
+
+                if (relocateIndex !== -1) {
+                  var _placeholderElement$p;
+
+                  var placeholderElement = relocatePlaceholders[relocateIndex];
+                  (_placeholderElement$p = placeholderElement.parentNode) ==
+                  null
+                    ? void 0
+                    : _placeholderElement$p.replaceChild(
+                        el,
+                        placeholderElement
+                      );
+                } else {
+                  el.parentNode.removeChild(el);
+                }
               }); // Activate new stylesheets:
             [].slice
               .call(document.querySelectorAll("link[data-n-staging]"))
Diff for index.html
@@ -6,7 +6,7 @@
     <meta name="next-head-count" content="2" />
     <link
       rel="preload"
-      href="/_next/static/chunks/main-068840f0e612011037b9.module.js"
+      href="/_next/static/chunks/main-d0cc0845ea39d503dc7b.module.js"
       as="script"
       crossorigin="anonymous"
     />
@@ -81,13 +81,13 @@
       src="/_next/static/chunks/polyfills-f73ba3fc145972ef83e9.js"
     ></script>
     <script
-      src="/_next/static/chunks/main-3b9630b9b147bb71a7cf.js"
+      src="/_next/static/chunks/main-bb1cdcacb135483d56cf.js"
       async=""
       crossorigin="anonymous"
       nomodule=""
     ></script>
     <script
-      src="/_next/static/chunks/main-068840f0e612011037b9.module.js"
+      src="/_next/static/chunks/main-d0cc0845ea39d503dc7b.module.js"
       async=""
       crossorigin="anonymous"
       type="module"
Diff for link.html
@@ -6,7 +6,7 @@
     <meta name="next-head-count" content="2" />
     <link
       rel="preload"
-      href="/_next/static/chunks/main-068840f0e612011037b9.module.js"
+      href="/_next/static/chunks/main-d0cc0845ea39d503dc7b.module.js"
       as="script"
       crossorigin="anonymous"
     />
@@ -86,13 +86,13 @@
       src="/_next/static/chunks/polyfills-f73ba3fc145972ef83e9.js"
     ></script>
     <script
-      src="/_next/static/chunks/main-3b9630b9b147bb71a7cf.js"
+      src="/_next/static/chunks/main-bb1cdcacb135483d56cf.js"
       async=""
       crossorigin="anonymous"
       nomodule=""
     ></script>
     <script
-      src="/_next/static/chunks/main-068840f0e612011037b9.module.js"
+      src="/_next/static/chunks/main-d0cc0845ea39d503dc7b.module.js"
       async=""
       crossorigin="anonymous"
       type="module"
Diff for withRouter.html
@@ -6,7 +6,7 @@
     <meta name="next-head-count" content="2" />
     <link
       rel="preload"
-      href="/_next/static/chunks/main-068840f0e612011037b9.module.js"
+      href="/_next/static/chunks/main-d0cc0845ea39d503dc7b.module.js"
       as="script"
       crossorigin="anonymous"
     />
@@ -81,13 +81,13 @@
       src="/_next/static/chunks/polyfills-f73ba3fc145972ef83e9.js"
     ></script>
     <script
-      src="/_next/static/chunks/main-3b9630b9b147bb71a7cf.js"
+      src="/_next/static/chunks/main-bb1cdcacb135483d56cf.js"
       async=""
       crossorigin="anonymous"
       nomodule=""
     ></script>
     <script
-      src="/_next/static/chunks/main-068840f0e612011037b9.module.js"
+      src="/_next/static/chunks/main-d0cc0845ea39d503dc7b.module.js"
       async=""
       crossorigin="anonymous"
       type="module"

Serverless Mode (Increase detected ⚠️)
General Overall increase ⚠️
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
buildDuration 14.2s 13.4s -809ms
nodeModulesSize 57.5 MB 57.5 MB ⚠️ +3.67 kB
Client Bundles (main, webpack, commons) Overall increase ⚠️
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
677f882d2ed8..7f47.js gzip 10.3 kB 10.3 kB
framework.HASH.js gzip 39 kB 39 kB
main-7e72e5b..8b35.js gzip 7.2 kB N/A N/A
webpack-e067..f178.js gzip 751 B 751 B
main-e201d12..5ffe.js gzip N/A 7.34 kB N/A
Overall change 57.2 kB 57.4 kB ⚠️ +143 B
Client Bundles (main, webpack, commons) Modern Overall increase ⚠️
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
677f882d2ed8..dule.js gzip 6.15 kB 6.15 kB
framework.HA..dule.js gzip 39 kB 39 kB
main-e35d22e..dule.js gzip 6.24 kB N/A N/A
webpack-07c5..dule.js gzip 751 B 751 B
main-5bdc93c..dule.js gzip N/A 6.39 kB N/A
Overall change 52.1 kB 52.3 kB ⚠️ +150 B
Legacy Client Bundles (polyfills)
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
polyfills-4b..e242.js gzip 31 kB 31 kB
Overall change 31 kB 31 kB
Client Pages
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
_app-9a0b9e1..b37e.js gzip 1.28 kB 1.28 kB
_error-28298..e0c9.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-000f151..65d4.js gzip 1.29 kB 1.29 kB
routerDirect..924c.js gzip 284 B 284 B
withRouter-7..c13d.js gzip 284 B 284 B
Overall change 7.69 kB 7.69 kB
Client Pages Modern
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
_app-75d3a82..dule.js gzip 625 B 625 B
_error-65c8a..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-4cfda7a..dule.js gzip 1.26 kB 1.26 kB
routerDirect..dule.js gzip 284 B 284 B
withRouter-f..dule.js gzip 282 B 282 B
Overall change 5.35 kB 5.35 kB
Client Build Manifests
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
_buildManifest.js gzip 322 B 322 B
_buildManife..dule.js gzip 330 B 330 B
Overall change 652 B 652 B
Serverless bundles
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
_error.js 1.03 MB 1.03 MB
404.html 4.18 kB 4.18 kB
hooks.html 3.82 kB 3.82 kB
index.js 1.03 MB 1.03 MB
link.js 1.07 MB 1.07 MB
routerDirect.js 1.07 MB 1.07 MB
withRouter.js 1.07 MB 1.07 MB
Overall change 5.28 MB 5.28 MB
Commit: 7948203

@Timer Timer marked this pull request as ready for review August 25, 2020 05:11
@ijjk
Copy link
Member

ijjk commented Aug 25, 2020

Stats from current PR

Default Server Mode (Increase detected ⚠️)
General Overall increase ⚠️
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
buildDuration 12.4s 12s -436ms
nodeModulesSize 57.5 MB 57.5 MB ⚠️ +3.67 kB
Page Load Tests Overall increase ✓
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
/ failed reqs 0 0
/ total time (seconds) 2.206 2.104 -0.1
/ avg req/sec 1133.05 1188.49 +55.44
/error-in-render failed reqs 0 0
/error-in-render total time (seconds) 1.198 1.132 -0.07
/error-in-render avg req/sec 2087.12 2207.86 +120.74
Client Bundles (main, webpack, commons) Overall increase ⚠️
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
677f882d2ed8..7f47.js gzip 10.3 kB 10.3 kB
framework.HASH.js gzip 39 kB 39 kB
main-1338f54..276e.js gzip 7.2 kB 7.34 kB ⚠️ +143 B
webpack-e067..f178.js gzip 751 B 751 B
Overall change 57.2 kB 57.4 kB ⚠️ +143 B
Client Bundles (main, webpack, commons) Modern Overall increase ⚠️
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
677f882d2ed8..dule.js gzip 6.15 kB 6.15 kB
framework.HA..dule.js gzip 39 kB 39 kB
main-1455da7..dule.js gzip 6.24 kB 6.39 kB ⚠️ +149 B
webpack-07c5..dule.js gzip 751 B 751 B
Overall change 52.1 kB 52.3 kB ⚠️ +149 B
Legacy Client Bundles (polyfills)
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
polyfills-4b..e242.js gzip 31 kB 31 kB
Overall change 31 kB 31 kB
Client Pages
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
_app-9a0b9e1..b37e.js gzip 1.28 kB 1.28 kB
_error-28298..e0c9.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-000f151..65d4.js gzip 1.29 kB 1.29 kB
routerDirect..924c.js gzip 284 B 284 B
withRouter-7..c13d.js gzip 284 B 284 B
Overall change 7.69 kB 7.69 kB
Client Pages Modern
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
_app-75d3a82..dule.js gzip 625 B 625 B
_error-65c8a..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-4cfda7a..dule.js gzip 1.26 kB 1.26 kB
routerDirect..dule.js gzip 284 B 284 B
withRouter-f..dule.js gzip 282 B 282 B
Overall change 5.35 kB 5.35 kB
Client Build Manifests
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
_buildManifest.js gzip 322 B 322 B
_buildManife..dule.js gzip 330 B 330 B
Overall change 652 B 652 B
Rendered Page Sizes Overall decrease ✓
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
index.html gzip 948 B 948 B
link.html gzip 954 B 953 B -1 B
withRouter.html gzip 940 B 940 B
Overall change 2.84 kB 2.84 kB -1 B

Diffs

Diff for main-486aa09..bc.module.js
@@ -738,33 +738,52 @@
           } // Clean up previous render if canceling:
 
           [].slice
-            .call(document.querySelectorAll("link[data-n-staging]"))
+            .call(
+              document.querySelectorAll(
+                "link[data-n-staging], noscript[data-n-staging]"
+              )
+            )
             .forEach(el => {
               el.parentNode.removeChild(el);
             });
-          var referenceNode = [].slice
-            .call(document.querySelectorAll("link[data-n-g], link[data-n-p]"))
-            .pop();
+          var referenceNodes = [].slice.call(
+            document.querySelectorAll("link[data-n-g], link[data-n-p]")
+          );
+          var referenceHrefs = new Set(
+            referenceNodes.map(e => e.getAttribute("href"))
+          );
+          var referenceNode = referenceNodes[referenceNodes.length - 1];
           var required = styleSheets.map(href => {
-            var [link, promise] = (0, _pageLoader.createLink)(
-              href,
-              "stylesheet"
-            );
-            link.setAttribute("data-n-staging", ""); // Media `none` does not work in Firefox, so `print` is more
-            // cross-browser. Since this is so short lived we don't have to worry
-            // about style thrashing in a print view (where no routing is going to be
-            // happening anyway).
+            var newNode, promise;
+            var existingLink = referenceHrefs.has(href);
 
-            link.setAttribute("media", "print");
+            if (existingLink) {
+              newNode = document.createElement("noscript");
+              newNode.setAttribute("data-n-staging", href);
+              promise = true;
+            } else {
+              var [link, onload] = (0, _pageLoader.createLink)(
+                href,
+                "stylesheet"
+              );
+              link.setAttribute("data-n-staging", ""); // Media `none` does not work in Firefox, so `print` is more
+              // cross-browser. Since this is so short lived we don't have to worry
+              // about style thrashing in a print view (where no routing is going to be
+              // happening anyway).
+
+              link.setAttribute("media", "print");
+              newNode = link;
+              promise = onload;
+            }
 
             if (referenceNode) {
               referenceNode.parentNode.insertBefore(
-                link,
+                newNode,
                 referenceNode.nextSibling
               );
-              referenceNode = link;
+              referenceNode = newNode;
             } else {
-              document.head.appendChild(link);
+              document.head.appendChild(newNode);
             }
 
             return promise;
@@ -792,16 +811,41 @@
 
         function onCommit() {
           if (
-            // We can skip this during hydration. Running it wont cause any harm, but
-            // we may as well save the CPU cycles.
-            !isInitialRender && // We use `style-loader` in development, so we don't need to do anything
+            // We use `style-loader` in development, so we don't need to do anything
             // unless we're in production:
-            true
+            true && // We can skip this during hydration. Running it wont cause any harm, but
+            // we may as well save the CPU cycles:
+            !isInitialRender && // Ensure this render commit owns the currently staged stylesheets:
+            renderPromiseReject === lastRenderReject
           ) {
-            // Remove old stylesheets:
+            // Remove or relocate old stylesheets:
+            var relocatePlaceholders = [].slice.call(
+              document.querySelectorAll("noscript[data-n-staging]")
+            );
+            var relocateHrefs = relocatePlaceholders.map(e =>
+              e.getAttribute("data-n-staging")
+            );
             [].slice
               .call(document.querySelectorAll("link[data-n-p]"))
-              .forEach(el => el.parentNode.removeChild(el)); // Activate new stylesheets:
+              .forEach(el => {
+                var currentHref = el.getAttribute("href");
+                var relocateIndex = relocateHrefs.indexOf(currentHref);
+
+                if (relocateIndex !== -1) {
+                  var _placeholderElement$p;
+
+                  var placeholderElement = relocatePlaceholders[relocateIndex];
+                  (_placeholderElement$p = placeholderElement.parentNode) ==
+                  null
+                    ? void 0
+                    : _placeholderElement$p.replaceChild(
+                        el,
+                        placeholderElement
+                      );
+                } else {
+                  el.parentNode.removeChild(el);
+                }
+              }); // Activate new stylesheets:
             [].slice
               .call(document.querySelectorAll("link[data-n-staging]"))
               .forEach(el => {
Diff for main-7ec0af7..0b45726c4.js
@@ -1003,34 +1003,55 @@ _N_E = (window["webpackJsonp_N_E"] = window["webpackJsonp_N_E"] || []).push([
           } // Clean up previous render if canceling:
 
           [].slice
-            .call(document.querySelectorAll("link[data-n-staging]"))
+            .call(
+              document.querySelectorAll(
+                "link[data-n-staging], noscript[data-n-staging]"
+              )
+            )
             .forEach(function(el) {
               el.parentNode.removeChild(el);
             });
-          var referenceNode = [].slice
-            .call(document.querySelectorAll("link[data-n-g], link[data-n-p]"))
-            .pop();
+          var referenceNodes = [].slice.call(
+            document.querySelectorAll("link[data-n-g], link[data-n-p]")
+          );
+          var referenceHrefs = new Set(
+            referenceNodes.map(function(e) {
+              return e.getAttribute("href");
+            })
+          );
+          var referenceNode = referenceNodes[referenceNodes.length - 1];
           var required = styleSheets.map(function(href) {
-            var _ref9 = (0, _pageLoader.createLink)(href, "stylesheet"),
-              _ref10 = _slicedToArray(_ref9, 2),
-              link = _ref10[0],
-              promise = _ref10[1];
-
-            link.setAttribute("data-n-staging", ""); // Media `none` does not work in Firefox, so `print` is more
-            // cross-browser. Since this is so short lived we don't have to worry
-            // about style thrashing in a print view (where no routing is going to be
-            // happening anyway).
+            var newNode, promise;
+            var existingLink = referenceHrefs.has(href);
 
-            link.setAttribute("media", "print");
+            if (existingLink) {
+              newNode = document.createElement("noscript");
+              newNode.setAttribute("data-n-staging", href);
+              promise = true;
+            } else {
+              var _ref9 = (0, _pageLoader.createLink)(href, "stylesheet"),
+                _ref10 = _slicedToArray(_ref9, 2),
+                link = _ref10[0],
+                onload = _ref10[1];
+
+              link.setAttribute("data-n-staging", ""); // Media `none` does not work in Firefox, so `print` is more
+              // cross-browser. Since this is so short lived we don't have to worry
+              // about style thrashing in a print view (where no routing is going to be
+              // happening anyway).
+
+              link.setAttribute("media", "print");
+              newNode = link;
+              promise = onload;
+            }
 
             if (referenceNode) {
               referenceNode.parentNode.insertBefore(
-                link,
+                newNode,
                 referenceNode.nextSibling
               );
-              referenceNode = link;
+              referenceNode = newNode;
             } else {
-              document.head.appendChild(link);
+              document.head.appendChild(newNode);
             }
 
             return promise;
@@ -1058,17 +1079,40 @@ _N_E = (window["webpackJsonp_N_E"] = window["webpackJsonp_N_E"] || []).push([
 
         function onCommit() {
           if (
-            // We can skip this during hydration. Running it wont cause any harm, but
-            // we may as well save the CPU cycles.
-            !isInitialRender && // We use `style-loader` in development, so we don't need to do anything
+            // We use `style-loader` in development, so we don't need to do anything
             // unless we're in production:
-            true
+            true && // We can skip this during hydration. Running it wont cause any harm, but
+            // we may as well save the CPU cycles:
+            !isInitialRender && // Ensure this render commit owns the currently staged stylesheets:
+            renderPromiseReject === _lastRenderReject
           ) {
-            // Remove old stylesheets:
+            // Remove or relocate old stylesheets:
+            var relocatePlaceholders = [].slice.call(
+              document.querySelectorAll("noscript[data-n-staging]")
+            );
+            var relocateHrefs = relocatePlaceholders.map(function(e) {
+              return e.getAttribute("data-n-staging");
+            });
             [].slice
               .call(document.querySelectorAll("link[data-n-p]"))
               .forEach(function(el) {
-                return el.parentNode.removeChild(el);
+                var currentHref = el.getAttribute("href");
+                var relocateIndex = relocateHrefs.indexOf(currentHref);
+
+                if (relocateIndex !== -1) {
+                  var _placeholderElement$p;
+
+                  var placeholderElement = relocatePlaceholders[relocateIndex];
+                  (_placeholderElement$p = placeholderElement.parentNode) ==
+                  null
+                    ? void 0
+                    : _placeholderElement$p.replaceChild(
+                        el,
+                        placeholderElement
+                      );
+                } else {
+                  el.parentNode.removeChild(el);
+                }
               }); // Activate new stylesheets:
             [].slice
               .call(document.querySelectorAll("link[data-n-staging]"))
Diff for index.html
@@ -6,7 +6,7 @@
     <meta name="next-head-count" content="2" />
     <link
       rel="preload"
-      href="/_next/static/chunks/main-486aa092e8fd438371bc.module.js"
+      href="/_next/static/chunks/main-b77b5828741294ade8ac.module.js"
       as="script"
       crossorigin="anonymous"
     />
@@ -81,13 +81,13 @@
       src="/_next/static/chunks/polyfills-f73ba3fc145972ef83e9.js"
     ></script>
     <script
-      src="/_next/static/chunks/main-7ec0af79f420b45726c4.js"
+      src="/_next/static/chunks/main-194e0334c953e5a791f5.js"
       async=""
       crossorigin="anonymous"
       nomodule=""
     ></script>
     <script
-      src="/_next/static/chunks/main-486aa092e8fd438371bc.module.js"
+      src="/_next/static/chunks/main-b77b5828741294ade8ac.module.js"
       async=""
       crossorigin="anonymous"
       type="module"
Diff for link.html
@@ -6,7 +6,7 @@
     <meta name="next-head-count" content="2" />
     <link
       rel="preload"
-      href="/_next/static/chunks/main-486aa092e8fd438371bc.module.js"
+      href="/_next/static/chunks/main-b77b5828741294ade8ac.module.js"
       as="script"
       crossorigin="anonymous"
     />
@@ -86,13 +86,13 @@
       src="/_next/static/chunks/polyfills-f73ba3fc145972ef83e9.js"
     ></script>
     <script
-      src="/_next/static/chunks/main-7ec0af79f420b45726c4.js"
+      src="/_next/static/chunks/main-194e0334c953e5a791f5.js"
       async=""
       crossorigin="anonymous"
       nomodule=""
     ></script>
     <script
-      src="/_next/static/chunks/main-486aa092e8fd438371bc.module.js"
+      src="/_next/static/chunks/main-b77b5828741294ade8ac.module.js"
       async=""
       crossorigin="anonymous"
       type="module"
Diff for withRouter.html
@@ -6,7 +6,7 @@
     <meta name="next-head-count" content="2" />
     <link
       rel="preload"
-      href="/_next/static/chunks/main-486aa092e8fd438371bc.module.js"
+      href="/_next/static/chunks/main-b77b5828741294ade8ac.module.js"
       as="script"
       crossorigin="anonymous"
     />
@@ -81,13 +81,13 @@
       src="/_next/static/chunks/polyfills-f73ba3fc145972ef83e9.js"
     ></script>
     <script
-      src="/_next/static/chunks/main-7ec0af79f420b45726c4.js"
+      src="/_next/static/chunks/main-194e0334c953e5a791f5.js"
       async=""
       crossorigin="anonymous"
       nomodule=""
     ></script>
     <script
-      src="/_next/static/chunks/main-486aa092e8fd438371bc.module.js"
+      src="/_next/static/chunks/main-b77b5828741294ade8ac.module.js"
       async=""
       crossorigin="anonymous"
       type="module"

Serverless Mode (Increase detected ⚠️)
General Overall increase ⚠️
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
buildDuration 13.5s 13.7s ⚠️ +194ms
nodeModulesSize 57.5 MB 57.5 MB ⚠️ +3.67 kB
Client Bundles (main, webpack, commons) Overall increase ⚠️
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
677f882d2ed8..7f47.js gzip 10.3 kB 10.3 kB
framework.HASH.js gzip 39 kB 39 kB
main-1338f54..276e.js gzip 7.2 kB N/A N/A
webpack-e067..f178.js gzip 751 B 751 B
main-a898b29..6706.js gzip N/A 7.34 kB N/A
Overall change 57.2 kB 57.4 kB ⚠️ +143 B
Client Bundles (main, webpack, commons) Modern Overall increase ⚠️
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
677f882d2ed8..dule.js gzip 6.15 kB 6.15 kB
framework.HA..dule.js gzip 39 kB 39 kB
main-1455da7..dule.js gzip 6.24 kB N/A N/A
webpack-07c5..dule.js gzip 751 B 751 B
main-0ecc3f9..dule.js gzip N/A 6.39 kB N/A
Overall change 52.1 kB 52.3 kB ⚠️ +149 B
Legacy Client Bundles (polyfills)
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
polyfills-4b..e242.js gzip 31 kB 31 kB
Overall change 31 kB 31 kB
Client Pages
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
_app-9a0b9e1..b37e.js gzip 1.28 kB 1.28 kB
_error-28298..e0c9.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-000f151..65d4.js gzip 1.29 kB 1.29 kB
routerDirect..924c.js gzip 284 B 284 B
withRouter-7..c13d.js gzip 284 B 284 B
Overall change 7.69 kB 7.69 kB
Client Pages Modern
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
_app-75d3a82..dule.js gzip 625 B 625 B
_error-65c8a..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-4cfda7a..dule.js gzip 1.26 kB 1.26 kB
routerDirect..dule.js gzip 284 B 284 B
withRouter-f..dule.js gzip 282 B 282 B
Overall change 5.35 kB 5.35 kB
Client Build Manifests
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
_buildManifest.js gzip 322 B 322 B
_buildManife..dule.js gzip 330 B 330 B
Overall change 652 B 652 B
Serverless bundles
vercel/next.js canary Timer/next.js hotfix/reuse-old-stylesheets Change
_error.js 1.03 MB 1.03 MB
404.html 4.18 kB 4.18 kB
hooks.html 3.82 kB 3.82 kB
index.js 1.03 MB 1.03 MB
link.js 1.07 MB 1.07 MB
routerDirect.js 1.07 MB 1.07 MB
withRouter.js 1.07 MB 1.07 MB
Overall change 5.28 MB 5.28 MB
Commit: cda1727

@kodiakhq kodiakhq bot merged commit 52efe33 into vercel:canary Aug 25, 2020
@Timer Timer deleted the hotfix/reuse-old-stylesheets branch August 25, 2020 15:22
@vercel vercel locked as resolved and limited conversation to collaborators Jan 30, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants