为什么带有 beforeInteractive 策略的下一个.js脚本标记不加载第三方脚本?



我试着理解next.js Script标签与策略beforeInteractive的工作原理。为了测试,我只使用lodash。但我一直得到一个ReferenceError: _是没有定义。我认为当一个脚本加载了beforeInteractive,它应该在我的页面组件内全局可用,因为它从服务器注入到初始Html中,我可以使用它,例如在useEffect钩子中改变一个div。有人能告诉我为什么它不起作用或者我做错了什么吗?我没有通过npm安装它,因为我想弄清楚它是如何工作的。

我有一个简单的_document.js,我添加了一个Next.js脚本标签与策略beforeInteractive到这个_document.js。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>
)
}

然后我有一个简单的页面组件在页面文件夹。我添加了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

撇开应该将Lodash作为节点模块导入的事实不谈,在_document中使用next/script时(无论外部脚本实际是什么)似乎确实存在问题。

原来这是一个Next.js的错误,已经在预发布版本v12.1.7-canary.8中解决了。要解决项目中的问题,只需将Next.js更新到版本>=12.2.0 (npm install next@latest)。


作为替代方案,您可以直接在_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>
)
}

首先,当您可以(并且应该)简单地将其安装到node_modules上时,我没有看到您想要这样做的任何理由。如果库类型不是模块,而下一个配置需要一个模块,那么你还可能面临bundle出现问题的风险。

基于问题的解决方案:

有两种方法。首先,请参阅有关此内容的文档。

请使用文档中提到的上述方法。

如果由于某种原因不能…

第二个是一个不太理想的,但有效的解决方案。

为静态文件创建一个文件夹。例如:<root>/static/js/hello.js。然后在_document文件中,

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

最新更新