React / nextJS:如何调试SSR react应用程序的不同节点?

use*_*695 8 javascript node.js reactjs next.js ssr

我正在运行nextJS应用程序,该应用程序正在运行SSR。

但是当我确实得到错误时:

警告:没想到服务器HTML在<div>中包含<div>。

因此,服务器端和客户端节点之间似乎存在差异。我如何找到这些差异?

这是一个示例应用程序的仓库:

https://github.com/jaqua/nextjs-app

只要运行npm installnpm run dev

Bal*_*zar 6

由于根据页面大小手动比较两个 html 可能会相当麻烦,因此建议首先评估可能出错的地方,而不是强制执行。根据我在 99% 的情况下的经验,当您执行以下任一操作时会发生 SSR 不匹配:

  • 包含并呈现一个在客户端和服务器上的行为方式不同的组件(例如,它们使用全局变量来确定代码正在运行的位置并基于此有条件地呈现元素)。例如,有一个剪贴板模块只能在客户端上工作,因为它会使用window.
  • 呈现从仅存在于服务器或客户端上的异步源获取的数据。您需要在初始渲染期间为两者提供相同的数据。

如果在这之后什么都没有想到,你需要通过消除来进行。如果每个页面都出现错误,则很可能是服务器配置错误的结果。例如,你是自己做的renderToString吗?仔细检查你没有在那里添加额外的嵌套 div,字符串应该就在你安装 React 的元素内部。

如果不是这种情况,请尝试一个一个提取您正在渲染的组件,您应该能够很快缩小导致问题的范围。

另请记住,每次进行更改时都需要重新启动服务器(除非您有一个 nodemon 或类似的配置在修改源代码时重新加载服务器端代码)才能应用它!


作为最后的手段,您可以diff在服务器响应和客户端第一次渲染之间创建自己的响应。

1) 从您的站点打开您的控制台,并粘贴以下内容:

console.log(document.documentElement.innerHTML)
Run Code Online (Sandbox Code Playgroud)

2)单击Copy按钮,并将其粘贴到client.html文件中

3)现在在你的终端中运行:

curl YOUR_URL > server.html 
Run Code Online (Sandbox Code Playgroud)

4) 服务器很可能会返回您的 html 的缩小版本,因此您需要缩进它以使其与您的客户端 html 匹配,为此目的使用类似的内容

5) 完成此操作后,您现在可以在终端中运行实际的差异:

diff server.html client.html
Run Code Online (Sandbox Code Playgroud)

这将列出彼此不同的文件的每个部分。您可以忽略与 Javascript 相关的差异,因为无论如何缩进很可能很糟糕,但请专注于 html 差异,您可以在其中发现差异并推断出问题所在。


在您的情况下,您的翻译系统很可能是问题的根本原因。我建议遵循更多的标准做法,而不是next-i18next那些看起来很新且更有可能出现问题的做法。其他人显然也对SSR有问题,说实话,像这样的事情很可怕。

我知道设置起来可能有点麻烦,但这里是我自己的 i18n 配置,如果您指定一个全局变量来确定您所在的环境(此处__BROWSER__),则服务器或客户端都可能需要该配置。

import i18n from 'i18next'
import LanguageDetector from 'i18next-browser-languagedetector'
import { reactI18nextModule } from 'react-i18next'

i18n
  .use(require(__BROWSER__ ? 'i18next-xhr-backend' : 'i18next-node-fs-backend'))
  .use(LanguageDetector)
  .use(reactI18nextModule)
  .init({
    fallbackLng: 'en',
    ns: ['translations'],
    defaultNS: 'translations',

    interpolation: {
      escapeValue: false,
    },

    react: {
      wait: true,
    },

    backend: {
      loadPath: __BROWSER__
        ? '/locales/{{lng}}/{{ns}}.json'
        : require('path').join(__dirname, '/locales/{{lng}}/{{ns}}.json'),
    },
  })

export default i18n
Run Code Online (Sandbox Code Playgroud)

您只需要使用中间件,从您的服务器提供语言环境,以便客户端可以从 xhr 加载它们并I18nextProvider需要i18n实例。完整的 SSR 文档在这里