水合:来自于英语的 Hydration,是从自然界的“水合作用”借用过来的术语。在自然界,水合作用是指水分子与某种物质结合,形成一个更复杂的结构或使物质变得活跃和可用。
在前端框架中,静态 HTML 就像“干燥”的物质,它是没有交互功能的静态内容。前端 JS 就像水分子,当 JS 代码执行并与静态 HTML 结合时,这个静态页面变得“活跃”并具有交互功能。因此,称这个过程为“水合”(hydration),因为它类似于给静态内容“注入生命”,使其变得动态和可交互。
接下来我们需要在客户端做水合操作,使其可以交互。
重构 app.js
import { createSSRApp } from 'vue'
export function createApp() { // 返回一个实例 return createSSRApp({ template: ` <div> <h1>Hello, Server-Side Rendering!</h1> <p>{{ message }}</p> <button @click="count++">{{ count }}</button> </div> `, data: () => ({ count: 1, message: 'This is a server-side rendered page', }), })}提供客户端和服务端两个文件:
client.js
import { createApp } from './app.js'createApp().mount('#app')客户端文件就是引入创建 Vue 实例的方法,然后创建 Vue 实例,挂载到 div#app 节点上面。
server.js 会有两处变化:
- 之前是在文件内部创建的 Vue 实例,现在需要引入 app.js 的 createApp 方法来创建实例
- 需要提供静态资源服务,方便之后客户端能够请求到 client.js
最后是 index.html 模板的变化:
<!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> {{ meta }} <title>{{ title }}</title> </head> <body> <!-- 注意这里一定要保证挂载点和外层div在同一行,否则会找不到挂载点 --> <div id="app"><!--vue-ssr-outlet--></div> <script type="importmap"> { "imports": { "vue": "https://unpkg.com/vue@3/dist/vue.esm-browser.js" } } </script> <script type="module" src="/client.js"></script> </body></html>相比之前的模板,这里新增了两个 script 标签,第一个是通过 CDN 的方式引入 Vue,第二个就是请求 client.js 文件。
客户端和服务器端渲染出来的页面结构是完全相同的,这种方式又被称之为“同构”。并且必须一致,如果不一致会报错:Hydration is mismatch.
-EOF-