Skip to content

水合操作

水合:来自于英语的 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 会有两处变化:

  1. 之前是在文件内部创建的 Vue 实例,现在需要引入 app.js 的 createApp 方法来创建实例
  2. 需要提供静态资源服务,方便之后客户端能够请求到 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-