解决 VitePress 由于引入不支持 SSR 的组件从而造成构建失败的问题
什么是 <ClientOnly>
?
<ClientOnly>
是 VuePress / VitePress 提供的一个特殊组件,用于确保其内容仅在客户端(浏览器)环境中渲染,而在服务器端渲染 (SSR) 阶段则不会进行渲染。
通过 <ClientOnly>
包裹的内容只有在客户端渲染时才会显示,这有助于防止在服务器渲染时尝试使用浏览器特有的 API 导致的错误。
服务端渲染 (SSR) 问题
在 SSR 模式下,页面首先在服务器端进行渲染,然后将预渲染的 HTML 发送到客户端,客户端接收到 HTML 后再进行接管。这个过程有助于提高页面的首次加载速度和 SEO 友好性。然而,并不是所有的 JavaScript 代码都能在服务器环境中运行,例如,直接操作 DOM、使用 window
或 document
对象等。
典型问题
当包含浏览器特有 API 的组件在 SSR 环境下渲染时,通常会抛出类似以下的错误:
ReferenceError: window is not defined
ReferenceError: document is not defined
- 第三方库依赖于浏览器环境而无法正常工作
例如,下述代码在 SSR 环境下将会报错,因为 navigator
这个 API 只有在浏览器环境中存在:
<template>
<div>
<p>User Agent: {{ userAgent }}</p>
</div>
</template>
<script>
export default {
data() {
return {
userAgent: navigator.userAgent,
};
},
};
</script>
<ClientOnly>
的作用
为了解决上述问题,VuePress / VitePress 提供了 <ClientOnly>
组件。通过将依赖浏览器 API 的部分代码包裹在 <ClientOnly>
中,可以避免在 SSR 过程中执行这些代码,防止出现错误。
示例
以下是一个使用 <ClientOnly>
的示例:
<template>
<div>
<client-only>
<p>User Agent: {{ userAgent }}</p>
</client-only>
</div>
</template>
<script>
export default {
data() {
return {
userAgent: '',
};
},
mounted() {
this.userAgent = navigator.userAgent;
},
};
</script>
在这个例子中,<p>User Agent: </p>
只有在浏览器环境下才会被渲染和执行。这确保了在服务器渲染阶段不会因 navigator 未定义而报错。
在 VitePress 中使用 <ClientOnly>
VitePress 是基于 Vite 构建的静态网站生成器,支持 Vue 3。与 VuePress 类似,VitePress 也可以使用 <ClientOnly>
组件来解决同样的问题。
使用示例
在 VitePress 中使用 <ClientOnly>
组件的方式与在 VuePress 中使用是相同的。以下是一个具体的例子:
<template>
<div>
<h1>Welcome to VitePress</h1>
<client-only>
<example-chart></example-chart>
</client-only>
</div>
</template>
<script>
import ExampleChart from './ExampleChart.vue'; // 假设 ExampleChart 组件依赖于浏览器 API
export default {
components: {
ExampleChart,
},
};
</script>
在这个例子中,<ExampleChart>
组件只有在客户端渲染时才会被挂载和执行。这样就可以避免在服务器渲染阶段因浏览器特有 API 不可用而导致的错误。
总结
在使用 VuePress 或 VitePress 构建静态网站时,可能会遇到一些组件依赖于浏览器环境的问题。通过使用 <ClientOnly>
组件,可以确保这些仅依赖于客户端环境的代码不会在服务端渲染时执行,从而提高应用的健壮性和可维护性。