由于根据页面大小手动比较两个 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) 服务器可能会返回您的 html 的缩小版本,因此您需要缩进它以使其与您的客户端 html 匹配,为此使用 like this。
5) 完成此操作后,您现在可以在终端中运行实际的差异:
diff server.html client.html
这将列出文件中彼此不同的每个部分。
您可以忽略与 Javascript 相关的差异,因为缩进很可能是不好的,但专注于 html 的差异,您可能能够发现差异并推断出了什么问题。
就您而言,您的翻译系统可能是问题的根本原因。我建议遵循更多的标准做法,而不是 next-i18next,这似乎很新,而且更有可能出现问题。其他人显然也有带有 SSR 的 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 实例。完整的 SSR 文档是 here。