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">
|
<script setup lang="ts">
|
||||||
import { useSideBar } from '../composables/sideBar'
|
import { useSideBar } from '../composables/sideBar'
|
||||||
import { SideBarLink } from './SideBarLink'
|
import { SideBarLink } from './SideBarLink'
|
||||||
|
|
||||||
const items = useSideBar()
|
const items = useSideBar()
|
||||||
</script>
|
</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