简体   繁体   English

为什么带有 beforeInteractive 策略的 next.js Script 标签不加载第三方脚本?

[英]Why does the next.js Script tag with the beforeInteractive strategy don't load thirdParty script?

I try to understand how the next.js Script tag with the strategy beforeInteractive works.我尝试了解 next.js Script 标记与 beforeInteractive 策略的工作原理。 For testing i just used lodash.为了测试,我只使用了 lodash。 But i keep getting a ReferenceError: _ is not defined .但我不断收到ReferenceError: _ is not defined I thought when a script is loaded with beforeInteractive it should be globally available inside my page Component since it get injected into the initial Html from the server and i could use it for example in the useEffect hook to alter a div.我认为当使用 beforeInteractive 加载脚本时,它应该在我的页面组件中全局可用,因为它是从服务器注入到初始 Html 中的,我可以在 useEffect 挂钩中使用它来更改 div。 Can someone explain to me why it's not working or what i'm doing wrong?有人可以向我解释为什么它不起作用或我做错了什么吗? I don't installed it via npm because im trying to figure out how it works.我没有通过 npm 安装它,因为我试图弄清楚它是如何工作的。

I have a simple _document.js and i added a Next.js script tag with the strategy beforeInteractive to this _document.js.我有一个简单的 _document.js,并在这个 _document.js 中添加了一个带有 beforeInteractive 策略的 Next.js 脚本标签。 The next.js docs says: This strategy only works inside _document.js and is designed to load scripts that are needed by the entire site (ie the script will load when any page in the application has been loaded server-side). next.js 文档说:此策略仅在 _document.js 内部有效,旨在加载整个站点所需的脚本(即,当应用程序中的任何页面加载到服务器端时,脚本将加载)。

import { Html, Head, Main, NextScript } from 'next/document'
import Script from 'next/script'

export default function Document() {
  return (
    <Html>
      <Head />
      <body>
        <Main />
        <NextScript />
        <Script
          src="https://unpkg.com/lodash@4.17.20"
          strategy="beforeInteractive"
        ></Script>
      </body>
    </Html>
  )
}

Then i have a simple page Component inside the pages folder.然后我在 pages 文件夹中有一个简单的页面组件。 I added the getServerSideProps function to use ServerSideRendering.我添加了 getServerSideProps 函数来使用 ServerSideRendering。

If you export a function called getServerSideProps (Server-Side Rendering) from a page, Next.js will pre-render this page on each request using the data returned by getServerSideProps.如果您从页面导出名为 getServerSideProps(服务器端渲染)的函数,Next.js 将使用 getServerSideProps 返回的数据在每个请求上预渲染此页面。

import Head from 'next/head';
import {useEffect, useState} from 'react';

const TestComponent = () => {
    const [change,setChange] = useState('not changed');

    useEffect(()=> {
        console.log(_);
        setChange(_.join(['one','two'],' - '));
    });

    return (
        <>
            <Head>
                <title>Test</title>
            </Head>
            <div>{change}</div>
        </>
    );
};

export async function getServerSideProps(context) {
    return {
      props: {},
    }
  }

export default TestComponent;

Update更新

Seems like it is indeed a bug which is fixed but not released yet https://github.com/vercel/next.js/discussions/37098似乎它确实是一个已修复但尚未发布的错误https://github.com/vercel/next.js/discussions/37098

Putting aside the fact that you should be importing Lodash as a node module, there does seem to be an issue when using next/script in _document (no matter what the external script actually is).撇开您应该将 Lodash 作为节点模块导入这一事实不谈,在_document中使用next/script似乎确实存在问题(无论外部脚本实际上是什么)。

It turns out this is a Next.js bug that has been addressed in this PR in pre-release versionv12.1.7-canary.8 .事实证明,这是一个 Next.js 错误,已在此PR中的预发布版本v12.1.7-canary.8 中解决 To fix the issue in your project simply update Next.js to version >=12.2.0 ( npm install next@latest ).要解决项目中的问题,只需将 Next.js 更新到 >=12.2.0 版本( npm install next@latest )。


As an alternative, you can use the <script> tag directly in the _document 's <Head> with the defer property.作为替代方案,您可以直接在_document<Head>中使用带有defer属性的<script>标记。 This closely matches what the next/script would output.这与next/script将输出的内容非常匹配。

import { Html, Head, Main, NextScript } from 'next/document'

export default function Document() {
    return (
        <Html>
            <Head>
                <script
                    type="text/javascript"
                    src="https://unpkg.com/lodash@4.17.20/lodash.js"
                    defer
                ></script>
            </Head>
            <body>
                <Main />
                <NextScript />
            </body>
        </Html>
    )
}

First and foremost, I'm failing to see virtually any reason you'd want to do this, when you can (and should) simply use install it to node_modules .首先,当您可以(并且应该)简单地使用 install it to node_modules时,我几乎看不到您想要这样做的任何理由。 You're also going to possibly run the risk of the bundle having issues if the library type isn't a module and the next configuration requires a module.如果库类型不是模块并且下一个配置需要模块,您还可能会冒包出现问题的风险。

Solution based on the question:基于问题的解决方案:

There's two ways.有两种方法。 Firstly, see the docs on this exact thing.首先,请参阅有关此确切内容的文档

Please use the above method mentioned in the docs.请使用文档中提到的上述方法。

If that's not an option for whatever reason...如果出于某种原因这不是一个选择...

The second is a less than ideal , but working solution.第二个是一个不太理想但有效的解决方案。

Create a folder for your static files.为您的静态文件创建一个文件夹。 Ex: <root>/static/js/hello.js .例如: <root>/static/js/hello.js Then in your _document file,然后在你的_document文件中,

<script type="text/javascript" src="/static/hello.js"></script>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM