Hydration 是指客户端处理过程,在此过程中,Vue 接管服务器发送的静态 HTML,并将其转换为可以响应客户端数据变化的动态 DOM。
¥Hydration refers to the client-side process during which Vue takes over the static HTML sent by the server and turns it into dynamic DOM that can react to client-side data changes.
由于服务器已经渲染了标记,我们显然不想丢弃它们并重新创建所有 DOM 元素。相反,我们希望将静态标记 “hydrate” 化并使其具有交互性。
¥Since the server has already rendered the markup, we obviously do not want to throw that away and re-create all the DOM elements. Instead, we want to “hydrate” the static markup and make it interactive.
警告
在开发模式下,Vue 将断言客户端生成的虚拟 DOM 树与服务器渲染的 DOM 结构匹配。如果存在不匹配的情况,它将放弃水合,丢弃现有 DOM 并从头开始渲染。在生产模式下,此断言被禁用以获得最佳性能。
¥In development mode, Vue will assert the client-side generated virtual DOM tree matches the DOM structure rendered from the server. If there is a mismatch, it will bail hydration, discard existing DOM and render from scratch. In production mode, this assertion is disabled for maximum performance.
Hydration 注意事项(Hydration Caveats)
¥Hydration Caveats
使用 SSR + 客户端数据融合时需要注意的是,一些特殊的 HTML 结构可能会被浏览器修改。例如,在 Vue 模板中编写以下内容:
¥One thing to be aware of when using SSR + client hydration is some special HTML structures that may be altered by the browser. For example, when you write this in a Vue template:
<table>
<tr><td>hi</td></tr>
</table>
浏览器会自动将 <tbody>
注入到 <table>
中,但是 Vue 生成的虚拟 DOM 不包含 <tbody>
,因此会导致不匹配。为确保正确匹配,请确保在模板中编写有效的 HTML。
¥The browser will automatically inject <tbody>
inside <table>
, however, the virtual DOM generated by Vue does not contain <tbody>
, so it will cause a mismatch. To ensure correct matching, make sure to write valid HTML in your templates.
处理 Hydration 错误(Handling Hydration Errors)
¥Handling Hydration Errors
如果你确实收到 Hydration 错误(如控制台中所示:“Vuejs 错误 - 客户端渲染的虚拟 DOM 树与服务端渲染的内容不匹配。”),你可以尝试以下步骤:
¥If you do receive hydration errors (as seen in console: “Vuejs Error - The client-side rendered virtual DOM tree is not matching server-rendered content”), you can try following these steps:
在 Chrome 中显示 DevTools(F12)
¥Show DevTools in Chrome (F12)
加载导致 “客户端渲染的虚拟 DOM 树……” 警告的页面。
¥Load the page that causes “the client-side rendered virtual DOM tree…” warning.
滚动到 DevTools 控制台中的警告。
¥Scroll to the warning in DevTools console.
点击 vue.runtime.esm.js 中警告的源位置超链接。
¥Click at the source location hyperlink of the warning in vue.runtime.esm.js.
在此处设置断点(在源代码浏览器中的行号处单击鼠标左键)。
¥Set a breakpoint there (left-clicking at line number in the source code browser).
再次显示相同的警告。通常是通过重新加载页面来实现的。如果出现许多警告,你可以将鼠标移到
msg
变量上来查看消息。¥Make the same warning appear again. Usually by reloading the page. If there are many warnings, you can check the message by moving a mouse over
msg
variable.当你找到消息并在断点处停止时,查看调用堆栈。点击下一行,调用 “patch” 打开其源代码。将鼠标悬停在 patch 中执行行上方 4 行的 hydrate 函数调用上。将打开指向 hydrate 源代码的超链接。
¥When you have found your message and stopped on a breakpoint, look at the call stack. Click one frame down to call to “patch” to open its source. Hover mouse over hydrate function call 4 lines above the execution line in patch. Hyperlink to the source of hydrate would open.
在 hydrate 函数中,从开头移动大约 15 行,并在
assertNodeMatch
返回false
后返回 false 的位置设置一个断点。在此处设置断点,并移除所有其他断点。¥In the hydrate function, move about 15 lines from the start and set a breakpoint where false is returned after
assertNodeMatch
returnedfalse
. Set the breakpoint there and remove all other breakpoints.再次显示相同的警告。现在,当断点触发时,执行应该在 hydrate 函数中停止。切换到 DevTools 控制台,依次评估
elm
和vnode
。这里elm
似乎是服务器渲染的 DOM 元素,而vnode
是虚拟 DOM 节点。Elm
会以 HTML 格式打印,以便你可以找出错误发生的位置。¥Make the same warning happen again. Now, when breakpoint is hit, execution should stop in the hydrate function. Switch to DevTools console and evaluate
elm
and thenvnode
. Hereelm
seems to be a server-rendered DOM element whilevnode
is a virtual DOM node.Elm
is printed as HTML so you can figure out where the error happened.