Skip to content

Instantly share code, notes, and snippets.

@alinzk
Last active January 20, 2022 05:55
Show Gist options
  • Save alinzk/593cbf0e79fa0a54111388a64dd9e480 to your computer and use it in GitHub Desktop.
Save alinzk/593cbf0e79fa0a54111388a64dd9e480 to your computer and use it in GitHub Desktop.
Customized NextScript from next.js to delay loading for non-critical js
/*
NOTE: This modifies next.js internal api behavior and may break your application.
Tested on next.js version: 9.2.1
*/
import React from 'react';
import { compact, flatten } from 'lodash';
import { NextScript } from 'next/document';
class NextScriptCustom extends NextScript {
render() {
const orgNextScripts = flatten(super.render().props.children);
const scripts = compact(
orgNextScripts.map((child) => {
if (child.props.id === '__NEXT_DATA__') {
return {
props: { ...child.props },
content: child.props.dangerouslySetInnerHTML.__html
};
}
if (child?.type === 'script') {
return {
props: { ...child.props },
content: ''
};
}
return null;
})
);
const initialFilterer = props => !props.src || !props.src.includes('chunk');
const initialLoadScripts = scripts.filter(({ props }) => initialFilterer(props));
const chunkedScripts = scripts.filter(({ props }) => !initialFilterer(props));
const jsContent = `
var chunkedScripts = ${JSON.stringify(chunkedScripts)};
setTimeout(() => {
chunkedScripts.map((script) => {
if (!script || !script.props) return;
try {
var scriptTag = document.createElement('script');
scriptTag.src = script.props.src;
scriptTag.async = script.props.async;
scriptTag.defer = script.props.defer;
if (script.props.id) scriptTag.id = script.props.id;
if (script.content) scriptTag.innerHTML = script.content;
document.body.appendChild(scriptTag);
}
catch(err) {
console.log(err);
}
});
// 1800ms seems like when PageSpeed Insights stop waiting for more js
}, 1800);
`;
return (
<>
{initialLoadScripts.map(({ props }) => (
<script key={props.id} {...props} src={props.src} />
))}
<script id="__NEXT_SCRIPT_CUSTOM" defer dangerouslySetInnerHTML={{ __html: jsContent }} />
</>
);
}
}
export default NextScriptCustom;
@dipakkr
Copy link

dipakkr commented Mar 22, 2021

Hi @anawaz42, I am getting an error props not defined in NextScriptCustom.js

I am not sure what props to pass from _document.js.

Can you share your _document.js file code ?

@tiagobbraga
Copy link

Hi @dipakkr, try this:

`
import React from "react";
import {compact, flatten} from "lodash";

import {NextScript} from "next/document";

class NextScriptCustom extends NextScript {
render() {
const orgNextScripts = compact(flatten(super.render().props.children));

const scripts = compact(
  orgNextScripts.map((child) => {
    if (child.props.id === "__NEXT_DATA__") {
      return {
        props: {...child.props},
        content: child.props.dangerouslySetInnerHTML.__html,
      };
    }

    if (child.type === "script") {
      return {
        props: {...child.props},
        content: "",
      };
    }

    return null;
  }),
);

const initialFilterer = (props) => !props.src || !props.src.includes("chunk");

const initialLoadScripts = scripts.filter((item) => initialFilterer(item.props));
const chunkedScripts = scripts.filter((item) => !initialFilterer(item.props));

const jsContent = `
  var chunkedScripts = ${JSON.stringify(chunkedScripts)};
  setTimeout(() => {
    chunkedScripts.map((script) => {
      if (!script || !script.props) return;

      try {
        var scriptTag = document.createElement('script');

        scriptTag.src = script.props.src;
        scriptTag.async = script.props.async;
        scriptTag.defer = script.props.defer;
        
        if (script.props.id) scriptTag.id = script.props.id;
        if (script.content) scriptTag.innerHTML = script.content;
        document.body.appendChild(scriptTag);
      }
      catch(err) {
        console.log(err);
      }
    });
  // 1800ms seems like when PageSpeed Insights stop waiting for more js       
  }, 1800);
`;

return (
  <>
    {initialLoadScripts.map(({props}, index) => (
      <script key={index} {...props} src={props.src} />
    ))}

    <script id="__NEXT_SCRIPT_CUSTOM" defer dangerouslySetInnerHTML={{__html: jsContent}} />
  </>
);

}
}

export default NextScriptCustom;
`

My version of the next.js is v9.3.5

@speeday
Copy link

speeday commented May 26, 2021

Hi @anawaz42,

Can we add Next-AMP tag in between this code to get pass in AMP VALIDATOR online..?

Next-AMP Tags:- https://nextjs.org/docs/api-reference/next/amp
AMP Validator: - https://search.google.com/test/amp

As of now it get reported as error in AMP Validator.

@speeday
Copy link

speeday commented Jun 7, 2021

Hello All,

I have been using it but found that it is been avoided by Google Insights Page Speed New Update v8.0.0.

Anyone if used and passed Google Page Speed with Good Score. Please let me know.

@speeday
Copy link

speeday commented Aug 24, 2021

Hello @anawaz42,

Hope you noted above comments for AMP and Google Page Speed v8.0.0 with Next JS v11.0.0 to share your inputs for the same..!!

@jaintarun268
Copy link

jaintarun268 commented Jan 20, 2022

I am facing same errors.

Error occurred prerendering page "/nextScriptCustom". Read more: https://nextjs.org/docs/messages/prerender-error
TypeError: Cannot destructure property 'assetPrefix' of 'this.context' as it is null.
at NextScriptCustom.render (G:\Projects\ArkaSoftwares\React\arka-react.next\server\chunks\6859.js:880:17)
at NextScriptCustom.render (G:\Projects\ArkaSoftwares\React\arka-react.next\server\pages\nextScriptCustom.js:34:82)
at d (G:\Projects\ArkaSoftwares\React\arka-react\node_modules\react-dom\cjs\react-dom-server.node.production.min.js:35:231)
at bb (G:\Projects\ArkaSoftwares\React\arka-react\node_modules\react-dom\cjs\react-dom-server.node.production.min.js:36:16)
at a.b.render (G:\Projects\ArkaSoftwares\React\arka-react\node_modules\react-dom\cjs\react-dom-server.node.production.min.js:42:43)
at a.b.read (G:\Projects\ArkaSoftwares\React\arka-react\node_modules\react-dom\cjs\react-dom-server.node.production.min.js:41:83)
at Object.exports.renderToString (G:\Projects\ArkaSoftwares\React\arka-react\node_modules\react-dom\cjs\react-dom-server.node.production.min.js:52:138)
at Object.renderPage (G:\Projects\ArkaSoftwares\React\arka-react\node_modules\next\dist\server\render.js:686:46)
at Object.defaultGetInitialProps (G:\Projects\ArkaSoftwares\React\arka-react\node_modules\next\dist\server\render.js:316:51)
at Function.getInitialProps (G:\Projects\ArkaSoftwares\React\arka-react.next\server\chunks\6859.js:515:20)
[== ] info - Generating static pages (182/426)
Error occurred prerendering page "/ar/nextScriptCustom". Read more: https://nextjs.org/docs/messages/prerender-error
TypeError: Cannot destructure property 'assetPrefix' of 'this.context' as it is null.
at NextScriptCustom.render (G:\Projects\ArkaSoftwares\React\arka-react.next\server\chunks\6859.js:880:17)
at NextScriptCustom.render (G:\Projects\ArkaSoftwares\React\arka-react.next\server\pages\nextScriptCustom.js:34:82)
at d (G:\Projects\ArkaSoftwares\React\arka-react\node_modules\react-dom\cjs\react-dom-server.node.production.min.js:35:231)
at bb (G:\Projects\ArkaSoftwares\React\arka-react\node_modules\react-dom\cjs\react-dom-server.node.production.min.js:36:16)
at a.b.render (G:\Projects\ArkaSoftwares\React\arka-react\node_modules\react-dom\cjs\react-dom-server.node.production.min.js:42:43)
at a.b.read (G:\Projects\ArkaSoftwares\React\arka-react\node_modules\react-dom\cjs\react-dom-server.node.production.min.js:41:83)
at Object.exports.renderToString (G:\Projects\ArkaSoftwares\React\arka-react\node_modules\react-dom\cjs\react-dom-server.node.production.min.js:52:138)
at Object.renderPage (G:\Projects\ArkaSoftwares\React\arka-react\node_modules\next\dist\server\render.js:686:46)
at Object.defaultGetInitialProps (G:\Projects\ArkaSoftwares\React\arka-react\node_modules\next\dist\server\render.js:316:51)
at Function.getInitialProps (G:\Projects\ArkaSoftwares\React\arka-react.next\server\chunks\6859.js:515:20)

Error occurred prerendering page "/en/nextScriptCustom". Read more: https://nextjs.org/docs/messages/prerender-error
TypeError: Cannot destructure property 'assetPrefix' of 'this.context' as it is null.
at NextScriptCustom.render (G:\Projects\ArkaSoftwares\React\arka-react.next\server\chunks\6859.js:880:17)
at NextScriptCustom.render (G:\Projects\ArkaSoftwares\React\arka-react.next\server\pages\nextScriptCustom.js:34:82)
at d (G:\Projects\ArkaSoftwares\React\arka-react\node_modules\react-dom\cjs\react-dom-server.node.production.min.js:35:231)
at bb (G:\Projects\ArkaSoftwares\React\arka-react\node_modules\react-dom\cjs\react-dom-server.node.production.min.js:36:16)
at a.b.render (G:\Projects\ArkaSoftwares\React\arka-react\node_modules\react-dom\cjs\react-dom-server.node.production.min.js:42:43)
at a.b.read (G:\Projects\ArkaSoftwares\React\arka-react\node_modules\react-dom\cjs\react-dom-server.node.production.min.js:41:83)
at Object.exports.renderToString (G:\Projects\ArkaSoftwares\React\arka-react\node_modules\react-dom\cjs\react-dom-server.node.production.min.js:52:138)
at Object.renderPage (G:\Projects\ArkaSoftwares\React\arka-react\node_modules\next\dist\server\render.js:686:46)
at Object.defaultGetInitialProps (G:\Projects\ArkaSoftwares\React\arka-react\node_modules\next\dist\server\render.js:316:51)
at Function.getInitialProps (G:\Projects\ArkaSoftwares\React\arka-react.next\server\chunks\6859.js:515:20)
info - Generating static pages (426/426)

Build error occurred
Error: Export encountered errors on following paths:
/nextScriptCustom
/nextScriptCustom: /ar/nextScriptCustom
/nextScriptCustom: /en/nextScriptCustom
at G:\Projects\ArkaSoftwares\React\arka-react\node_modules\next\dist\export\index.js:500:19
at runMicrotasks ()
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async Span.traceAsyncFn (G:\Projects\ArkaSoftwares\React\arka-react\node_modules\next\dist\trace\trace.js:74:20)
at async G:\Projects\ArkaSoftwares\React\arka-react\node_modules\next\dist\build\index.js:987:17
at async Span.traceAsyncFn (G:\Projects\ArkaSoftwares\React\arka-react\node_modules\next\dist\trace\trace.js:74:20)
at async G:\Projects\ArkaSoftwares\React\arka-react\node_modules\next\dist\build\index.js:861:13
at async Span.traceAsyncFn (G:\Projects\ArkaSoftwares\React\arka-react\node_modules\next\dist\trace\trace.js:74:20)
at async Object.build [as default] (G:\Projects\ArkaSoftwares\React\arka-react\node_modules\next\dist\build\index.js:82:25)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment