mirror of https://github.com/vuejs/vitepress
BREAKING CHANGE: - Individual `useX()` data methods are removed. ```js // before import { useSiteDataByRoute, usePageData } from 'vitepress' const site = useSiteDataByRoute() const page = usePageData() const theme = computed(() => site.value.themeConfig) // after import { useData } from 'vitepress' const { site, page, theme } = useData() ``` All destructured values are computed refs injected from app root so they are created only once globally. - Global mixin properties (e.g. `$site`) are removed. Always use `useData()` to retrieve VitePress data.pull/314/head
parent
e10fdbcf34
commit
0661063d29
@ -1,9 +0,0 @@
|
||||
import { Ref, computed } from 'vue'
|
||||
import { usePageData } from './pageData'
|
||||
|
||||
export type FrontmatterRef = Ref<Record<string, any>>
|
||||
|
||||
export function useFrontmatter() {
|
||||
const pageData = usePageData()
|
||||
return computed(() => pageData.value.frontmatter)
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
import { Ref, computed } from 'vue'
|
||||
import { PageData } from '/@types/shared'
|
||||
import { Route, useRoute } from '../router'
|
||||
|
||||
export type PageDataRef = Ref<PageData>
|
||||
|
||||
export function usePageData(route?: Route) {
|
||||
const r = route || useRoute()
|
||||
|
||||
return computed(() => r.data)
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
import serialized from '@siteData'
|
||||
import { SiteData } from '/@types/shared'
|
||||
import { Ref, ref, readonly } from 'vue'
|
||||
|
||||
export type SiteDataRef<T = any> = Ref<SiteData<T>>
|
||||
|
||||
export const siteDataRef: Ref<SiteData> = ref(parse(serialized))
|
||||
|
||||
export function useSiteData<T = any>() {
|
||||
return siteDataRef as Ref<SiteData<T>>
|
||||
}
|
||||
|
||||
function parse(data: string): SiteData {
|
||||
return readonly(JSON.parse(data)) as SiteData
|
||||
}
|
||||
|
||||
// hmr
|
||||
if (import.meta.hot) {
|
||||
import.meta.hot!.accept('/@siteData', (m) => {
|
||||
siteDataRef.value = parse(m.default)
|
||||
})
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
import { computed } from 'vue'
|
||||
import { resolveSiteDataByRoute } from '/@shared/config'
|
||||
import { siteDataRef } from './siteData'
|
||||
import { Route, useRoute } from '../router'
|
||||
|
||||
export function useSiteDataByRoute(route?: Route) {
|
||||
const r = route || useRoute()
|
||||
|
||||
return computed(() => {
|
||||
return resolveSiteDataByRoute(siteDataRef.value, r.path)
|
||||
})
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
import { InjectionKey, Ref, ref, readonly, computed, inject } from 'vue'
|
||||
import { Route } from './router'
|
||||
import { PageData, SiteData } from '/@types/shared'
|
||||
import serializedSiteData from '@siteData'
|
||||
import { resolveSiteDataByRoute } from '../shared/config'
|
||||
|
||||
export const dataSymbol: InjectionKey<VitePressData> = Symbol()
|
||||
|
||||
export interface VitePressData {
|
||||
site: Ref<SiteData>
|
||||
theme: Ref<any>
|
||||
page: Ref<PageData>
|
||||
frontmatter: Ref<any>
|
||||
lang: Ref<string>
|
||||
localePath: Ref<string>
|
||||
title: Ref<string>
|
||||
description: Ref<string>
|
||||
}
|
||||
|
||||
// site data is a singleton
|
||||
export type SiteDataRef<T = any> = Ref<SiteData<T>>
|
||||
|
||||
export const siteDataRef: Ref<SiteData> = ref(parse(serializedSiteData))
|
||||
|
||||
function parse(data: string): SiteData {
|
||||
return readonly(JSON.parse(data)) as SiteData
|
||||
}
|
||||
|
||||
// hmr
|
||||
if (import.meta.hot) {
|
||||
import.meta.hot!.accept('/@siteData', (m) => {
|
||||
siteDataRef.value = parse(m.default)
|
||||
})
|
||||
}
|
||||
|
||||
// per-app data
|
||||
export function initData(route: Route): VitePressData {
|
||||
const site = computed(() =>
|
||||
resolveSiteDataByRoute(siteDataRef.value, route.path)
|
||||
)
|
||||
|
||||
return {
|
||||
site,
|
||||
theme: computed(() => site.value.themeConfig),
|
||||
page: computed(() => route.data),
|
||||
frontmatter: computed(() => route.data.frontmatter),
|
||||
lang: computed(() => site.value.lang),
|
||||
localePath: computed(() => {
|
||||
const { locales, lang } = site.value
|
||||
const path = Object.keys(locales).find((lp) => locales[lp].lang === lang)
|
||||
return (locales && path) || '/'
|
||||
}),
|
||||
title: computed(() => {
|
||||
return route.data.title
|
||||
? route.data.title + ' | ' + site.value.title
|
||||
: site.value.title
|
||||
}),
|
||||
description: computed(() => {
|
||||
return route.data.description || site.value.description
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export function useData(): VitePressData {
|
||||
const data = inject(dataSymbol)
|
||||
if (!data) {
|
||||
throw new Error('vitepress data not properly injected in app')
|
||||
}
|
||||
return data
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
import { App, defineAsyncComponent } from 'vue'
|
||||
import { joinPath } from './utils'
|
||||
import { SiteDataRef } from './composables/siteData'
|
||||
import { PageDataRef } from './composables/pageData'
|
||||
import { Content } from './components/Content'
|
||||
import { ClientOnly } from './components/ClientOnly'
|
||||
|
||||
export function mixinGlobalComputed(
|
||||
app: App,
|
||||
site: SiteDataRef,
|
||||
siteByRoute: SiteDataRef,
|
||||
page: PageDataRef
|
||||
): void {
|
||||
Object.defineProperties(app.config.globalProperties, {
|
||||
$site: {
|
||||
get() {
|
||||
return site.value
|
||||
}
|
||||
},
|
||||
|
||||
$siteByRoute: {
|
||||
get() {
|
||||
return siteByRoute.value
|
||||
}
|
||||
},
|
||||
|
||||
$themeConfig: {
|
||||
get() {
|
||||
return siteByRoute.value.themeConfig
|
||||
}
|
||||
},
|
||||
|
||||
$page: {
|
||||
get() {
|
||||
return page.value
|
||||
}
|
||||
},
|
||||
|
||||
$frontmatter: {
|
||||
get() {
|
||||
return page.value.frontmatter
|
||||
}
|
||||
},
|
||||
|
||||
$lang: {
|
||||
get() {
|
||||
return siteByRoute.value.lang
|
||||
}
|
||||
},
|
||||
|
||||
$localePath: {
|
||||
get() {
|
||||
const { locales } = site.value
|
||||
const { lang } = siteByRoute.value
|
||||
|
||||
const path = Object.keys(locales).find(
|
||||
(lp) => locales[lp].lang === lang
|
||||
)
|
||||
|
||||
return (locales && path) || '/'
|
||||
}
|
||||
},
|
||||
|
||||
$title: {
|
||||
get() {
|
||||
return page.value.title
|
||||
? page.value.title + ' | ' + siteByRoute.value.title
|
||||
: siteByRoute.value.title
|
||||
}
|
||||
},
|
||||
|
||||
$description: {
|
||||
get() {
|
||||
return page.value.description || siteByRoute.value.description
|
||||
}
|
||||
},
|
||||
|
||||
$withBase: {
|
||||
value(path: string) {
|
||||
return joinPath(site.value.base, path)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function mixinGlobalComponents(app: App) {
|
||||
app.component('Content', Content)
|
||||
app.component('ClientOnly', ClientOnly)
|
||||
app.component(
|
||||
'Debug',
|
||||
import.meta.env.PROD
|
||||
? () => null
|
||||
: defineAsyncComponent(() => import('./components/Debug.vue'))
|
||||
)
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
<template>
|
||||
<ul v-if="items.length > 0" class="sidebar-links">
|
||||
<SideBarLink v-for="item of items" :key="item.text" :item="item" />
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useSideBar } from '../composables/sideBar'
|
||||
import { SideBarLink } from './SideBarLink'
|
||||
|
||||
const items = useSideBar()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ul v-if="items.length > 0" class="sidebar-links">
|
||||
<SideBarLink v-for="item of items" :item="item" />
|
||||
</ul>
|
||||
</template>
|
||||
|
@ -1,13 +0,0 @@
|
||||
import { useSiteData, joinPath } from 'vitepress'
|
||||
|
||||
export function useUrl() {
|
||||
const site = useSiteData()
|
||||
|
||||
function withBase(path: string): string {
|
||||
return joinPath(site.value.base, path)
|
||||
}
|
||||
|
||||
return {
|
||||
withBase
|
||||
}
|
||||
}
|
Loading…
Reference in new issue