【问题标题】:Defer scripts with Next JS使用 Next JS 延迟脚本
【发布时间】:2021-06-01 08:16:37
【问题描述】:

我正在一个项目中使用 Next JS,并且我正在使用 Google 的 Page Speed Insights 工具进行一些优化。对我的网站性能造成负面影响的主要因素之一是 3rd 方脚本,主要是 Google Tag 脚本(它也加载了我的 Google Analytics)和 Google maps 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"
      />
    </>)
  }
}

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

谢谢

【问题讨论】:

  • 如果我错了,请纠正我,但推迟脚本加载不会帮助您处理那些外部脚本中未使用的 JavaScript。无论何时加载脚本,您仍然会使用其中的相同代码。
  • 在页面加载速度的背景下,我想 Google 并不关心在 DOM 完成加载其他所有内容后加载的脚本,不是吗?
  • 在这种情况下,也许您应该尝试使用async 属性?
  • 我试过异步,但不幸的是它有同样的效果
  • Analytics 在尽早加载时效果最佳。此外,所有分析都会损害性能,因此它始终是一种妥协。这里重要的是用户在每个域中加载此脚本一次。如果可能的话,您可以使用更轻量级的分析工具,例如 Fathom

标签: javascript reactjs next.js


【解决方案1】:

我提供此选项,因为它还没有出现。 这并不意味着这个解决方案是最好的。一种在加载 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)
      });
      `,
    }}
/>

【讨论】:

    【解决方案2】:

    谷歌分析/Gtag

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

    谷歌地图

    感谢上帝,Google 地图与众不同。有一个名为 Google Maps JavaScript API Loader 的 npm 包。这使得动态加载 Maps 成为可能或更容易。除此之外,您还可以利用 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 挂钩中,甚至在用户悬停在某处或点击某物时调用它,从而将导入延迟更长的时间。

    【讨论】:

      【解决方案3】:

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

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

      此外,每个 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

      一个潜在的解决方案

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

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

      我希望它有意义并且有用。

      参考文献

      GTM - Page View Trigger

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-08-02
        • 2021-08-22
        • 2014-10-13
        • 2017-03-27
        • 2012-03-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多