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.
In entry-client.js
, we are simply mounting the app with this line:
// this assumes App.vue template root element has `id="app"`
app.$mount('#app')
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.
If you inspect the server-rendered output, you will notice that the app's root element has had a special attribute added:
<div id="app" data-server-rendered="true">
The data-server-rendered
special attribute lets the client-side Vue know that the markup is rendered by the server and it should mount in hydration mode. Note that it didn't add id="app"
, just the data-server-rendered
attribute: you need to add the ID or some other selector to the app's root element yourself or the app won't hydrate properly.
Note that on elements without the data-server-rendered
attribute, hydration can also be forced by passing true
to the hydrating
argument of $mount
:
// Force hydration of the app
app.$mount('#app', true)
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.
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>
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.