为什么带有 beforeInteractive 策略的 next.js Script 标签不加载第三方脚本?
Why does the next.js Script tag with the beforeInteractive strategy don't load thirdParty script?
我试图了解带有策略 beforeInteractive 的 next.js Script 标签是如何工作的。为了进行测试,我只使用了 lodash。但是我一直收到 ReferenceError: _ is not defined。我认为当脚本加载 beforeInteractive 时,它应该在我的页面组件中全局可用,因为它从服务器注入到初始 Html 中,我可以在 useEffect 挂钩中使用它来改变 div.
有人可以向我解释为什么它不起作用或我做错了什么吗?
我没有通过 npm 安装它,因为我试图弄清楚它是如何工作的。
我有一个简单的 _document.js 并且我添加了一个 Next.js 脚本标签和这个 _document.js 的 beforeInteractive 策略。 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>
)
}
然后我在 pages 文件夹中有一个简单的页面组件。我添加了 getServerSideProps 函数以使用 ServerSideRendering。
如果您从页面导出名为 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;
更新
看来确实是个bug,已经修复但还没有发布
https://github.com/vercel/next.js/discussions/37098
首先,当您可以(并且应该)简单地使用将其安装到 node_modules
时,我几乎没有看到您想要这样做的任何理由。如果库类型不是模块并且下一个配置需要模块,您还可能 运行 捆绑包出现问题的风险。
基于问题的解决方案:
有两种方法。
首先,请参阅关于这件事的 docs。
请使用文档中提到的上述方法
如果出于某种原因不能选择...
第二个是不太理想但可行的解决方案。
为您的静态文件创建一个文件夹。例如:<root>/static/js/hello.js
。然后在你的 _document
文件中,
<script type="text/javascript" src="/static/hello.js"></script>
抛开您应该将 Lodash 作为节点模块导入这一事实,在 _document
中使用 next/script
似乎确实存在问题(无论外部脚本实际上是什么) .
事实证明这是一个 Next.js 错误,已在 PR in pre-release version v12.1.7-canary.8 中解决。要解决项目中的问题,只需更新到最新的金丝雀版本 (npm install next@canary
),或等待稳定的 v12.1.7 版本。
作为替代方法,您可以直接在 _document
的 <Head>
和 defer
属性 中使用 <script>
标签。这与 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>
)
}
我试图了解带有策略 beforeInteractive 的 next.js Script 标签是如何工作的。为了进行测试,我只使用了 lodash。但是我一直收到 ReferenceError: _ is not defined。我认为当脚本加载 beforeInteractive 时,它应该在我的页面组件中全局可用,因为它从服务器注入到初始 Html 中,我可以在 useEffect 挂钩中使用它来改变 div. 有人可以向我解释为什么它不起作用或我做错了什么吗? 我没有通过 npm 安装它,因为我试图弄清楚它是如何工作的。
我有一个简单的 _document.js 并且我添加了一个 Next.js 脚本标签和这个 _document.js 的 beforeInteractive 策略。 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>
)
}
然后我在 pages 文件夹中有一个简单的页面组件。我添加了 getServerSideProps 函数以使用 ServerSideRendering。
如果您从页面导出名为 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;
更新
看来确实是个bug,已经修复但还没有发布 https://github.com/vercel/next.js/discussions/37098
首先,当您可以(并且应该)简单地使用将其安装到 node_modules
时,我几乎没有看到您想要这样做的任何理由。如果库类型不是模块并且下一个配置需要模块,您还可能 运行 捆绑包出现问题的风险。
基于问题的解决方案:
有两种方法。 首先,请参阅关于这件事的 docs。
请使用文档中提到的上述方法
如果出于某种原因不能选择...
第二个是不太理想但可行的解决方案。
为您的静态文件创建一个文件夹。例如:<root>/static/js/hello.js
。然后在你的 _document
文件中,
<script type="text/javascript" src="/static/hello.js"></script>
抛开您应该将 Lodash 作为节点模块导入这一事实,在 _document
中使用 next/script
似乎确实存在问题(无论外部脚本实际上是什么) .
事实证明这是一个 Next.js 错误,已在 PR in pre-release version v12.1.7-canary.8 中解决。要解决项目中的问题,只需更新到最新的金丝雀版本 (npm install next@canary
),或等待稳定的 v12.1.7 版本。
作为替代方法,您可以直接在 _document
的 <Head>
和 defer
属性 中使用 <script>
标签。这与 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>
)
}