如何在Next.js 11中使用next/script组件加载Google Tag Manager?

18

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;

它运行得很好,它加载了Google标签管理器,但问题在于它在每个页面导航上都注入了相同的脚本,导致重复标签。

如何利用新的Script组件?

3个回答

18

由于 <Script> 组件具有内联内容(没有 src 属性),因此必须为其设置 id

接下来可以检查它是否已经被渲染,这样就不会出现重复内容。

这是来自 Next 的 eslint 规则:

next/script组件需要定义一个id属性以跟踪和优化脚本。

请参阅:https://nextjs.org/docs/messages/inline-script-id

因此,您的解决方案可能是:

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

你下一个项目可能也应该安装eslint:
要么运行next lint,要么安装eslint next config:

yarn add -D eslint eslint-config-next

并且至少要定义文件.eslintrc.json,并将其内容定义为以下内容:

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

关于 Next.js 的 eslint 配置信息。


从源代码(https://github.com/vercel/next.js/blob/canary/packages/next/client/script.tsx#L42)中可以看出,它使用id或src(这是有意义的,因为src足够唯一)。 - felixmosh
2
是的,这是针对内联脚本的,因为在这种情况下你没有 src 属性。 - Stephane L
但是我没有没有src的脚本组件,文档中的script标签是原生的script标签。 - felixmosh
哈,这只是我的初步尝试(根本不起作用),解决方案才是我的答案,而不是我的问题 :] - felixmosh
1
是的,我认为你的答案是一个解决方案,如果你想使用next/script,添加一个id也是解决你最初问题的另一个方法。我不确定,但也许next/script的优点是它可以压缩脚本的内容(但我没有检查过)。 - Stephane L
显示剩余3条评论

9

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

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

// _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;

谢谢。我和你一样遇到了同样的问题,这个方法解决了它! - Anup Sheth

2

id 的要求仅适用于内联 Script 标签,而在我的示例中并没有。 - felixmosh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接