跳至內容

SSR 相容性

VitePress 在生產建置期間使用 Vue 的伺服器端渲染 (SSR) 功能,在 Node.js 中預先渲染應用程式。這表示主題元件中的所有自訂程式碼都受 SSR 相容性約束。

官方 Vue 文件中的 SSR 區段 提供更多關於 SSR 的內容、SSR / SSG 之間的關係,以及撰寫 SSR 友善程式碼的常見注意事項。經驗法則是在 Vue 元件的 beforeMountmounted 鉤子中存取瀏覽器 / DOM API。

<ClientOnly>

如果您使用或展示非 SSR 友善的元件(例如包含自訂指令),您可以將它們包裝在內建的 <ClientOnly> 元件中

md
<ClientOnly>
  <NonSSRFriendlyComponent />
</ClientOnly>

在導入時存取瀏覽器 API 的函式庫

有些元件或函式庫會在導入時存取瀏覽器 API。若要使用在導入時假設瀏覽器環境的程式碼,您需要動態導入它們。

在 Mounted 鉤子中導入

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

onMounted(() => {
  import('./lib-that-access-window-on-import').then((module) => {
    // use code
  })
})
</script>

條件式導入

您也可以使用 import.meta.env.SSR 旗標(Vite 環境變數 的一部分)有條件地導入依賴項

js
if (!import.meta.env.SSR) {
  import('./lib-that-access-window-on-import').then((module) => {
    // use code
  })
}

由於 Theme.enhanceApp 可以是非同步的,因此您可以有條件地導入和註冊在導入時存取瀏覽器 API 的 Vue 外掛程式

js
// .vitepress/theme/index.js
/** @type {import('vitepress').Theme} */
export default {
  // ...
  async enhanceApp({ app }) {
    if (!import.meta.env.SSR) {
      const plugin = await import('plugin-that-access-window-on-import')
      app.use(plugin.default)
    }
  }
}

如果您使用 TypeScript

ts
// .vitepress/theme/index.ts
import type { Theme } from 'vitepress'

export default {
  // ...
  async enhanceApp({ app }) {
    if (!import.meta.env.SSR) {
      const plugin = await import('plugin-that-access-window-on-import')
      app.use(plugin.default)
    }
  }
} satisfies Theme

defineClientComponent

VitePress 提供一個方便的輔助程式,用於匯入在匯入時存取瀏覽器 API 的 Vue 元件。

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

const ClientComp = defineClientComponent(() => {
  return import('component-that-access-window-on-import')
})
</script>

<template>
  <ClientComp />
</template>

您也可以將 props/children/slots 傳遞給目標元件

vue
<script setup>
import { ref } from 'vue'
import { defineClientComponent } from 'vitepress'

const clientCompRef = ref(null)
const ClientComp = defineClientComponent(
  () => import('component-that-access-window-on-import'),

  // args are passed to h() - https://vuejs.org/api/render-function.html#h
  [
    {
      ref: clientCompRef
    },
    {
      default: () => 'default slot',
      foo: () => h('div', 'foo'),
      bar: () => [h('span', 'one'), h('span', 'two')]
    }
  ],

  // callback after the component is loaded, can be async
  () => {
    console.log(clientCompRef.value)
  }
)
</script>

<template>
  <ClientComp />
</template>

目標元件只會在包裝元件的 mounted 鉤子中匯入。

在 MIT 授權條款下釋出。