Vuejs 错误:客户端渲染的虚拟 DOM 树与服务器渲染的不匹配

IT技术 javascript vue.js vuejs2 nuxt.js
2021-01-27 23:27:51

我正在为我的应用程序使用 Nuxt.js / Vuejs,但我在不同的地方一直面临这个错误:

    The client-side rendered virtual DOM tree is not matching server-rendered content. 
This is likely caused by incorrect HTML markup, for example nesting block-level elements inside <p>, or missing <tbody>. 
Bailing hydration and performing full client-side render.

我想了解调试此错误的最佳方法是什么?他们是我可以记录/获取客户端和服务器的虚拟 DOM 树的一种方式,以便我可以比较并找出错误所在?

我的是一个大型应用程序,手动验证很困难。

6个回答

部分答案:使用 Chrome DevTools,您可以本地化问题并查看导致问题的确切因素。执行以下操作(我使用 Nuxt 5.6.0 和 Chrome 64.0.3282.186 执行此操作)

  1. 在 Chrome 中显示 DevTools (F12)
  2. 加载导致“客户端呈现的虚拟 DOM 树...”警告的页面。
  3. 滚动到 DevTools 控制台中的警告。
  4. 单击警告的源位置超链接(在我的例子中是 vue.runtime.esm.js:574)。
  5. 在那里设置断点(在源代码浏览器中左键单击行号)。
  6. 再次出现相同的警告。我并不是说这总是可能的,但就我而言,我只是重新加载了页面。如果有很多警告,您可以通过将鼠标移到msg变量上来检查消息
  7. 当您找到消息并在断点处停止时,请查看调用堆栈。单击向下一帧以调用“补丁”以打开其源代码。将鼠标悬停hydrate在执行行上方 4 行的函数调用上patch源的超链接hydrate将打开。
  8. hydrate函数中,从开始处移动大约 15 行,并在false返回后assertNodeMatch返回的位置设置断点false在那里设置断点并删除所有其他断点。
  9. 再次发出相同的警告。现在,当断点被击中时,执行应该在hydrate函数中停止切换到 DevTools 控制台并评估elm,然后vnode. 这里 elm 似乎是一个服务器渲染的 DOM 元素,而 vnode 是一个虚拟 DOM 节点。Elm 打印为 HTML,因此您可以找出错误发生的位置。
我发现这个博客根据@budden73 的回答发布了对这个错误的扩展解释,它实际上帮助我理解了这个问题。希望这可以帮助其他人:blog.lichter.io/posts/vue-hydration-error
2021-03-14 23:27:51
Nuxt 5.6.0,你活在未来?
2021-03-23 23:27:51
访问 hydr 函数执行的更快方法是在 Chrome 开发工具的控制台区域中展开错误,您可以在列表中看到它。只需单击同一行的@ 符号后的链接。例如水合物@commons.app.js:15934
2021-04-07 23:27:51

对我来说,这个错误发生了,因为获取数组列表AsyncData并渲染<tr>标签v-for,我把v-for代码放在<client-only>块中,问题解决了

@FelixEve 这个不再需要了,因为它被烘焙到 Nuxt 中。
2021-03-16 23:27:51
@Tekz,您可以在服务器端呈现表,只要确保行包含在<thead>,<tbody><tfoot>标签中(有关如何正确使用这些标签的参考,请参阅 MDN)
2021-03-22 23:27:51
如果您不使用 Nuxt,则需要安装vue-client-only
2021-04-04 23:27:51
这是否意味着我们无法呈现表服务器端?并将完整的 html 发送到浏览器?这真的破坏了 Nuxt 的 SSR 和 SEO 功能的概念。我遇到了同样的问题,可以用 <client-only> 块解决,但我猜这不是真正的解决方案
2021-04-05 23:27:51

这个错误调试起来真的很痛苦。为了快速获取导致问题的元素,请编辑node_modules/vue/dist/vue.esm.js并添加以下行:

// Search for this line: 
function hydrate (elm, vnode, insertedVnodeQueue, inVPre) {
    var i;
    var tag = vnode.tag;
    var data = vnode.data;
    var children = vnode.children;
    inVPre = inVPre || (data && data.pre);
    vnode.elm = elm;

    // Add the following lines: 
    console.log('elm', elm)
    console.log('vnode', vnode)
    console.log('inVpre', inVPre)
    // ...


您将在控制台中获得故障节点。

2.14.0在实现vue-particles包时,我遇到了与 nuxt 版本相同的问题解决方法是用 包围标签no-ssr并解决了问题。

编辑:
解决方案的更新变体(如果 Nuxt 版本高于2.9.0

<client-only>
  <vue-particles>
  </vue-particles>
</client-only>

旧解决方案:

<no-ssr>
  <vue-particles>
  </vue-particles>
</no-ssr>

有很多方法可以解决这个问题,但其中大多数都不是真正的修复,只是临时用的创可贴。注意几点:

  • 它包成<client-only>标签,有些提防重要的细节寿
  • 使用 av-show而不是 av-if
  • 试图破解一些生命周期
  • 等等...

我强烈推荐阅读亚历山大·利希特 (Alexander Lichter) 撰写的这篇精彩文章

https://blog.lichter.io/posts/vue-hydration-error/

他会向您解释,您应该诊断为什么会发生这种情况并解决实际问题。
基本上,每次与服务器上生成的内容不同时,以及在客户端上完成补水后可用的内容都会导致此错误。

其中一些是:

  • 无效的 HTML(在 a 中有一个块元素<p>a嵌套在另一个中标签也是如此,等等......)
  • 3rd 方脚本弄乱了您的组件
  • 服务器与客户端的不同状态
  • 任何随机都是有风险的(new Date()例如)
  • 任何与身份验证相关的页面

我强烈建议您阅读这篇文章,用 Alexandre 自己的话了解如何处理此类问题。如果您赶时间,您可以随时使用创可贴修复,但尝试实际修复问题以获得最佳性能并保持代码清洁。