如何将dom-操纵脚本包含到SSR Next.js App中

How to include dom-manipulating scripts into SSR Next.js App

我遇到以下错误:

Warning: Text content did not match. Server: "But I want to be altered by the client" Client: "Test"
    in div (at pages/index.tsx:17)
    in div (at pages/index.tsx:6)
    in HomePage (at _app.tsx:5)
    in MyApp
    in Container (created by AppContainer)
    in AppContainer

...具有以下设置:

一个 NextJS 应用程序组件:

function HomePage() {
  return (
    <>
      <div id="test-div">I am rendered on the server.</div>
      <script src="http://localhost:8080/bundle.js"></script>
    </>
  );
}

export default HomePage;

(注意:URL http://localhost:8080/bundle.js 假定 webpack-dev-server 是 运行 并提供该资源)

包含的 "example" 脚本:

const element = document.getElementById('test-div') as any;
element.innerHTML = 'But I want to be altered by the client';

在一个简单的设置中,我将只有一个静态 html 文件,声明一个 div 元素并包含 "example" 脚本。

但我想使用 NextJS,因为我想将动态 (SSR) 内容呈现到页面中(例如来自 cms 的文本内容)。

我注意到,有时(如果脚本执行需要更多时间)没有错误。只是在示例脚本中做一些耗时的事情。

另一种 hacky 方法是在示例脚本中使用 setTimeout。 在我知道为什么会这样之前,我不想这样做:

setTimeout(function() {
  const element = document.getElementById('test-div') as any;
  element.innerHTML = 'But I want to be altered by the client';
}, 20);

Next.js 11.0.0 及以上

您可以使用Next.js Script component加载第三方脚本。

// pages/index.js
import Script from 'next/script'

function Home() {
  return (
    <>
      <Script src="https://www.google-analytics.com/analytics.js" />
    </>
  )
}

使用 next/script,您可以定义 strategy 属性 并且 Next.js 将优化脚本的加载。

之前 Next.js 11.0.0

浏览器和 documentwindow 对象在服务器端呈现期间不可用。

您可以在 React 组件挂载后初始化操作 DOM 的脚本。

useEffect(() => init(), [])

要添加外部脚本,您可以执行以下操作:

useEffect(() => require('../babylon.js'), [])

要包含来自其他服务器的脚本,您可以添加 script 标签:

useEffect(() => {
  const script = document.createElement("script");
  script.src = "http://localhost:8080/bundle.js";
  script.async = true;
  document.body.appendChild(script);
},[])

如果您要添加 DOM 个侦听器,您还需要进行清理。

Using the Effect Hook

Effects with Cleanup

您也可以使用动态导入
https://nextjs.org/docs/advanced-features/dynamic-import#with-no-ssr