React/nextJS: 如何调试不同节点的SSR react应用?
React/nextJS: How to debug different nodes of SSR react application?
我正在 运行ning nextJS 应用程序,它是 运行ning SSR。
但是当我收到错误时:
Warning: Did not expect server HTML to contain a <div> in <div>.
因此服务器端和客户端节点之间似乎存在差异。我怎样才能找到这些差异?
这是示例应用程序的存储库:
https://github.com/jaqua/nextjs-app
只是 运行 npm install
和 npm run dev
我会首先查看进入浏览器的 html(chrome devtools 中的网络选项卡),然后 React 可能正在渲染客户端,因此您可以看到当前的 DOM 在客户端渲染和比较之后(转到 chrome devtools 中的元素选项卡 -> 右键单击 html 元素和 select "copy> copy outterHTML")
如果还是不行,你可以试试在浏览器里面react本身加断点:
函数 canHydrateInstance @ ReactDOMHostConfig.js
可能与同类问题相关的链接:
由于手动比较两个 html 可能相当麻烦,具体取决于页面的大小,建议首先评估可能出现的错误,而不是暴力破解。根据我在 99% 的情况下的经验,当您执行以下任一操作时,就会发生 SSR 不匹配:
- 包含并呈现了一个组件,该组件在客户端和服务器上的行为方式不同(例如,它们使用全局变量来确定代码的位置 运行 并基于此有条件地呈现元素) .例如,有一个剪贴板模块只能在客户端上工作,因为它会使用
window
. 变量
- 呈现从仅出现在服务器或客户端上的异步源获取的数据。您需要在初始渲染期间为两者提供相同的数据。
如果这之后什么都想不起来,就需要进行淘汰了。如果每个页面都出现错误,则很可能是服务器配置错误的结果。例如,你在做自己的 renderToString
吗?仔细检查你没有在其中添加额外的嵌套 div,字符串应该就在你挂载 React 的元素内。
如果不是这种情况,请尝试一个一个地提取您正在渲染的组件,您应该能够很快缩小导致问题的范围。
另外请记住,每次进行更改时都需要重新启动服务器(除非您有 nodemon 或类似的配置在您修改源代码时重新加载服务器端代码)才能应用它!
作为最后的手段,您可以在服务器响应和客户端首次呈现之间做出您自己的 diff
。
1) 从您的站点打开您的控制台,然后粘贴以下内容:
console.log(document.documentElement.innerHTML)
2) 单击 Copy
按钮,并将其粘贴到 client.html
文件中
3) 现在 运行 在您的终端中:
curl YOUR_URL > server.html
4) 服务器可能会 return 你 html 的缩小版本,所以你需要缩进它以使其与你的客户端匹配 html,为此目的使用一些东西like this。
5) 完成此操作后,您现在可以 运行 终端中的实际差异:
diff server.html client.html
这将列出文件中彼此不同的每个部分。
您可以忽略与 Javascript 相关的差异,因为缩进很可能无论如何都会很糟糕,但请专注于 html 的差异,您可以在其中发现差异并推断出问题所在。
在您的情况下,您的翻译系统很可能是问题的根本原因。我建议遵循更多标准做法,而不是 next-i18next
,后者看起来很新,而且更可能出现问题。别人貌似也有an issue with SSR, and to be honest stuff 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
实例。完整的 SSR 文档是 here.
我正在 运行ning nextJS 应用程序,它是 运行ning SSR。
但是当我收到错误时:
Warning: Did not expect server HTML to contain a <div> in <div>.
因此服务器端和客户端节点之间似乎存在差异。我怎样才能找到这些差异?
这是示例应用程序的存储库:
https://github.com/jaqua/nextjs-app
只是 运行 npm install
和 npm run dev
我会首先查看进入浏览器的 html(chrome devtools 中的网络选项卡),然后 React 可能正在渲染客户端,因此您可以看到当前的 DOM 在客户端渲染和比较之后(转到 chrome devtools 中的元素选项卡 -> 右键单击 html 元素和 select "copy> copy outterHTML")
如果还是不行,你可以试试在浏览器里面react本身加断点: 函数 canHydrateInstance @ ReactDOMHostConfig.js
可能与同类问题相关的链接:
由于手动比较两个 html 可能相当麻烦,具体取决于页面的大小,建议首先评估可能出现的错误,而不是暴力破解。根据我在 99% 的情况下的经验,当您执行以下任一操作时,就会发生 SSR 不匹配:
- 包含并呈现了一个组件,该组件在客户端和服务器上的行为方式不同(例如,它们使用全局变量来确定代码的位置 运行 并基于此有条件地呈现元素) .例如,有一个剪贴板模块只能在客户端上工作,因为它会使用
window
. 变量
- 呈现从仅出现在服务器或客户端上的异步源获取的数据。您需要在初始渲染期间为两者提供相同的数据。
如果这之后什么都想不起来,就需要进行淘汰了。如果每个页面都出现错误,则很可能是服务器配置错误的结果。例如,你在做自己的 renderToString
吗?仔细检查你没有在其中添加额外的嵌套 div,字符串应该就在你挂载 React 的元素内。
如果不是这种情况,请尝试一个一个地提取您正在渲染的组件,您应该能够很快缩小导致问题的范围。
另外请记住,每次进行更改时都需要重新启动服务器(除非您有 nodemon 或类似的配置在您修改源代码时重新加载服务器端代码)才能应用它!
作为最后的手段,您可以在服务器响应和客户端首次呈现之间做出您自己的 diff
。
1) 从您的站点打开您的控制台,然后粘贴以下内容:
console.log(document.documentElement.innerHTML)
2) 单击 Copy
按钮,并将其粘贴到 client.html
文件中
3) 现在 运行 在您的终端中:
curl YOUR_URL > server.html
4) 服务器可能会 return 你 html 的缩小版本,所以你需要缩进它以使其与你的客户端匹配 html,为此目的使用一些东西like this。
5) 完成此操作后,您现在可以 运行 终端中的实际差异:
diff server.html client.html
这将列出文件中彼此不同的每个部分。 您可以忽略与 Javascript 相关的差异,因为缩进很可能无论如何都会很糟糕,但请专注于 html 的差异,您可以在其中发现差异并推断出问题所在。
在您的情况下,您的翻译系统很可能是问题的根本原因。我建议遵循更多标准做法,而不是 next-i18next
,后者看起来很新,而且更可能出现问题。别人貌似也有an issue with SSR, and to be honest stuff 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
实例。完整的 SSR 文档是 here.