React/nextJS:如何调试 s-s-r react 应用的不同节点?

Posted

技术标签:

【中文标题】React/nextJS:如何调试 s-s-r react 应用的不同节点?【英文标题】:React/nextJS: How to debug different nodes of s-s-r react application? 【发布时间】:2019-05-03 09:58:07 【问题描述】:

我正在运行一个运行 s-s-r 的 nextJS 应用程序。

但我确实得到了错误:

警告:不希望服务器 html

中包含 。

所以服务器端和客户端节点之间似乎存在差异。我怎样才能找到这些差异?

这是一个示例应用的 repo:

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

只需运行 npm installnpm run dev

【问题讨论】:

【参考方案1】:

由于根据页面大小手动比较两个 html 可能相当麻烦,因此建议首先评估可能出现的问题,而不是暴力破解。根据我在 99% 的案例中的经验,当您出现以下任一情况时,就会发生 s-s-r 不匹配:

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

如果在此之后没有任何想法,您需要通过消除来继续。如果每个页面都发生错误,则很可能是服务器配置错误造成的。例如,您是否在做自己的renderToString?仔细检查你没有在其中添加额外的嵌套 div,字符串应该在你安装 React 的元素内。

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

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


作为最后的手段,您可能会在服务器响应和客户端首次呈现之间创建自己的diff

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

console.log(document.documentElement.innerHTML)

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

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

curl YOUR_URL > server.html 

4) 服务器可能会返回您的 html 的缩小版本,因此您需要缩进它以使其与您的客户端 html 匹配,为此使用 like this。

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

diff server.html client.html

这将列出文件中彼此不同的每个部分。 您可以忽略与 javascript 相关的差异,因为缩进很可能是不好的,但专注于 html 的差异,您可能能够发现差异并推断出了什么问题。


就您而言,您的翻译系统可能是问题的根本原因。我建议遵循更多的标准做法,而不是 next-i18next,这似乎很新,而且更有可能出现问题。其他人显然也有带有 s-s-r 的 an issue,老实说 like this 是相当可怕的。

我知道设置起来可能有点麻烦,但这是我自己的 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

您只需要使用中间件,从您的服务器提供区域设置,以便客户端可以从 xhr 加载它们并让 I18nextProvider 需要 i18n 实例。完整的 s-s-r 文档是 here。

【讨论】:

我已经用一个示例 repo 更新了帖子。你能看一下吗? 已更新,但尽量不要过多偏离原来的问题,因为这完全是另一个问题 感谢您的纯美文章。实际上,这是创建 s-s-r 应用程序的难点,我的意思是发现不匹配错误。上述两个原因可能与找到问题的确切位置是分不开的。真的很感谢@Balthazar?【参考方案2】:

我会首先查看到达浏览器的 html(chrome devtools 中的网络选项卡),然后 react 可能正在渲染客户端,因此您可以在客户端渲染和比较后看到当前 DOM(转到chrome devtools中的元素选项卡->右键单击html元素并选择“复制>复制outterHTML”)

如果失败了,你可以尝试在浏览器里面添加断点: 函数canHydrateInstance@ReactDOMHostConfig.js

https://github.com/facebook/react/blob/c954efa70f44a44be9c33c60c57f87bea6f40a10/packages/react-dom/src/client/ReactDOMHostConfig.js

可能与同类问题相关的链接:

React 16 warning "warning.js:36 Warning: Did not expect server HTML to contain a <div> in <div>."

https://github.com/zeit/next.js/issues/5367

【讨论】:

如何从服务器获取 html - 发送到浏览器?我正在使用铬。我在网络选项卡中没有看到 html... 这是第一个请求。清除网络标签中的请求(红圈旁边的“禁止”图标),然后刷新页面 也检查一下,看看它最终是否与您遇到的问题相同github.com/zeit/next.js/issues/5367 我想我也有同样的问题:***.com/questions/45350360/… 我只是将网络标签中的代码与浏览器源代码进行了比较,它是相同的......

以上是关于React/nextJS:如何调试 s-s-r react 应用的不同节点?的主要内容,如果未能解决你的问题,请参考以下文章

从零搭建一个基于React+Nextjs的SSR网站:如何搭建服务器并部署Nextjs项目

如何将Drift bot JS代码与静态React NextJs应用(着陆页)整合?

React + NextJS - 受保护的路线

如何在 nextjs 中使用 keycloak?

React/NextJS 使用 UseEffect 错误:渲染的钩子比上一次渲染期间更多

React - nextjs 在 useEffect 中调用自定义钩子