Skip to content

SSR 兼容性

VitePress 是一个静态站点生成器(SSG),它的工作原理是在构建时通过服务器端渲染(SSR)将每个页面渲染成静态 HTML。这意味着你的 Vue 组件代码不仅会在浏览器(客户端)中运行,也会在 Node.js 环境(服务器端)中运行。

因此,你需要确保你的代码是同构的(Isomorphic),即同一份代码能够在这两种环境中正确运行。这通常被称为“SSR 兼容性”。

浏览器/DOM 特有的 API

最常见的 SSR 不兼容问题是直接访问了仅存在于浏览器中的全局变量,如 windowdocument

错误示例:

javascript
// 在组件的 <script setup> 或 created() 钩子中
// 这会在构建时(Node.js 环境)抛出错误,因为 Node.js 中没有 window 对象
const width = window.innerWidth;

正确做法:

将访问浏览器特有 API 的代码移动到只在客户端执行的生命周期钩子中,最常用的是 onMounted

vue
<script setup>
import { ref, onMounted } from 'vue'

const width = ref(0)

// onMounted 钩子只会在组件被挂载到 DOM 后(即在浏览器中)执行
onMounted(() => {
  width.value = window.innerWidth
})
</script>

VitePress 提供的辅助工具

VitePress 提供了一些内置的辅助工具来帮助你处理 SSR 兼容性问题。

<ClientOnly /> 组件

如果你有一个组件不兼容 SSR,或者你只想让它在客户端渲染(例如,一个包含大量交互且对 SEO 不重要的组件),你可以使用 <ClientOnly /> 组件来包裹它。

vue
<template>
  <div>
    <p>这部分内容会被 SSR 渲染。</p>
    <ClientOnly>
      <!-- 这部分内容以及它的子组件只会在客户端渲染 -->
      <MyInteractiveComponent />
    </ClientOnly>
  </div>
</template>

inBrowser 常量

VitePress 提供了一个 inBrowser 常量,你可以用它来有条件地执行只应在浏览器中运行的代码。

vue
<script setup>
import { inBrowser } from 'vitepress'

if (inBrowser) {
  // 这里的代码只会在浏览器环境中执行
  const geo = navigator.geolocation;
}
</script>

第三方库的兼容性

当你使用第三方库时,也要注意它的 SSR 兼容性。一些库可能假设它们只在浏览器环境中运行。

处理技巧:

  1. 检查文档:查看库的文档是否提到了 SSR 或 Nuxt/Next.js/VitePress 的用法。

  2. 动态导入:如果一个库不兼容 SSR,你可以在 onMounted 钩子中动态地 import() 它,确保它只在客户端被加载和执行。

    vue
    <script setup>
    import { onMounted } from 'vue'
    
    onMounted(async () => {
      const SomeLibrary = (await import('some-non-ssr-library')).default
      // 现在可以在这里使用 SomeLibrary
      const instance = new SomeLibrary()
    })
    </script>

确保代码的 SSR 兼容性是使用 VitePress 或任何现代前端框架进行静态站点生成时的关键一步,它可以避免构建错误,并确保你的网站能够被成功地预渲染。