Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changes to the beforeInteractive strategy to make it work for streaming #31936

Merged
merged 53 commits into from Apr 21, 2022

Conversation

janicklas-ralph
Copy link
Contributor

@janicklas-ralph janicklas-ralph commented Nov 29, 2021

Changes to the beforeInteractive strategy to make it work for streaming

Splitting beforeInteractive into two strategies beforeInteractive at the _document level and beforePageRender for page level

@ijjk ijjk added created-by: Chrome Aurora PRs by the Google Chrome team: https://web.dev/aurora type: next labels Nov 29, 2021
@ijjk

This comment has been minimized.

@ijjk

This comment has been minimized.

@ijjk

This comment has been minimized.

@ijjk

This comment has been minimized.

docs/basic-features/script.md Outdated Show resolved Hide resolved
docs/basic-features/script.md Outdated Show resolved Hide resolved
@@ -0,0 +1,51 @@
const path = require('path')
Copy link
Collaborator

Choose a reason for hiding this comment

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

In addition to an ESLint warning, would be good to have a runtime console warning since some people don't use ESLint and this will actually break once streaming is added.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am not sure if theres an easy way to do this. We will have to know the component's parent. I tried using React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner to get that info, but that didn't work. Any advice is appreciated @kara @devknoll

Copy link
Contributor

Choose a reason for hiding this comment

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

@janicklas-ralph Document and App are rendered in separate React trees, so I think you could just reuse the context to determine if we're rendering Document or not and warn appropriately

Copy link
Collaborator

Choose a reason for hiding this comment

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

+1. I think it's OK to put the console warning in a separate PR though (I'm good with merging this one with just the ESLint warning and docs)

Copy link
Collaborator

@housseindjirdeh housseindjirdeh left a comment

Choose a reason for hiding this comment

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

Thanks for doing this! Most of my comments are documentation-related 🙏


- `beforeInteractive`: Load before the page is interactive
- `beforeInteractive`: Load scripts required by the entire site before the page is interactive
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
- `beforeInteractive`: Load scripts required by the entire site before the page is interactive
- `beforeInteractive`: Load script when any page in the application is loaded and before it becomes interactive


- `beforeInteractive`: Load before the page is interactive
- `beforeInteractive`: Load scripts required by the entire site before the page is interactive
- `beforePageRender`: Load scripts required by a particular page before the page is interactive
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
- `beforePageRender`: Load scripts required by a particular page before the page is interactive
- `beforePageRender`: Load script when for a single page before it becomes interactive

- `afterInteractive`: (**default**): Load immediately after the page becomes interactive
- `lazyOnload`: Load during idle time

#### beforeInteractive

Scripts that load with the `beforeInteractive` strategy are injected into the initial HTML from the server and run before self-bundled JavaScript is executed. This strategy should be used for any critical scripts that need to be fetched and executed before the page is interactive.
Scripts that load with the `beforeInteractive` strategy are injected into the initial HTML from the server and run before self-bundled JavaScript is executed. This strategy should be used for any critical scripts that need to be fetched and executed before the page is interactive. This strategy only works inside **\_document.js** and is designed to load scripts that is needed by the entire site.
Copy link
Collaborator

Choose a reason for hiding this comment

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

This strategy only works inside **\_document.js** and is designed to load scripts that is needed by the entire site

Which of the following correct?

  • Script will only load once on a page reload (SSR) and not during page transitions (CSR), but will load when any page is reloaded
  • Script will load during page reload (SSR) and during client side transitions

I assume it's the first option, and if so - can we clarify that a bit here? Something along the lines of:

Suggested change
Scripts that load with the `beforeInteractive` strategy are injected into the initial HTML from the server and run before self-bundled JavaScript is executed. This strategy should be used for any critical scripts that need to be fetched and executed before the page is interactive. This strategy only works inside **\_document.js** and is designed to load scripts that is needed by the entire site.
Scripts that load with the `beforeInteractive` strategy are injected into the initial HTML from the server and run before self-bundled JavaScript is executed. This strategy should be used for any critical scripts that need to be fetched and executed before any page becomes interactive. This strategy only works inside **\_document.js** and is designed to load scripts that is needed by the entire site (i.e. the script will load when any page in the application has been loaded server-side).

<Main />
<NextScript />
<Script
id="scriptBeforeInteractive"
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is the id here necessary? If not, could we remove it to keep the code snippets as short as possible

<NextScript />
<Script
id="scriptBeforeInteractive"
src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js?a=scriptBeforeInteractive"
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm confused about the a=scriptBeforeInteractive queryparam here. Was it included for any particular reason? If not, can we remove it so folks don't get confused thinking that it's a requirement to have? :)

Suggested change
src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js?a=scriptBeforeInteractive"
src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"

```

Examples of scripts that should be loaded as soon as possible with this strategy include:

- Bot detectors
- Cookie consent managers

#### beforePageRender

Scripts that load with the `beforePageRender` strategy are injected into the initial HTML from the server and run before self-bundled JavaScript is executed. This strategy is similar to `beforeInteractive` but is designed for scripts that are needed by a page and not the entire site. Syntax for adding the script is as shown below.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Similarly here, can we clarify that this Script will load only for a page that it has been used in.

Suggested change
Scripts that load with the `beforePageRender` strategy are injected into the initial HTML from the server and run before self-bundled JavaScript is executed. This strategy is similar to `beforeInteractive` but is designed for scripts that are needed by a page and not the entire site. Syntax for adding the script is as shown below.
Scripts that load with the `beforePageRender` strategy are injected into the initial HTML from the server and run before self-bundled JavaScript is executed. This strategy is similar to `beforeInteractive` but is designed for scripts that are needed by a page and not the entire site (i.e. this script will load only when the page that uses it is loaded server-side)

Page.scriptLoader = () => {
return (
<Script
id="scriptBeforePageRender"
Copy link
Collaborator

Choose a reason for hiding this comment

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

Similarly here, can we remove the unnecessary id?

Suggested change
id="scriptBeforePageRender"

return (
<Script
id="scriptBeforePageRender"
src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js?a=scriptBeforePageRender"
Copy link
Collaborator

Choose a reason for hiding this comment

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

Similarly here, can we remove the unnecessary query param?

Suggested change
src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js?a=scriptBeforePageRender"
src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"

@@ -20,6 +20,7 @@ module.exports = {
'no-duplicate-head': require('./rules/no-duplicate-head'),
'inline-script-id': require('./rules/inline-script-id'),
'next-script-for-ga': require('./rules/next-script-for-ga'),
'no-script-bi-outside-document': require('./rules/no-script-bi-outside-document'),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit (feel free to ignore): I think it would be nicer to not shorten beforeInteractive to bi in the naming here. Maybe something like no-before-interactive-script-outside-doument?

@@ -39,12 +40,13 @@ module.exports = {
'@next/next/next-script-for-ga': 1,
'@next/next/no-document-import-in-page': 2,
'@next/next/no-head-import-in-document': 2,
'@next/next/no-script-in-document': 2,
'@next/next/no-script-in-document': 0,
Copy link
Collaborator

Choose a reason for hiding this comment

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

If we're turning off this rule entirely, we should probably just delete it completely (unless you think there's a reason why folks would like to turn it on?)

@ijjk

This comment has been minimized.

@ijjk

This comment has been minimized.

@ijjk
Copy link
Member

ijjk commented Apr 8, 2022

Failing test suites

Commit: 19f9ae1

yarn testheadless test/e2e/next-script-worker-strategy/index.test.ts

  • experimental.nextScriptWorkers: true with required Partytown dependency > Worker scripts are modified by Partytown to execute on a worker thread
Expand output

● experimental.nextScriptWorkers: true with required Partytown dependency › Worker scripts are modified by Partytown to execute on a worker thread

expect(received).toEqual(expected) // deep equality

Expected: 1
Received: 2

  124 |       )
  125 |
> 126 |       expect(predefinedWorkerScripts).toEqual(1)
      |                                       ^
  127 |
  128 |       await waitFor(1000)
  129 |

  at Object.<anonymous> (e2e/next-script-worker-strategy/index.test.ts:126:39)

Read more about building and testing Next.js in contributing.md.

@ijjk
Copy link
Member

ijjk commented Apr 8, 2022

Failing test suites

Commit: 19f9ae1

yarn testheadless test/integration/script-loader/test/index.test.js

  • Next.js Script - Primary Strategies > priority beforeInteractive
  • Next.js Script - Primary Strategies > priority beforeInteractive on navigate
Expand output

● Next.js Script - Primary Strategies › priority beforeInteractive

expect(received).toBe(expected) // Object.is equality

Expected: 1
Received: 0

  118 |
  119 |       // Renders script tag
> 120 |       expect(script.length).toBe(1)
      |                             ^
  121 |       expect(script.attr('data-nscript')).toBeDefined()
  122 |
  123 |       // Script is inserted before NextScripts

  at test (integration/script-loader/test/index.test.js:120:29)
  at Object.<anonymous> (integration/script-loader/test/index.test.js:129:5)

● Next.js Script - Primary Strategies › priority beforeInteractive on navigate

expect(received).toBe(expected) // Object.is equality

Expected: 1
Received: 0

  160 |         '[src$="documentBeforeInteractive"]'
  161 |       )
> 162 |       expect(documentBIScripts.length).toBe(1)
      |                                        ^
  163 |
  164 |       await browser.waitForElementByCss('[href="/page1"]')
  165 |       await browser.click('[href="/page1"]')

  at Object.<anonymous> (integration/script-loader/test/index.test.js:162:40)

Read more about building and testing Next.js in contributing.md.

@ijjk
Copy link
Member

ijjk commented Apr 8, 2022

Failing test suites

Commit: 19f9ae1

yarn testheadless test/e2e/next-script-worker-strategy/index.test.ts

  • experimental.nextScriptWorkers: true with required Partytown dependency > Worker scripts are modified by Partytown to execute on a worker thread
Expand output

● experimental.nextScriptWorkers: true with required Partytown dependency › Worker scripts are modified by Partytown to execute on a worker thread

expect(received).toEqual(expected) // deep equality

Expected: 1
Received: 2

  124 |       )
  125 |
> 126 |       expect(predefinedWorkerScripts).toEqual(1)
      |                                       ^
  127 |
  128 |       await waitFor(1000)
  129 |

  at Object.<anonymous> (e2e/next-script-worker-strategy/index.test.ts:126:39)

Read more about building and testing Next.js in contributing.md.

@ijjk
Copy link
Member

ijjk commented Apr 11, 2022

Stats from current PR

Default Build (Increase detected ⚠️)
General Overall increase ⚠️
vercel/next.js canary janicklas-ralph/next.js script-update Change
buildDuration 17.9s 17.8s -165ms
buildDurationCached 7.2s 6.9s -319ms
nodeModulesSize 484 MB 484 MB ⚠️ +2.5 kB
Page Load Tests Overall increase ✓
vercel/next.js canary janicklas-ralph/next.js script-update Change
/ failed reqs 0 0
/ total time (seconds) 3.786 3.744 -0.04
/ avg req/sec 660.33 667.71 +7.38
/error-in-render failed reqs 0 0
/error-in-render total time (seconds) 1.635 1.602 -0.03
/error-in-render avg req/sec 1528.95 1560.9 +31.95
Client Bundles (main, webpack) Overall increase ⚠️
vercel/next.js canary janicklas-ralph/next.js script-update Change
925.HASH.js gzip 179 B 179 B
framework-HASH.js gzip 42 kB 42 kB
main-HASH.js gzip 28 kB 28.2 kB ⚠️ +187 B
webpack-HASH.js gzip 1.44 kB 1.44 kB
Overall change 71.7 kB 71.9 kB ⚠️ +187 B
Legacy Client Bundles (polyfills)
vercel/next.js canary janicklas-ralph/next.js script-update Change
polyfills-HASH.js gzip 31 kB 31 kB
Overall change 31 kB 31 kB
Client Pages
vercel/next.js canary janicklas-ralph/next.js script-update Change
_app-HASH.js gzip 1.36 kB 1.36 kB
_error-HASH.js gzip 192 B 192 B
amp-HASH.js gzip 309 B 309 B
css-HASH.js gzip 327 B 327 B
dynamic-HASH.js gzip 3.05 kB 3.05 kB
head-HASH.js gzip 351 B 351 B
hooks-HASH.js gzip 920 B 920 B
image-HASH.js gzip 5.68 kB 5.68 kB
index-HASH.js gzip 263 B 263 B
link-HASH.js gzip 2.32 kB 2.32 kB
routerDirect..HASH.js gzip 320 B 320 B
script-HASH.js gzip 387 B 387 B
withRouter-HASH.js gzip 319 B 319 B
85e02e95b279..7e3.css gzip 107 B 107 B
Overall change 15.9 kB 15.9 kB
Client Build Manifests
vercel/next.js canary janicklas-ralph/next.js script-update Change
_buildManifest.js gzip 460 B 460 B
Overall change 460 B 460 B
Rendered Page Sizes Overall increase ⚠️
vercel/next.js canary janicklas-ralph/next.js script-update Change
index.html gzip 531 B 532 B ⚠️ +1 B
link.html gzip 545 B 546 B ⚠️ +1 B
withRouter.html gzip 525 B 526 B ⚠️ +1 B
Overall change 1.6 kB 1.6 kB ⚠️ +3 B

Diffs

Diff for main-HASH.js
@@ -790,9 +790,8 @@
                     if (false) {
                     }
                     if (initialData.scriptLoader) {
-                      initScriptLoader = __webpack_require__(
-                        3573
-                      ) /* .initScriptLoader */.z;
+                      initScriptLoader = __webpack_require__(3573)
+                        .initScriptLoader;
                       initScriptLoader(initialData.scriptLoader);
                     }
                     pageLoader = new _pageLoader.default(
@@ -2826,7 +2825,6 @@
       __webpack_require__
     ) {
       "use strict";
-      var __webpack_unused_export__;
 
       function _arrayLikeToArray(arr, len) {
         if (len == null || len > arr.length) len = arr.length;
@@ -2836,6 +2834,16 @@
       function _arrayWithHoles(arr) {
         if (Array.isArray(arr)) return arr;
       }
+      function _arrayWithoutHoles(arr) {
+        if (Array.isArray(arr)) return _arrayLikeToArray(arr);
+      }
+      function _iterableToArray(iter) {
+        if (
+          (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null) ||
+          iter["@@iterator"] != null
+        )
+          return Array.from(iter);
+      }
       function _iterableToArrayLimit(arr, i) {
         var _i =
           arr == null
@@ -2869,6 +2877,11 @@
           "Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."
         );
       }
+      function _nonIterableSpread() {
+        throw new TypeError(
+          "Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."
+        );
+      }
       function _slicedToArray(arr, i) {
         return (
           _arrayWithHoles(arr) ||
@@ -2877,6 +2890,14 @@
           _nonIterableRest()
         );
       }
+      function _toConsumableArray(arr) {
+        return (
+          _arrayWithoutHoles(arr) ||
+          _iterableToArray(arr) ||
+          _unsupportedIterableToArray(arr) ||
+          _nonIterableSpread()
+        );
+      }
       function _unsupportedIterableToArray(o, minLen) {
         if (!o) return;
         if (typeof o === "string") return _arrayLikeToArray(o, minLen);
@@ -2889,10 +2910,11 @@
         )
           return _arrayLikeToArray(o, minLen);
       }
-      __webpack_unused_export__ = {
+      Object.defineProperty(exports, "__esModule", {
         value: true
-      };
-      exports.z = initScriptLoader;
+      });
+      exports.handleClientScriptLoad = handleClientScriptLoad;
+      exports.initScriptLoader = initScriptLoader;
       exports["default"] = void 0;
       var _react = _interopRequireWildcard(__webpack_require__(7294));
       var _headManagerContext = __webpack_require__(4664);
@@ -3090,14 +3112,14 @@
       function handleClientScriptLoad(props) {
         var _strategy = props.strategy,
           strategy = _strategy === void 0 ? "afterInteractive" : _strategy;
-        if (strategy === "afterInteractive") {
-          loadScript(props);
-        } else if (strategy === "lazyOnload") {
+        if (strategy === "lazyOnload") {
           window.addEventListener("load", function() {
             (0, _requestIdleCallback).requestIdleCallback(function() {
               return loadScript(props);
             });
           });
+        } else {
+          loadScript(props);
         }
       }
       function loadLazyScript(props) {
@@ -3113,8 +3135,22 @@
           });
         }
       }
+      function addBeforeInteractiveToCache() {
+        var scripts = _toConsumableArray(
+          document.querySelectorAll('[data-nscript="beforeInteractive"]')
+        ).concat(
+          _toConsumableArray(
+            document.querySelectorAll('[data-nscript="beforePageRender"]')
+          )
+        );
+        scripts.forEach(function(script) {
+          var cacheKey = script.id || script.getAttribute("src");
+          LoadCache.add(cacheKey);
+        });
+      }
       function initScriptLoader(scriptLoaderItems) {
         scriptLoaderItems.forEach(handleClientScriptLoad);
+        addBeforeInteractiveToCache();
       }
       function Script(props) {
         var _src = props.src,
@@ -4342,6 +4378,7 @@
       exports["default"] = void 0;
       var _normalizeTrailingSlash = __webpack_require__(2700);
       var _routeLoader = __webpack_require__(2497);
+      var _script = __webpack_require__(3573);
       var _isError = _interopRequireWildcard(__webpack_require__(676));
       var _denormalizePagePath = __webpack_require__(4522);
       var _normalizeLocalePath = __webpack_require__(4769);
@@ -5011,6 +5048,8 @@
                     props,
                     __N_SSG,
                     __N_SSP,
+                    component,
+                    scripts,
                     destination,
                     parsedHref,
                     ref3,
@@ -5504,14 +5543,23 @@
                               (props = routeInfo.props),
                               (__N_SSG = routeInfo.__N_SSG),
                               (__N_SSP = routeInfo.__N_SSP);
+                            component = routeInfo.Component;
+                            if (component && component.scriptLoader) {
+                              scripts = [].concat(component.scriptLoader());
+                              scripts.forEach(function(script) {
+                                (0, _script).handleClientScriptLoad(
+                                  script.props
+                                );
+                              });
+                            }
                             if (!((__N_SSG || __N_SSP) && props)) {
-                              _ctx.next = 144;
+                              _ctx.next = 146;
                               break;
                             }
                             if (
                               !(props.pageProps && props.pageProps.__N_REDIRECT)
                             ) {
-                              _ctx.next = 129;
+                              _ctx.next = 131;
                               break;
                             }
                             destination = props.pageProps.__N_REDIRECT;
@@ -5521,7 +5569,7 @@
                                 props.pageProps.__N_REDIRECT_BASE_PATH !== false
                               )
                             ) {
-                              _ctx.next = 127;
+                              _ctx.next = 129;
                               break;
                             }
                             parsedHref = (0,
@@ -5541,31 +5589,31 @@
                               "return",
                               _this.change(method, newUrl, newAs, options)
                             );
-                          case 127:
+                          case 129:
                             window.location.href = destination;
                             return _ctx.abrupt(
                               "return",
                               new Promise(function() {})
                             );
-                          case 129:
+                          case 131:
                             nextState.isPreview = !!props.__N_PREVIEW;
                             if (!(props.notFound === SSG_DATA_NOT_FOUND)) {
-                              _ctx.next = 144;
+                              _ctx.next = 146;
                               break;
                             }
-                            _ctx.prev = 132;
-                            _ctx.next = 135;
+                            _ctx.prev = 134;
+                            _ctx.next = 137;
                             return _this.fetchComponent("/404");
-                          case 135:
+                          case 137:
                             notFoundRoute = "/404";
-                            _ctx.next = 141;
+                            _ctx.next = 143;
                             break;
-                          case 138:
-                            _ctx.prev = 138;
-                            _ctx.t3 = _ctx["catch"](132);
+                          case 140:
+                            _ctx.prev = 140;
+                            _ctx.t3 = _ctx["catch"](134);
                             notFoundRoute = "/_error";
-                          case 141:
-                            _ctx.next = 143;
+                          case 143:
+                            _ctx.next = 145;
                             return _this.getRouteInfo(
                               notFoundRoute,
                               notFoundRoute,
@@ -5578,9 +5626,9 @@
                               nextState.locale,
                               nextState.isPreview
                             );
-                          case 143:
+                          case 145:
                             routeInfo = _ctx.sent;
-                          case 144:
+                          case 146:
                             Router.events.emit(
                               "beforeHistoryChange",
                               as,
@@ -5618,7 +5666,7 @@
                                   y: 0
                                 }
                               : null;
-                            _ctx.next = 153;
+                            _ctx.next = 155;
                             return _this
                               .set(
                                 _objectSpread({}, nextState, {
@@ -5637,9 +5685,9 @@
                                 if (e.cancelled) error = error || e;
                                 else throw e;
                               });
-                          case 153:
+                          case 155:
                             if (!error) {
-                              _ctx.next = 156;
+                              _ctx.next = 158;
                               break;
                             }
                             Router.events.emit(
@@ -5649,7 +5697,7 @@
                               routeProps
                             );
                             throw error;
-                          case 156:
+                          case 158:
                             if (false) {
                             }
                             Router.events.emit(
@@ -5658,8 +5706,8 @@
                               routeProps
                             );
                             return _ctx.abrupt("return", true);
-                          case 161:
-                            _ctx.prev = 161;
+                          case 163:
+                            _ctx.prev = 163;
                             _ctx.t4 = _ctx["catch"](113);
                             if (
                               !(
@@ -5667,13 +5715,13 @@
                                 _ctx.t4.cancelled
                               )
                             ) {
-                              _ctx.next = 165;
+                              _ctx.next = 167;
                               break;
                             }
                             return _ctx.abrupt("return", false);
-                          case 165:
+                          case 167:
                             throw _ctx.t4;
-                          case 166:
+                          case 168:
                           case "end":
                             return _ctx.stop();
                         }
@@ -5682,8 +5730,8 @@
                     null,
                     [
                       [39, 51],
-                      [113, 161],
-                      [132, 138]
+                      [113, 163],
+                      [134, 140]
                     ]
                   );
                 })
Diff for index.html
@@ -19,7 +19,7 @@
       defer=""
     ></script>
     <script
-      src="/_next/static/chunks/main-eb6922b25512ec18.js"
+      src="/_next/static/chunks/main-ee04e351dce28253.js"
       defer=""
     ></script>
     <script
Diff for link.html
@@ -19,7 +19,7 @@
       defer=""
     ></script>
     <script
-      src="/_next/static/chunks/main-eb6922b25512ec18.js"
+      src="/_next/static/chunks/main-ee04e351dce28253.js"
       defer=""
     ></script>
     <script
Diff for withRouter.html
@@ -19,7 +19,7 @@
       defer=""
     ></script>
     <script
-      src="/_next/static/chunks/main-eb6922b25512ec18.js"
+      src="/_next/static/chunks/main-ee04e351dce28253.js"
       defer=""
     ></script>
     <script

Default Build with SWC (Increase detected ⚠️)
General Overall increase ⚠️
vercel/next.js canary janicklas-ralph/next.js script-update Change
buildDuration 20.9s 21.5s ⚠️ +577ms
buildDurationCached 7.2s 7.2s
nodeModulesSize 484 MB 484 MB ⚠️ +2.5 kB
Page Load Tests Overall decrease ⚠️
vercel/next.js canary janicklas-ralph/next.js script-update Change
/ failed reqs 0 0
/ total time (seconds) 3.764 3.751 -0.01
/ avg req/sec 664.22 666.43 +2.21
/error-in-render failed reqs 0 0
/error-in-render total time (seconds) 1.501 1.605 ⚠️ +0.1
/error-in-render avg req/sec 1666.02 1557.87 ⚠️ -108.15
Client Bundles (main, webpack) Overall increase ⚠️
vercel/next.js canary janicklas-ralph/next.js script-update Change
925.HASH.js gzip 178 B 178 B
framework-HASH.js gzip 42.3 kB 42.3 kB
main-HASH.js gzip 28.3 kB 28.5 kB ⚠️ +136 B
webpack-HASH.js gzip 1.45 kB 1.45 kB
Overall change 72.3 kB 72.4 kB ⚠️ +136 B
Legacy Client Bundles (polyfills)
vercel/next.js canary janicklas-ralph/next.js script-update Change
polyfills-HASH.js gzip 31 kB 31 kB
Overall change 31 kB 31 kB
Client Pages
vercel/next.js canary janicklas-ralph/next.js script-update Change
_app-HASH.js gzip 1.35 kB 1.35 kB
_error-HASH.js gzip 179 B 179 B
amp-HASH.js gzip 313 B 313 B
css-HASH.js gzip 325 B 325 B
dynamic-HASH.js gzip 3.03 kB 3.03 kB
head-HASH.js gzip 351 B 351 B
hooks-HASH.js gzip 921 B 921 B
image-HASH.js gzip 5.74 kB 5.74 kB
index-HASH.js gzip 261 B 261 B
link-HASH.js gzip 2.38 kB 2.38 kB
routerDirect..HASH.js gzip 322 B 322 B
script-HASH.js gzip 388 B 388 B
withRouter-HASH.js gzip 317 B 317 B
85e02e95b279..7e3.css gzip 107 B 107 B
Overall change 16 kB 16 kB
Client Build Manifests
vercel/next.js canary janicklas-ralph/next.js script-update Change
_buildManifest.js gzip 459 B 459 B
Overall change 459 B 459 B
Rendered Page Sizes
vercel/next.js canary janicklas-ralph/next.js script-update Change
index.html gzip 532 B 532 B
link.html gzip 545 B 545 B
withRouter.html gzip 527 B 527 B
Overall change 1.6 kB 1.6 kB

Diffs

Diff for main-HASH.js
@@ -790,9 +790,8 @@
                     if (false) {
                     }
                     if (initialData.scriptLoader) {
-                      initScriptLoader = __webpack_require__(
-                        3573
-                      ) /* .initScriptLoader */.z;
+                      initScriptLoader = __webpack_require__(3573)
+                        .initScriptLoader;
                       initScriptLoader(initialData.scriptLoader);
                     }
                     pageLoader = new _pageLoader.default(
@@ -2826,7 +2825,6 @@
       __webpack_require__
     ) {
       "use strict";
-      var __webpack_unused_export__;
 
       function _arrayLikeToArray(arr, len) {
         if (len == null || len > arr.length) len = arr.length;
@@ -2836,6 +2834,16 @@
       function _arrayWithHoles(arr) {
         if (Array.isArray(arr)) return arr;
       }
+      function _arrayWithoutHoles(arr) {
+        if (Array.isArray(arr)) return _arrayLikeToArray(arr);
+      }
+      function _iterableToArray(iter) {
+        if (
+          (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null) ||
+          iter["@@iterator"] != null
+        )
+          return Array.from(iter);
+      }
       function _iterableToArrayLimit(arr, i) {
         var _i =
           arr == null
@@ -2869,6 +2877,11 @@
           "Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."
         );
       }
+      function _nonIterableSpread() {
+        throw new TypeError(
+          "Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."
+        );
+      }
       function _slicedToArray(arr, i) {
         return (
           _arrayWithHoles(arr) ||
@@ -2877,6 +2890,14 @@
           _nonIterableRest()
         );
       }
+      function _toConsumableArray(arr) {
+        return (
+          _arrayWithoutHoles(arr) ||
+          _iterableToArray(arr) ||
+          _unsupportedIterableToArray(arr) ||
+          _nonIterableSpread()
+        );
+      }
       function _unsupportedIterableToArray(o, minLen) {
         if (!o) return;
         if (typeof o === "string") return _arrayLikeToArray(o, minLen);
@@ -2889,10 +2910,11 @@
         )
           return _arrayLikeToArray(o, minLen);
       }
-      __webpack_unused_export__ = {
+      Object.defineProperty(exports, "__esModule", {
         value: true
-      };
-      exports.z = initScriptLoader;
+      });
+      exports.handleClientScriptLoad = handleClientScriptLoad;
+      exports.initScriptLoader = initScriptLoader;
       exports["default"] = void 0;
       var _react = _interopRequireWildcard(__webpack_require__(7294));
       var _headManagerContext = __webpack_require__(4664);
@@ -3090,14 +3112,14 @@
       function handleClientScriptLoad(props) {
         var _strategy = props.strategy,
           strategy = _strategy === void 0 ? "afterInteractive" : _strategy;
-        if (strategy === "afterInteractive") {
-          loadScript(props);
-        } else if (strategy === "lazyOnload") {
+        if (strategy === "lazyOnload") {
           window.addEventListener("load", function() {
             (0, _requestIdleCallback).requestIdleCallback(function() {
               return loadScript(props);
             });
           });
+        } else {
+          loadScript(props);
         }
       }
       function loadLazyScript(props) {
@@ -3113,8 +3135,22 @@
           });
         }
       }
+      function addBeforeInteractiveToCache() {
+        var scripts = _toConsumableArray(
+          document.querySelectorAll('[data-nscript="beforeInteractive"]')
+        ).concat(
+          _toConsumableArray(
+            document.querySelectorAll('[data-nscript="beforePageRender"]')
+          )
+        );
+        scripts.forEach(function(script) {
+          var cacheKey = script.id || script.getAttribute("src");
+          LoadCache.add(cacheKey);
+        });
+      }
       function initScriptLoader(scriptLoaderItems) {
         scriptLoaderItems.forEach(handleClientScriptLoad);
+        addBeforeInteractiveToCache();
       }
       function Script(props) {
         var _src = props.src,
@@ -4342,6 +4378,7 @@
       exports["default"] = void 0;
       var _normalizeTrailingSlash = __webpack_require__(2700);
       var _routeLoader = __webpack_require__(2497);
+      var _script = __webpack_require__(3573);
       var _isError = _interopRequireWildcard(__webpack_require__(676));
       var _denormalizePagePath = __webpack_require__(4522);
       var _normalizeLocalePath = __webpack_require__(4769);
@@ -5011,6 +5048,8 @@
                     props,
                     __N_SSG,
                     __N_SSP,
+                    component,
+                    scripts,
                     destination,
                     parsedHref,
                     ref3,
@@ -5504,14 +5543,23 @@
                               (props = routeInfo.props),
                               (__N_SSG = routeInfo.__N_SSG),
                               (__N_SSP = routeInfo.__N_SSP);
+                            component = routeInfo.Component;
+                            if (component && component.scriptLoader) {
+                              scripts = [].concat(component.scriptLoader());
+                              scripts.forEach(function(script) {
+                                (0, _script).handleClientScriptLoad(
+                                  script.props
+                                );
+                              });
+                            }
                             if (!((__N_SSG || __N_SSP) && props)) {
-                              _ctx.next = 144;
+                              _ctx.next = 146;
                               break;
                             }
                             if (
                               !(props.pageProps && props.pageProps.__N_REDIRECT)
                             ) {
-                              _ctx.next = 129;
+                              _ctx.next = 131;
                               break;
                             }
                             destination = props.pageProps.__N_REDIRECT;
@@ -5521,7 +5569,7 @@
                                 props.pageProps.__N_REDIRECT_BASE_PATH !== false
                               )
                             ) {
-                              _ctx.next = 127;
+                              _ctx.next = 129;
                               break;
                             }
                             parsedHref = (0,
@@ -5541,31 +5589,31 @@
                               "return",
                               _this.change(method, newUrl, newAs, options)
                             );
-                          case 127:
+                          case 129:
                             window.location.href = destination;
                             return _ctx.abrupt(
                               "return",
                               new Promise(function() {})
                             );
-                          case 129:
+                          case 131:
                             nextState.isPreview = !!props.__N_PREVIEW;
                             if (!(props.notFound === SSG_DATA_NOT_FOUND)) {
-                              _ctx.next = 144;
+                              _ctx.next = 146;
                               break;
                             }
-                            _ctx.prev = 132;
-                            _ctx.next = 135;
+                            _ctx.prev = 134;
+                            _ctx.next = 137;
                             return _this.fetchComponent("/404");
-                          case 135:
+                          case 137:
                             notFoundRoute = "/404";
-                            _ctx.next = 141;
+                            _ctx.next = 143;
                             break;
-                          case 138:
-                            _ctx.prev = 138;
-                            _ctx.t3 = _ctx["catch"](132);
+                          case 140:
+                            _ctx.prev = 140;
+                            _ctx.t3 = _ctx["catch"](134);
                             notFoundRoute = "/_error";
-                          case 141:
-                            _ctx.next = 143;
+                          case 143:
+                            _ctx.next = 145;
                             return _this.getRouteInfo(
                               notFoundRoute,
                               notFoundRoute,
@@ -5578,9 +5626,9 @@
                               nextState.locale,
                               nextState.isPreview
                             );
-                          case 143:
+                          case 145:
                             routeInfo = _ctx.sent;
-                          case 144:
+                          case 146:
                             Router.events.emit(
                               "beforeHistoryChange",
                               as,
@@ -5618,7 +5666,7 @@
                                   y: 0
                                 }
                               : null;
-                            _ctx.next = 153;
+                            _ctx.next = 155;
                             return _this
                               .set(
                                 _objectSpread({}, nextState, {
@@ -5637,9 +5685,9 @@
                                 if (e.cancelled) error = error || e;
                                 else throw e;
                               });
-                          case 153:
+                          case 155:
                             if (!error) {
-                              _ctx.next = 156;
+                              _ctx.next = 158;
                               break;
                             }
                             Router.events.emit(
@@ -5649,7 +5697,7 @@
                               routeProps
                             );
                             throw error;
-                          case 156:
+                          case 158:
                             if (false) {
                             }
                             Router.events.emit(
@@ -5658,8 +5706,8 @@
                               routeProps
                             );
                             return _ctx.abrupt("return", true);
-                          case 161:
-                            _ctx.prev = 161;
+                          case 163:
+                            _ctx.prev = 163;
                             _ctx.t4 = _ctx["catch"](113);
                             if (
                               !(
@@ -5667,13 +5715,13 @@
                                 _ctx.t4.cancelled
                               )
                             ) {
-                              _ctx.next = 165;
+                              _ctx.next = 167;
                               break;
                             }
                             return _ctx.abrupt("return", false);
-                          case 165:
+                          case 167:
                             throw _ctx.t4;
-                          case 166:
+                          case 168:
                           case "end":
                             return _ctx.stop();
                         }
@@ -5682,8 +5730,8 @@
                     null,
                     [
                       [39, 51],
-                      [113, 161],
-                      [132, 138]
+                      [113, 163],
+                      [134, 140]
                     ]
                   );
                 })
Diff for index.html
@@ -19,7 +19,7 @@
       defer=""
     ></script>
     <script
-      src="/_next/static/chunks/main-eb6922b25512ec18.js"
+      src="/_next/static/chunks/main-ee04e351dce28253.js"
       defer=""
     ></script>
     <script
Diff for link.html
@@ -19,7 +19,7 @@
       defer=""
     ></script>
     <script
-      src="/_next/static/chunks/main-eb6922b25512ec18.js"
+      src="/_next/static/chunks/main-ee04e351dce28253.js"
       defer=""
     ></script>
     <script
Diff for withRouter.html
@@ -19,7 +19,7 @@
       defer=""
     ></script>
     <script
-      src="/_next/static/chunks/main-eb6922b25512ec18.js"
+      src="/_next/static/chunks/main-ee04e351dce28253.js"
       defer=""
     ></script>
     <script
Commit: c6e2f2f

@ijjk
Copy link
Member

ijjk commented Apr 11, 2022

Stats from current PR

Default Build (Increase detected ⚠️)
General Overall increase ⚠️
vercel/next.js canary janicklas-ralph/next.js script-update Change
buildDuration 16.7s 17.1s ⚠️ +342ms
buildDurationCached 6.7s 6.6s -39ms
nodeModulesSize 484 MB 484 MB ⚠️ +2.5 kB
Page Load Tests Overall decrease ⚠️
vercel/next.js canary janicklas-ralph/next.js script-update Change
/ failed reqs 0 0
/ total time (seconds) 3.536 3.633 ⚠️ +0.1
/ avg req/sec 706.95 688.22 ⚠️ -18.73
/error-in-render failed reqs 0 0
/error-in-render total time (seconds) 1.461 1.513 ⚠️ +0.05
/error-in-render avg req/sec 1711.5 1652.63 ⚠️ -58.87
Client Bundles (main, webpack) Overall increase ⚠️
vercel/next.js canary janicklas-ralph/next.js script-update Change
925.HASH.js gzip 179 B 179 B
framework-HASH.js gzip 42 kB 42 kB
main-HASH.js gzip 28 kB 28.2 kB ⚠️ +187 B
webpack-HASH.js gzip 1.44 kB 1.44 kB
Overall change 71.7 kB 71.9 kB ⚠️ +187 B
Legacy Client Bundles (polyfills)
vercel/next.js canary janicklas-ralph/next.js script-update Change
polyfills-HASH.js gzip 31 kB 31 kB
Overall change 31 kB 31 kB
Client Pages
vercel/next.js canary janicklas-ralph/next.js script-update Change
_app-HASH.js gzip 1.36 kB 1.36 kB
_error-HASH.js gzip 192 B 192 B
amp-HASH.js gzip 309 B 309 B
css-HASH.js gzip 327 B 327 B
dynamic-HASH.js gzip 3.05 kB 3.05 kB
head-HASH.js gzip 351 B 351 B
hooks-HASH.js gzip 920 B 920 B
image-HASH.js gzip 5.68 kB 5.68 kB
index-HASH.js gzip 263 B 263 B
link-HASH.js gzip 2.32 kB 2.32 kB
routerDirect..HASH.js gzip 320 B 320 B
script-HASH.js gzip 387 B 387 B
withRouter-HASH.js gzip 319 B 319 B
85e02e95b279..7e3.css gzip 107 B 107 B
Overall change 15.9 kB 15.9 kB
Client Build Manifests
vercel/next.js canary janicklas-ralph/next.js script-update Change
_buildManifest.js gzip 460 B 460 B
Overall change 460 B 460 B
Rendered Page Sizes Overall increase ⚠️
vercel/next.js canary janicklas-ralph/next.js script-update Change
index.html gzip 531 B 532 B ⚠️ +1 B
link.html gzip 545 B 546 B ⚠️ +1 B
withRouter.html gzip 525 B 526 B ⚠️ +1 B
Overall change 1.6 kB 1.6 kB ⚠️ +3 B

Diffs

Diff for main-HASH.js
@@ -790,9 +790,8 @@
                     if (false) {
                     }
                     if (initialData.scriptLoader) {
-                      initScriptLoader = __webpack_require__(
-                        3573
-                      ) /* .initScriptLoader */.z;
+                      initScriptLoader = __webpack_require__(3573)
+                        .initScriptLoader;
                       initScriptLoader(initialData.scriptLoader);
                     }
                     pageLoader = new _pageLoader.default(
@@ -2826,7 +2825,6 @@
       __webpack_require__
     ) {
       "use strict";
-      var __webpack_unused_export__;
 
       function _arrayLikeToArray(arr, len) {
         if (len == null || len > arr.length) len = arr.length;
@@ -2836,6 +2834,16 @@
       function _arrayWithHoles(arr) {
         if (Array.isArray(arr)) return arr;
       }
+      function _arrayWithoutHoles(arr) {
+        if (Array.isArray(arr)) return _arrayLikeToArray(arr);
+      }
+      function _iterableToArray(iter) {
+        if (
+          (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null) ||
+          iter["@@iterator"] != null
+        )
+          return Array.from(iter);
+      }
       function _iterableToArrayLimit(arr, i) {
         var _i =
           arr == null
@@ -2869,6 +2877,11 @@
           "Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."
         );
       }
+      function _nonIterableSpread() {
+        throw new TypeError(
+          "Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."
+        );
+      }
       function _slicedToArray(arr, i) {
         return (
           _arrayWithHoles(arr) ||
@@ -2877,6 +2890,14 @@
           _nonIterableRest()
         );
       }
+      function _toConsumableArray(arr) {
+        return (
+          _arrayWithoutHoles(arr) ||
+          _iterableToArray(arr) ||
+          _unsupportedIterableToArray(arr) ||
+          _nonIterableSpread()
+        );
+      }
       function _unsupportedIterableToArray(o, minLen) {
         if (!o) return;
         if (typeof o === "string") return _arrayLikeToArray(o, minLen);
@@ -2889,10 +2910,11 @@
         )
           return _arrayLikeToArray(o, minLen);
       }
-      __webpack_unused_export__ = {
+      Object.defineProperty(exports, "__esModule", {
         value: true
-      };
-      exports.z = initScriptLoader;
+      });
+      exports.handleClientScriptLoad = handleClientScriptLoad;
+      exports.initScriptLoader = initScriptLoader;
       exports["default"] = void 0;
       var _react = _interopRequireWildcard(__webpack_require__(7294));
       var _headManagerContext = __webpack_require__(4664);
@@ -3090,14 +3112,14 @@
       function handleClientScriptLoad(props) {
         var _strategy = props.strategy,
           strategy = _strategy === void 0 ? "afterInteractive" : _strategy;
-        if (strategy === "afterInteractive") {
-          loadScript(props);
-        } else if (strategy === "lazyOnload") {
+        if (strategy === "lazyOnload") {
           window.addEventListener("load", function() {
             (0, _requestIdleCallback).requestIdleCallback(function() {
               return loadScript(props);
             });
           });
+        } else {
+          loadScript(props);
         }
       }
       function loadLazyScript(props) {
@@ -3113,8 +3135,22 @@
           });
         }
       }
+      function addBeforeInteractiveToCache() {
+        var scripts = _toConsumableArray(
+          document.querySelectorAll('[data-nscript="beforeInteractive"]')
+        ).concat(
+          _toConsumableArray(
+            document.querySelectorAll('[data-nscript="beforePageRender"]')
+          )
+        );
+        scripts.forEach(function(script) {
+          var cacheKey = script.id || script.getAttribute("src");
+          LoadCache.add(cacheKey);
+        });
+      }
       function initScriptLoader(scriptLoaderItems) {
         scriptLoaderItems.forEach(handleClientScriptLoad);
+        addBeforeInteractiveToCache();
       }
       function Script(props) {
         var _src = props.src,
@@ -4342,6 +4378,7 @@
       exports["default"] = void 0;
       var _normalizeTrailingSlash = __webpack_require__(2700);
       var _routeLoader = __webpack_require__(2497);
+      var _script = __webpack_require__(3573);
       var _isError = _interopRequireWildcard(__webpack_require__(676));
       var _denormalizePagePath = __webpack_require__(4522);
       var _normalizeLocalePath = __webpack_require__(4769);
@@ -5011,6 +5048,8 @@
                     props,
                     __N_SSG,
                     __N_SSP,
+                    component,
+                    scripts,
                     destination,
                     parsedHref,
                     ref3,
@@ -5504,14 +5543,23 @@
                               (props = routeInfo.props),
                               (__N_SSG = routeInfo.__N_SSG),
                               (__N_SSP = routeInfo.__N_SSP);
+                            component = routeInfo.Component;
+                            if (component && component.scriptLoader) {
+                              scripts = [].concat(component.scriptLoader());
+                              scripts.forEach(function(script) {
+                                (0, _script).handleClientScriptLoad(
+                                  script.props
+                                );
+                              });
+                            }
                             if (!((__N_SSG || __N_SSP) && props)) {
-                              _ctx.next = 144;
+                              _ctx.next = 146;
                               break;
                             }
                             if (
                               !(props.pageProps && props.pageProps.__N_REDIRECT)
                             ) {
-                              _ctx.next = 129;
+                              _ctx.next = 131;
                               break;
                             }
                             destination = props.pageProps.__N_REDIRECT;
@@ -5521,7 +5569,7 @@
                                 props.pageProps.__N_REDIRECT_BASE_PATH !== false
                               )
                             ) {
-                              _ctx.next = 127;
+                              _ctx.next = 129;
                               break;
                             }
                             parsedHref = (0,
@@ -5541,31 +5589,31 @@
                               "return",
                               _this.change(method, newUrl, newAs, options)
                             );
-                          case 127:
+                          case 129:
                             window.location.href = destination;
                             return _ctx.abrupt(
                               "return",
                               new Promise(function() {})
                             );
-                          case 129:
+                          case 131:
                             nextState.isPreview = !!props.__N_PREVIEW;
                             if (!(props.notFound === SSG_DATA_NOT_FOUND)) {
-                              _ctx.next = 144;
+                              _ctx.next = 146;
                               break;
                             }
-                            _ctx.prev = 132;
-                            _ctx.next = 135;
+                            _ctx.prev = 134;
+                            _ctx.next = 137;
                             return _this.fetchComponent("/404");
-                          case 135:
+                          case 137:
                             notFoundRoute = "/404";
-                            _ctx.next = 141;
+                            _ctx.next = 143;
                             break;
-                          case 138:
-                            _ctx.prev = 138;
-                            _ctx.t3 = _ctx["catch"](132);
+                          case 140:
+                            _ctx.prev = 140;
+                            _ctx.t3 = _ctx["catch"](134);
                             notFoundRoute = "/_error";
-                          case 141:
-                            _ctx.next = 143;
+                          case 143:
+                            _ctx.next = 145;
                             return _this.getRouteInfo(
                               notFoundRoute,
                               notFoundRoute,
@@ -5578,9 +5626,9 @@
                               nextState.locale,
                               nextState.isPreview
                             );
-                          case 143:
+                          case 145:
                             routeInfo = _ctx.sent;
-                          case 144:
+                          case 146:
                             Router.events.emit(
                               "beforeHistoryChange",
                               as,
@@ -5618,7 +5666,7 @@
                                   y: 0
                                 }
                               : null;
-                            _ctx.next = 153;
+                            _ctx.next = 155;
                             return _this
                               .set(
                                 _objectSpread({}, nextState, {
@@ -5637,9 +5685,9 @@
                                 if (e.cancelled) error = error || e;
                                 else throw e;
                               });
-                          case 153:
+                          case 155:
                             if (!error) {
-                              _ctx.next = 156;
+                              _ctx.next = 158;
                               break;
                             }
                             Router.events.emit(
@@ -5649,7 +5697,7 @@
                               routeProps
                             );
                             throw error;
-                          case 156:
+                          case 158:
                             if (false) {
                             }
                             Router.events.emit(
@@ -5658,8 +5706,8 @@
                               routeProps
                             );
                             return _ctx.abrupt("return", true);
-                          case 161:
-                            _ctx.prev = 161;
+                          case 163:
+                            _ctx.prev = 163;
                             _ctx.t4 = _ctx["catch"](113);
                             if (
                               !(
@@ -5667,13 +5715,13 @@
                                 _ctx.t4.cancelled
                               )
                             ) {
-                              _ctx.next = 165;
+                              _ctx.next = 167;
                               break;
                             }
                             return _ctx.abrupt("return", false);
-                          case 165:
+                          case 167:
                             throw _ctx.t4;
-                          case 166:
+                          case 168:
                           case "end":
                             return _ctx.stop();
                         }
@@ -5682,8 +5730,8 @@
                     null,
                     [
                       [39, 51],
-                      [113, 161],
-                      [132, 138]
+                      [113, 163],
+                      [134, 140]
                     ]
                   );
                 })
Diff for index.html
@@ -19,7 +19,7 @@
       defer=""
     ></script>
     <script
-      src="/_next/static/chunks/main-eb6922b25512ec18.js"
+      src="/_next/static/chunks/main-ee04e351dce28253.js"
       defer=""
     ></script>
     <script
Diff for link.html
@@ -19,7 +19,7 @@
       defer=""
     ></script>
     <script
-      src="/_next/static/chunks/main-eb6922b25512ec18.js"
+      src="/_next/static/chunks/main-ee04e351dce28253.js"
       defer=""
     ></script>
     <script
Diff for withRouter.html
@@ -19,7 +19,7 @@
       defer=""
     ></script>
     <script
-      src="/_next/static/chunks/main-eb6922b25512ec18.js"
+      src="/_next/static/chunks/main-ee04e351dce28253.js"
       defer=""
     ></script>
     <script

Default Build with SWC (Increase detected ⚠️)
General Overall increase ⚠️
vercel/next.js canary janicklas-ralph/next.js script-update Change
buildDuration 20.6s 21s ⚠️ +439ms
buildDurationCached 7s 6.6s -425ms
nodeModulesSize 484 MB 484 MB ⚠️ +2.5 kB
Page Load Tests Overall increase ✓
vercel/next.js canary janicklas-ralph/next.js script-update Change
/ failed reqs 0 0
/ total time (seconds) 3.69 3.66 -0.03
/ avg req/sec 677.57 683.06 +5.49
/error-in-render failed reqs 0 0
/error-in-render total time (seconds) 1.562 1.514 -0.05
/error-in-render avg req/sec 1600.81 1651.01 +50.2
Client Bundles (main, webpack) Overall increase ⚠️
vercel/next.js canary janicklas-ralph/next.js script-update Change
925.HASH.js gzip 178 B 178 B
framework-HASH.js gzip 42.3 kB 42.3 kB
main-HASH.js gzip 28.3 kB 28.5 kB ⚠️ +136 B
webpack-HASH.js gzip 1.45 kB 1.45 kB
Overall change 72.3 kB 72.4 kB ⚠️ +136 B
Legacy Client Bundles (polyfills)
vercel/next.js canary janicklas-ralph/next.js script-update Change
polyfills-HASH.js gzip 31 kB 31 kB
Overall change 31 kB 31 kB
Client Pages
vercel/next.js canary janicklas-ralph/next.js script-update Change
_app-HASH.js gzip 1.35 kB 1.35 kB
_error-HASH.js gzip 179 B 179 B
amp-HASH.js gzip 313 B 313 B
css-HASH.js gzip 325 B 325 B
dynamic-HASH.js gzip 3.03 kB 3.03 kB
head-HASH.js gzip 351 B 351 B
hooks-HASH.js gzip 921 B 921 B
image-HASH.js gzip 5.74 kB 5.74 kB
index-HASH.js gzip 261 B 261 B
link-HASH.js gzip 2.38 kB 2.38 kB
routerDirect..HASH.js gzip 322 B 322 B
script-HASH.js gzip 388 B 388 B
withRouter-HASH.js gzip 317 B 317 B
85e02e95b279..7e3.css gzip 107 B 107 B
Overall change 16 kB 16 kB
Client Build Manifests
vercel/next.js canary janicklas-ralph/next.js script-update Change
_buildManifest.js gzip 459 B 459 B
Overall change 459 B 459 B
Rendered Page Sizes
vercel/next.js canary janicklas-ralph/next.js script-update Change
index.html gzip 532 B 532 B
link.html gzip 545 B 545 B
withRouter.html gzip 527 B 527 B
Overall change 1.6 kB 1.6 kB

Diffs

Diff for main-HASH.js
@@ -790,9 +790,8 @@
                     if (false) {
                     }
                     if (initialData.scriptLoader) {
-                      initScriptLoader = __webpack_require__(
-                        3573
-                      ) /* .initScriptLoader */.z;
+                      initScriptLoader = __webpack_require__(3573)
+                        .initScriptLoader;
                       initScriptLoader(initialData.scriptLoader);
                     }
                     pageLoader = new _pageLoader.default(
@@ -2826,7 +2825,6 @@
       __webpack_require__
     ) {
       "use strict";
-      var __webpack_unused_export__;
 
       function _arrayLikeToArray(arr, len) {
         if (len == null || len > arr.length) len = arr.length;
@@ -2836,6 +2834,16 @@
       function _arrayWithHoles(arr) {
         if (Array.isArray(arr)) return arr;
       }
+      function _arrayWithoutHoles(arr) {
+        if (Array.isArray(arr)) return _arrayLikeToArray(arr);
+      }
+      function _iterableToArray(iter) {
+        if (
+          (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null) ||
+          iter["@@iterator"] != null
+        )
+          return Array.from(iter);
+      }
       function _iterableToArrayLimit(arr, i) {
         var _i =
           arr == null
@@ -2869,6 +2877,11 @@
           "Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."
         );
       }
+      function _nonIterableSpread() {
+        throw new TypeError(
+          "Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."
+        );
+      }
       function _slicedToArray(arr, i) {
         return (
           _arrayWithHoles(arr) ||
@@ -2877,6 +2890,14 @@
           _nonIterableRest()
         );
       }
+      function _toConsumableArray(arr) {
+        return (
+          _arrayWithoutHoles(arr) ||
+          _iterableToArray(arr) ||
+          _unsupportedIterableToArray(arr) ||
+          _nonIterableSpread()
+        );
+      }
       function _unsupportedIterableToArray(o, minLen) {
         if (!o) return;
         if (typeof o === "string") return _arrayLikeToArray(o, minLen);
@@ -2889,10 +2910,11 @@
         )
           return _arrayLikeToArray(o, minLen);
       }
-      __webpack_unused_export__ = {
+      Object.defineProperty(exports, "__esModule", {
         value: true
-      };
-      exports.z = initScriptLoader;
+      });
+      exports.handleClientScriptLoad = handleClientScriptLoad;
+      exports.initScriptLoader = initScriptLoader;
       exports["default"] = void 0;
       var _react = _interopRequireWildcard(__webpack_require__(7294));
       var _headManagerContext = __webpack_require__(4664);
@@ -3090,14 +3112,14 @@
       function handleClientScriptLoad(props) {
         var _strategy = props.strategy,
           strategy = _strategy === void 0 ? "afterInteractive" : _strategy;
-        if (strategy === "afterInteractive") {
-          loadScript(props);
-        } else if (strategy === "lazyOnload") {
+        if (strategy === "lazyOnload") {
           window.addEventListener("load", function() {
             (0, _requestIdleCallback).requestIdleCallback(function() {
               return loadScript(props);
             });
           });
+        } else {
+          loadScript(props);
         }
       }
       function loadLazyScript(props) {
@@ -3113,8 +3135,22 @@
           });
         }
       }
+      function addBeforeInteractiveToCache() {
+        var scripts = _toConsumableArray(
+          document.querySelectorAll('[data-nscript="beforeInteractive"]')
+        ).concat(
+          _toConsumableArray(
+            document.querySelectorAll('[data-nscript="beforePageRender"]')
+          )
+        );
+        scripts.forEach(function(script) {
+          var cacheKey = script.id || script.getAttribute("src");
+          LoadCache.add(cacheKey);
+        });
+      }
       function initScriptLoader(scriptLoaderItems) {
         scriptLoaderItems.forEach(handleClientScriptLoad);
+        addBeforeInteractiveToCache();
       }
       function Script(props) {
         var _src = props.src,
@@ -4342,6 +4378,7 @@
       exports["default"] = void 0;
       var _normalizeTrailingSlash = __webpack_require__(2700);
       var _routeLoader = __webpack_require__(2497);
+      var _script = __webpack_require__(3573);
       var _isError = _interopRequireWildcard(__webpack_require__(676));
       var _denormalizePagePath = __webpack_require__(4522);
       var _normalizeLocalePath = __webpack_require__(4769);
@@ -5011,6 +5048,8 @@
                     props,
                     __N_SSG,
                     __N_SSP,
+                    component,
+                    scripts,
                     destination,
                     parsedHref,
                     ref3,
@@ -5504,14 +5543,23 @@
                               (props = routeInfo.props),
                               (__N_SSG = routeInfo.__N_SSG),
                               (__N_SSP = routeInfo.__N_SSP);
+                            component = routeInfo.Component;
+                            if (component && component.scriptLoader) {
+                              scripts = [].concat(component.scriptLoader());
+                              scripts.forEach(function(script) {
+                                (0, _script).handleClientScriptLoad(
+                                  script.props
+                                );
+                              });
+                            }
                             if (!((__N_SSG || __N_SSP) && props)) {
-                              _ctx.next = 144;
+                              _ctx.next = 146;
                               break;
                             }
                             if (
                               !(props.pageProps && props.pageProps.__N_REDIRECT)
                             ) {
-                              _ctx.next = 129;
+                              _ctx.next = 131;
                               break;
                             }
                             destination = props.pageProps.__N_REDIRECT;
@@ -5521,7 +5569,7 @@
                                 props.pageProps.__N_REDIRECT_BASE_PATH !== false
                               )
                             ) {
-                              _ctx.next = 127;
+                              _ctx.next = 129;
                               break;
                             }
                             parsedHref = (0,
@@ -5541,31 +5589,31 @@
                               "return",
                               _this.change(method, newUrl, newAs, options)
                             );
-                          case 127:
+                          case 129:
                             window.location.href = destination;
                             return _ctx.abrupt(
                               "return",
                               new Promise(function() {})
                             );
-                          case 129:
+                          case 131:
                             nextState.isPreview = !!props.__N_PREVIEW;
                             if (!(props.notFound === SSG_DATA_NOT_FOUND)) {
-                              _ctx.next = 144;
+                              _ctx.next = 146;
                               break;
                             }
-                            _ctx.prev = 132;
-                            _ctx.next = 135;
+                            _ctx.prev = 134;
+                            _ctx.next = 137;
                             return _this.fetchComponent("/404");
-                          case 135:
+                          case 137:
                             notFoundRoute = "/404";
-                            _ctx.next = 141;
+                            _ctx.next = 143;
                             break;
-                          case 138:
-                            _ctx.prev = 138;
-                            _ctx.t3 = _ctx["catch"](132);
+                          case 140:
+                            _ctx.prev = 140;
+                            _ctx.t3 = _ctx["catch"](134);
                             notFoundRoute = "/_error";
-                          case 141:
-                            _ctx.next = 143;
+                          case 143:
+                            _ctx.next = 145;
                             return _this.getRouteInfo(
                               notFoundRoute,
                               notFoundRoute,
@@ -5578,9 +5626,9 @@
                               nextState.locale,
                               nextState.isPreview
                             );
-                          case 143:
+                          case 145:
                             routeInfo = _ctx.sent;
-                          case 144:
+                          case 146:
                             Router.events.emit(
                               "beforeHistoryChange",
                               as,
@@ -5618,7 +5666,7 @@
                                   y: 0
                                 }
                               : null;
-                            _ctx.next = 153;
+                            _ctx.next = 155;
                             return _this
                               .set(
                                 _objectSpread({}, nextState, {
@@ -5637,9 +5685,9 @@
                                 if (e.cancelled) error = error || e;
                                 else throw e;
                               });
-                          case 153:
+                          case 155:
                             if (!error) {
-                              _ctx.next = 156;
+                              _ctx.next = 158;
                               break;
                             }
                             Router.events.emit(
@@ -5649,7 +5697,7 @@
                               routeProps
                             );
                             throw error;
-                          case 156:
+                          case 158:
                             if (false) {
                             }
                             Router.events.emit(
@@ -5658,8 +5706,8 @@
                               routeProps
                             );
                             return _ctx.abrupt("return", true);
-                          case 161:
-                            _ctx.prev = 161;
+                          case 163:
+                            _ctx.prev = 163;
                             _ctx.t4 = _ctx["catch"](113);
                             if (
                               !(
@@ -5667,13 +5715,13 @@
                                 _ctx.t4.cancelled
                               )
                             ) {
-                              _ctx.next = 165;
+                              _ctx.next = 167;
                               break;
                             }
                             return _ctx.abrupt("return", false);
-                          case 165:
+                          case 167:
                             throw _ctx.t4;
-                          case 166:
+                          case 168:
                           case "end":
                             return _ctx.stop();
                         }
@@ -5682,8 +5730,8 @@
                     null,
                     [
                       [39, 51],
-                      [113, 161],
-                      [132, 138]
+                      [113, 163],
+                      [134, 140]
                     ]
                   );
                 })
Diff for index.html
@@ -19,7 +19,7 @@
       defer=""
     ></script>
     <script
-      src="/_next/static/chunks/main-eb6922b25512ec18.js"
+      src="/_next/static/chunks/main-ee04e351dce28253.js"
       defer=""
     ></script>
     <script
Diff for link.html
@@ -19,7 +19,7 @@
       defer=""
     ></script>
     <script
-      src="/_next/static/chunks/main-eb6922b25512ec18.js"
+      src="/_next/static/chunks/main-ee04e351dce28253.js"
       defer=""
     ></script>
     <script
Diff for withRouter.html
@@ -19,7 +19,7 @@
       defer=""
     ></script>
     <script
-      src="/_next/static/chunks/main-eb6922b25512ec18.js"
+      src="/_next/static/chunks/main-ee04e351dce28253.js"
       defer=""
     ></script>
     <script
Commit: d8d6a4a

Copy link
Member

@ijjk ijjk left a comment

Choose a reason for hiding this comment

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

Left a couple comments, looks good from testing other than that and should be good to land as it shouldn't be breaking

@janicklas-ralph
Copy link
Contributor Author

Thanks! Made the changes. LMK if theres anything needed else for approval.

Copy link
Member

@ijjk ijjk left a comment

Choose a reason for hiding this comment

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

Looks good to land as no breaking changes are present and new behavior is under unstable_ prefix

@kodiakhq kodiakhq bot merged commit 0441f81 into vercel:canary Apr 21, 2022
@janicklas-ralph janicklas-ralph deleted the script-update branch April 21, 2022 21:42
@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 22, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area: documentation created-by: Chrome Aurora PRs by the Google Chrome team: https://web.dev/aurora type: next
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants