使用 Next JS 延迟脚本

时间:2021-03-02 18:42:49

标签: javascript reactjs next.js

我在一个项目中使用 Next JS,我正在使用 Google 的 Page Speed Insights 工具进行一些优化。对我的网站性能产生负面影响的主要因素之一是 3rd 方脚本,主要是 Google Tag 脚本(也加载了我的 Google Analytics)和 Google 地图 API 脚本。到目前为止,我已经尝试了几种方法来抵消这两个库的加载,但我仍然从该工具中收到以下消息:

删除未使用的 JavaScript

https://maps.googleapis.com/maps/api/js?key=asdafsafasafasfasf&libraries=places&language=en&region=US
(maps.googleapis.com)

https://www.googletagmanager.com/gtag/js?id=UA-123123-2
(www.googletagmanager.com)

我需要在网站的任何地方加载这些脚本,所以我试图延迟脚本的加载,直到页面上的其他所有内容都完成加载。这是我最初拥有的:

_document.js

import Document, { Head, Main, NextScript, Html } from "next/document";

export default class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const initialProps = await Document.getInitialProps(ctx);
    return { ...initialProps };
  }

  render() {
    return (
      <Html lang="en">
        <Head>
          <script
            defer
            src={`https://www.googletagmanager.com/gtag/js?id=UA-123123-2`}
          />
          <script
            defer
            src="https://maps.googleapis.com/maps/api/js?key=asdafsafasafasfasf&libraries=places&language=en&region=US"
          />
          <script
            dangerouslySetInnerHTML={{
              __html: `
            window.dataLayer = window.dataLayer || [];
            function gtag(){dataLayer.push(arguments);}
            gtag('js', new Date());
            gtag('config', 'UA-123123-2');
          `,
            }}
          />
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

如您所见,我只是像往常一样使用 defer 道具加载脚本。然而,使用这种方法谷歌页面速度洞察仍然给我同样的信息。然后我尝试了一种不同的方法,使用 Next JS 中名为 ScriptLoader 的实验组件,旨在允许人们推迟脚本。这是该组件的链接:

https://github.com/vercel/next.js/discussions/18172

这是我的实现:

_app.js

import App from "next/app";
import ScriptLoader from "next/dist/client/experimental-script.js";

export default class NextApp extends App {
  render() {
    return (<>
      <ScriptLoader
        strategy="defer"
        src="https://www.googletagmanager.com/gtag/js?id=UA-123123-2"
      />
      <ScriptLoader
        strategy="defer"
        src="https://maps.googleapis.com/maps/api/js?key=asdafsafasafasfasf&libraries=places&language=en&region=US"
      />
    </>)
  }
}

但是它仍然给我同样的错误信息。我不知道现在该尝试什么!有没有其他人遇到过这个问题并找到了解决方法?

谢谢

3 个答案:

答案 0 :(得分:3)

Google Analytics/Gtag

根据我自己的经验,我不得不遗憾地告诉您,延迟加载分析不是一个好主意,并且在调用不存在(尚不存在)的函数时通常会导致意外错误。所以最好在一开始就加载这个,即使谷歌因为使用他们自己的脚本而惩罚你很糟糕。所以我认为您通过自定义 _document.js 文件加载 gtag 的初始方法很好。

谷歌地图

谢天谢地,Google 地图与众不同。有一个名为 Google Maps JavaScript API Loader 的 npm 包。这使得动态加载地图成为可能——或者更容易。除此之外,您还可以利用 JavaScriptdynamic import functionality。您可以创建一个自定义加载函数,该函数仅在满足某些条件后才会触发。它可能看起来像这样:

const myCustomLoadFunction = async () => {
  try {
    const { Loader } = await import("@googlemaps/js-api-loader");
    const loader = new Loader({
      apiKey: "YOUR_API_KEY",
      version: "weekly",
      // ...additionalOptions,
    });

    const mapOptions = {
      center: { lat: 0, lng: 0 },
      zoom: 4,
    };

    await loader.load();
    new google.maps.Map(document.getElementById("map"), mapOptions);
  } catch (e) {
    // do something
  }
};

您可以将其置于 useEffect 钩子中,甚至在用户悬停在某处或点击某处时调用它,从而使导入延迟更长时间。

答案 1 :(得分:2)

我最近正在使用更复杂的 GTM 配置处理同样的问题。我可以分享我的方法。

首先,在 Lighthouse 中,“删除未使用的 JavaScript”并不意味着不使用整个文件。它实际上只是告诉您给定文件中有很大一部分未使用的代码。如果是第三方文件,我们可能无能为力。

此外,每个 JavaScript 文件(包括分析)都会对性能产生影响。理想情况下,只有在成本合理的情况下才支付价格(基本分析、应用监控服务等......)。

目标

目标不是解决“删除未使用的 JavaScript”。真正的目标应该是通过延迟加载来减少 JavaScript 的影响,以便尽快加载其他更重要的页面内容。

异步标签

GTM 本身没有很大的性能影响。这实际上取决于您在 GTM 容器中的内容。我认为让 GTM 加载 async 标签没问题。

Google Maps API 可以通过 GTM 异步加载。我们可以更准确地决定何时加载它。

GTM 加载

对于不需要立即交付的脚本,例如 Google Map API,您可能不想在 Container Loaded 上加载它们,因为这会占用可用于加载真实页面内容的宝贵资源.您应该考虑将其移至 Window Loaded。此时,页面已完全加载,对 Google Web Core Vita 的影响应该是最小的。

对于分析,理想情况下,应尽早加载它们以更准确地捕获数据。但是,这可能会发生变化,具体取决于业务需求。对于我的组织,我们将一些分析移至 Window Loaded 阶段。原因是我们希望有更好的页面加载性能,而我们不太关心在页面加载之前反弹的用户。

如果需要进一步延迟,我们可以创建一个额外的触发器,它会在几毫秒的超时后触发。更多详情可以参考这个blog post

一个潜在的解决方案

总而言之,这是我会采用的一种方法。它类似于我的团队在我们的项目中使用的东西。

  • 仅在具有 Next.js 属性的 async 中加载 GTM。
  • 将 Google Analytic 和 Google Map API 移至 GTM
  • 尽可能延迟加载时间,同时对业务/项目/用户仍然有意义。

我希望它有意义并且有帮助。

参考资料

GTM - Page View Trigger

答案 2 :(得分:2)

我提供了这个选项,因为它还没有出现。 这并不意味着这个解决方案是最好的。加载 DOM 内容后开始加载脚本的方法。我认为它可以插入 _document.js 而不是上面提到的三个脚本

我使用 setTimeout 将此任务放入事件队列,0 表示它会尽快发生。

<script 
    dangerouslySetInnerHTML={{
      __html: `
      document.addEventListener("DOMContentLoaded", function(event) {
        setTimeout(function() {
            var gtag = document.createElement('script');
            gtag.type = 'text/javascript';
            gtag.async = true;
            var gmaps = gtag.cloneNode(false);
            gtag.src = "https://www.googletagmanager.com/gtag/js?id=UA-123123-2"
            gmaps.src = "https://maps.googleapis.com/maps/api/js?key=asdafsafasafasfasf&libraries=places&language=en&region=US"

            var s = document.getElementsByTagName('script')[0]; 
            s.parentNode.insertBefore(gtag, s);
            s.parentNode.insertBefore(gmaps, s);            

            window.dataLayer = window.dataLayer || [];
            function gtag(){dataLayer.push(arguments);}
            gtag('js', new Date());
            gtag('config', 'UA-123123-2');
        }, 0)
      });
      `,
    }}
/>