How can I load scripts after the window.onload event with reactjs / nextjs
Asked Answered
D

2

7

I am trying to optimize my google pagespeed insights score and I have come to the conclusion that deffering NextScript of nextjs is not good enough, it still leads to bad LCP and TII.

I have the following code.

How can bundle the scripts I'm looping though so that thy are all loaded after the window.onload event?

Any help would be much appreciated.

import { NextScript } from 'next/document';
import React from 'react';

type DocumentFiles = {
  sharedFiles: readonly string[];
  pageFiles: readonly string[];
  allFiles: readonly string[];
};

function dedupe<T extends { file: string }>(bundles: T[]): T[] {
  const files = new Set<string>();
  const kept: T[] = [];

  // eslint-disable-next-line
  for (const bundle of bundles) {
    if (files.has(bundle.file)) {
      // eslint-disable-next-line
      continue;
    }
    files.add(bundle.file);
    kept.push(bundle);
  }
  return kept;
}

export class DeferredNextScript extends NextScript {
  getScripts(files: DocumentFiles) {
    return super.getScripts(files).map((script: JSX.Element) => {
      console.log(script);
      return React.cloneElement(script, {
        // eslint-disable-next-line
        key: script.props.src,
        defer: true,
        async: false,
      });
    });
  }

  getDynamicChunks(files: DocumentFiles) {
    const { dynamicImports, assetPrefix, devOnlyCacheBusterQueryString } = this.context;

    return dedupe(dynamicImports).map((bundle) => {
      console.log(bundle);
      let modernProps = {};
      if (process.env.__NEXT_MODERN_BUILD) {
        modernProps = bundle.file.endsWith('.module.js') ? { type: 'module' } : { noModule: true };
      }

      if (!bundle.file.endsWith('.js') || files.allFiles.includes(bundle.file)) {
        return null;
      }

      return (
        <script
          defer
          async={false}
          key={bundle.file}
          src={`${assetPrefix}/_next/${encodeURI(bundle.file)}${devOnlyCacheBusterQueryString}`}
          nonce={this.props.nonce}
          crossOrigin={this.props.crossOrigin || process.env.__NEXT_CROSS_ORIGIN}
          {...modernProps}
        />
      );
    });
  }
}
Disaffect answered 4/1, 2021 at 17:55 Comment(2)
I am in need of the same thing, load something once page is loaded, did you solve this, and if so, how?Partial
hello! did not had a chance to do that yet. I'm thinking server components will allow me to not load userless js, that will be good enoughSprouse
C
1

You can try:

useEffect(
() => {
// Your fn
},
 [])
Colunga answered 18/5, 2023 at 18:51 Comment(1)
This answer is not okay, you shouldn't use window.location inside useEffect or anything similar, don't interfere with the lifecycle of the component. You can achieve better result with useEffect(() => {//fn }, [])Ampereturn
M
0

In order to bundle your scripts when you have access to the global window, you can use react useEffect hook. (or similarly, if you are using a class-based component, you can use the componentDidMount life cycle.)

Myrilla answered 19/5, 2021 at 12:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.