API 浏览器
Quasar CLI with Webpack - @quasar/app-webpack
客户端水合

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:

  1. 在 Chrome 中显示 DevTools(F12)

    ¥Show DevTools in Chrome (F12)

  2. 加载导致 “客户端渲染的虚拟 DOM 树……” 警告的页面。

    ¥Load the page that causes “the client-side rendered virtual DOM tree…” warning.

  3. 滚动到 DevTools 控制台中的警告。

    ¥Scroll to the warning in DevTools console.

  4. 点击 vue.runtime.esm.js 中警告的源位置超链接。

    ¥Click at the source location hyperlink of the warning in vue.runtime.esm.js.

  5. 在此处设置断点(在源代码浏览器中的行号处单击鼠标左键)。

    ¥Set a breakpoint there (left-clicking at line number in the source code browser).

  6. 再次显示相同的警告。通常是通过重新加载页面来实现的。如果出现许多警告,你可以将鼠标移到 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.

  7. 当你找到消息并在断点处停止时,查看调用堆栈。点击下一行,调用 “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.

  8. 在 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 returned false. Set the breakpoint there and remove all other breakpoints.

  9. 再次显示相同的警告。现在,当断点触发时,执行应该在 hydrate 函数中停止。切换到 DevTools 控制台,依次评估 elmvnode。这里 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 then vnode. Here elm seems to be a server-rendered DOM element while vnode is a virtual DOM node. Elm is printed as HTML so you can figure out where the error happened.