SSR 相容性
VitePress 在生產建置期間使用 Vue 的伺服器端渲染 (SSR) 功能,在 Node.js 中預先渲染應用程式。這表示主題元件中的所有自訂程式碼都受 SSR 相容性約束。
官方 Vue 文件中的 SSR 區段 提供更多關於 SSR 的內容、SSR / SSG 之間的關係,以及撰寫 SSR 友善程式碼的常見注意事項。經驗法則是在 Vue 元件的 beforeMount
或 mounted
鉤子中存取瀏覽器 / 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 鉤子中匯入。