将标签管理器添加到下一个 js,混淆文档

Adding tag manager to next js, confusing docs

我正在向我的 next.js 网站(下一个版本 12.0.4)添加标签管理器,这里的文档 https://nextjs.org/docs/basic-features/script 说我可以在 _document.js 文件。

当我按照说明操作时,我收到一个错误,将我指向此页面 https://nextjs.org/docs/messages/no-script-in-document-page 说我不能在 _document.js 页面中使用 next/script,此页面指向原始页面。

我很困惑,正确的实现是什么?

在四处挖掘之后,我发现了这个 post:

基本上说脚本不起作用,一旦我忽略了警告并尝试了我的解决方案,我发现也是这种情况。

在我的 _app.js 中使用 next/head 的解决方案似乎工作正常。

阅读@juliomalves 的上述评论,了解为什么要在 _app.js

中完成此操作的解释
import Script from "next/script";

    const App = ({ Component, pageProps }) => (
      <>
        <Script
        id="tagmanager-main"
        strategy="afterInteractive"
        async
        src={`https://www.googletagmanager.com/gtag/js?id=${process.env.NEXT_PUBLIC_MEASUREMENT_ID}`}
      ></Script>
      <Script
        id="tagmanager-setup"
        strategy="afterInteractive"
        dangerouslySetInnerHTML={{
          __html: `
            window.dataLayer = window.dataLayer || [];
            function gtag(){dataLayer.push(arguments);}
            gtag('js', new Date());
            gtag('config', '${process.env.NEXT_PUBLIC_MEASUREMENT_ID}');
          `,
        }}
      />
        {/* eslint-disable-next-line react/jsx-props-no-​spreading */}
        <Component {...pageProps} />
      </>
    );
    
    export default App;

这是我的_document.tsx,也许里面有什么东西阻止它工作,但我对上面的工作解决方案很满意。

import * as React from 'react';
// eslint-disable-next-line @next/next/no-document-import-in-page
import Document, { Html, Head, Main, NextScript } from 'next/document';
import createEmotionServer from '@emotion/server/create-instance';
// import theme from '../../styles/theme';
import createEmotionCache from '../lib/createEmotionCache';
// eslint-disable-next-line @next/next/no-script-in-document
import Script from 'next/script';

export default class MyDocument extends Document {
  render() {
    return (
      <Html lang="en">
        <Head>
          {/* PWA primary color */}
          {/* <meta name="theme-color" content={theme.palette.primary.main} /> */}
          <link
            rel="stylesheet"
            href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"
          />
          <link
            rel="stylesheet"
            href="https://fonts.googleapis.com/icon?family=Material+Icons"
          />
          <Script
            id="tagman"
            strategy="afterInteractive"
            async
            src="https://www.googletagmanager.com/gtag/js?id=G-xxxxx"
          ></Script>
          <Script
            id="tagman-datalayer"
            strategy="afterInteractive"
            dangerouslySetInnerHTML={{
              __html: `
                window.dataLayer = window.dataLayer || [];
                function gtag(){dataLayer.push(arguments);}
                gtag('js', new Date());
          
                gtag('config', 'G-xxxxx');
              `,
            }}
          />

          <script
            src={`https://maps.googleapis.com/maps/api/js?key=${
              process.env.NEXT_PUBLIC_MAPS_API_KEY || ''
            }&libraries=&v=weekly`}
            async
          ></script>
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

// `getInitialProps` belongs to `_document` (instead of `_app`),
// it's compatible with static-site generation (SSG).
MyDocument.getInitialProps = async (ctx) => {
  // Resolution order
  //
  // On the server:
  // 1. app.getInitialProps
  // 2. page.getInitialProps
  // 3. document.getInitialProps
  // 4. app.render
  // 5. page.render
  // 6. document.render
  //
  // On the server with error:
  // 1. document.getInitialProps
  // 2. app.render
  // 3. page.render
  // 4. document.render
  //
  // On the client
  // 1. app.getInitialProps
  // 2. page.getInitialProps
  // 3. app.render
  // 4. page.render

  const originalRenderPage = ctx.renderPage;

  // You can consider sharing the same emotion cache between all the SSR requests to speed up performance.
  // However, be aware that it can have global side effects.
  const cache = createEmotionCache();
  const { extractCriticalToChunks } = createEmotionServer(cache);

  ctx.renderPage = () =>
    originalRenderPage({
      // eslint-disable-next-line react/display-name, @typescript-eslint/no-explicit-any
      enhanceApp: (App: any) => (props) =>
        <App emotionCache={cache} {...props} />,
    });

  const initialProps = await Document.getInitialProps(ctx);
  // This is important. It prevents emotion to render invalid HTML.
  // See https://github.com/mui-org/material-ui/issues/26561#issuecomment-855286153
  const emotionStyles = extractCriticalToChunks(initialProps.html);
  const emotionStyleTags = emotionStyles.styles.map((style) => (
    <style
      data-emotion={`${style.key} ${style.ids.join(' ')}`}
      key={style.key}
      // eslint-disable-next-line react/no-danger
      dangerouslySetInnerHTML={{ __html: style.css }}
    />
  ));

  return {
    ...initialProps,
    // Styles fragment is rendered after the app and page rendering finish.
    styles: [
      ...React.Children.toArray(initialProps.styles),
      ...emotionStyleTags,
    ],
  };
};