如何在 window.onload 事件之后使用 reactjs / nextjs 加载脚本

问题描述

我正在尝试优化我的 google pagespeed 洞察分数,我得出的结论是,推迟 nextjs 的 NextScript 还不够好,它仍然会导致糟糕的 LCP 和 TII。

我有以下代码

如何捆绑我正在循环的脚本,以便在 window.onload 事件之后全部加载?

任何帮助将不胜感激。

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}
        />
      );
    });
  }
}

解决方法

为了在您有权访问 global window 时捆绑您的脚本,您可以使用 react useEffect 钩子。 (或者类似地,如果您使用的是基于类的组件,则可以使用 componentDidMount 生命周期。)