【问题标题】:How to load Google Tag Manager with next/script component (Next.js 11)?如何使用 next/script 组件(Next.js 11)加载谷歌标签管理器?
【发布时间】:2021-09-07 22:37:03
【问题描述】:

Next.js v11 发布了一个新的Script 组件,它有不同的策略。

建议使用afterInteractive 策略加载Google TagManager。

我试过了

// _app.js

import Script from 'next/script';

class MyApp extends App {
  public render() {
    const { Component, pageProps } = this.props;

    return (
      <>
        <Script strategy="afterInteractive">
          {`(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':` +
            `new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],` +
            `j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=` +
            `'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);` +
            `})(window,document,'script','dataLayer','GTM-XXXXXXX');`}
        </Script>
        <Component {...pageProps} />
      </>
    );
  }
}

export default MyApp;

它工作正常,它加载谷歌标签管理器,但问题是它在每个页面导航上注入相同的脚本,这会产生重复的标签。

如何使用新的Script 组件?

【问题讨论】:

    标签: javascript next.js google-tag-manager


    【解决方案1】:

    我的最终解决方案是拆分 GTM 脚本。

    将初始dataLayer 对象放在_document 页面中的窗口上。

    // _document.js
    
    import Document, { Head, Html, Main, NextScript } from 'next/document';
    
    export default class MyDocument extends Document {
      render() {
        return (
          <Html lang="en">
            <Head>
              <meta charSet="utf-8" />
    
              <script
                dangerouslySetInnerHTML={{
                  __html:
                    `(function(w,l){` +
                    `w[l] = w[l] || [];w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});` +
                    `})(window,'dataLayer');`,
                }}
              />
            </Head>
            <body>
              <Main />
              <NextScript />
            </body>
          </Html>
        );
      }
    }
    

    加载带有Script组件的GMT脚本(在_document页面中不允许使用)

    // _app.js
    
    import Script from 'next/script';
    
    class MyApp extends App {
      public render() {
        const { Component, pageProps } = this.props;
    
        return (
          <>
            <Script src={`https://www.googletagmanager.com/gtm.js?id=GMT-XXXXXXX`} />
            <Component {...pageProps} />
          </>
        );
      }
    }
    
    export default MyApp;
    

    【讨论】:

      【解决方案2】:

      我认为你应该为你的&lt;Script&gt; 组件设置一个id

      Next 可以检查它是否已经渲染,你不会有这些重复。

      这是与 Next 关联的 eslint 规则:

      具有内联内容的下一个/脚本组件需要定义一个 id 属性来跟踪和优化脚本。

      见:https://nextjs.org/docs/messages/inline-script-id

      所以你的解决方案可能是:

          <Script id="gtm-script" strategy="afterInteractive">{`...`}</Script>
      

      您可能还应该为您的下一个项目安装 eslint:
      要么运行 next lint 要么安装 eslint 下一个配置:

      yarn add -D eslint eslint-config-next
      

      并至少使用此内容定义文件 .eslintrc.json :

      {
        "extends": ["next/core-web-vitals"]
      }
      

      Information about next.js eslint configuration.

      【讨论】:

      • 来自source code,它使用 id 或 src(这是有道理的,因为 src 足够独特)。
      • 是的,这是专门针对内联脚本的,因为在这种情况下,您没有 src 属性。
      • 但是我没有没有src的Script组件,文档里面的script标签就是原生的script标签。
      • 是的,您确实有一个没有 src 属性的 Script 组件:`
      • 是的,我认为您的答案是一个解决方案,添加一个 id 是您最初问题的另一个解决方案(如果您想使用 next/script)。我不确定,但也许 next/script 的优势在于它缩小了脚本的内容(但我没有检查)。
      【解决方案3】:

      您的内联脚本需要一个“id”参数,以便 Next 可以在内部检查并避免再次加载脚本。

      文档中提到了它,但他们在第一个版本中错过了这一点。

      它后来被添加为一个补丁,所以升级你的 Next 可以解决这个问题

      补丁 - https://github.com/vercel/next.js/pull/28779/files/11cdc1d28e76c78a140d9abd2e2fb10fc2030b82

      讨论帖 - https://github.com/vercel/next.js/pull/28779

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多