Skip to content

Commit 0661063

Browse files
committed
feat: more efficient useData() method that exposes all data
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.
1 parent e10fdbc commit 0661063

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1153
-1248
lines changed

src/client/app/components/Debug.vue

+9-10
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,8 @@
1-
<template>
2-
<div class="debug" :class="{ open }" ref="el" @click="open = !open">
3-
<p class="title">Debug</p>
4-
5-
<pre class="block">$page {{ $page }}</pre>
6-
<pre class="block">$siteByRoute {{ $siteByRoute }}</pre>
7-
<pre class="block">$site {{ $site }}</pre>
8-
</div>
9-
</template>
10-
111
<script setup lang="ts">
122
import { ref, watch } from 'vue'
3+
import { useData } from '../data'
134
5+
const data = useData()
146
const el = ref<HTMLElement | null>(null)
157
const open = ref(false)
168
@@ -21,6 +13,13 @@ watch(open, (value) => {
2113
})
2214
</script>
2315

16+
<template>
17+
<div class="debug" :class="{ open }" ref="el" @click="open = !open">
18+
<p class="title">Debug</p>
19+
<pre class="block">{{ data }}</pre>
20+
</div>
21+
</template>
22+
2423
<style scoped>
2524
.debug {
2625
box-sizing: border-box;

src/client/app/composables/frontmatter.ts

-9
This file was deleted.

src/client/app/composables/pageData.ts

-11
This file was deleted.

src/client/app/composables/siteData.ts

-22
This file was deleted.

src/client/app/composables/siteDataByRoute.ts

-12
This file was deleted.

src/client/app/data.ts

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { InjectionKey, Ref, ref, readonly, computed, inject } from 'vue'
2+
import { Route } from './router'
3+
import { PageData, SiteData } from '/@types/shared'
4+
import serializedSiteData from '@siteData'
5+
import { resolveSiteDataByRoute } from '../shared/config'
6+
7+
export const dataSymbol: InjectionKey<VitePressData> = Symbol()
8+
9+
export interface VitePressData {
10+
site: Ref<SiteData>
11+
theme: Ref<any>
12+
page: Ref<PageData>
13+
frontmatter: Ref<any>
14+
lang: Ref<string>
15+
localePath: Ref<string>
16+
title: Ref<string>
17+
description: Ref<string>
18+
}
19+
20+
// site data is a singleton
21+
export type SiteDataRef<T = any> = Ref<SiteData<T>>
22+
23+
export const siteDataRef: Ref<SiteData> = ref(parse(serializedSiteData))
24+
25+
function parse(data: string): SiteData {
26+
return readonly(JSON.parse(data)) as SiteData
27+
}
28+
29+
// hmr
30+
if (import.meta.hot) {
31+
import.meta.hot!.accept('/@siteData', (m) => {
32+
siteDataRef.value = parse(m.default)
33+
})
34+
}
35+
36+
// per-app data
37+
export function initData(route: Route): VitePressData {
38+
const site = computed(() =>
39+
resolveSiteDataByRoute(siteDataRef.value, route.path)
40+
)
41+
42+
return {
43+
site,
44+
theme: computed(() => site.value.themeConfig),
45+
page: computed(() => route.data),
46+
frontmatter: computed(() => route.data.frontmatter),
47+
lang: computed(() => site.value.lang),
48+
localePath: computed(() => {
49+
const { locales, lang } = site.value
50+
const path = Object.keys(locales).find((lp) => locales[lp].lang === lang)
51+
return (locales && path) || '/'
52+
}),
53+
title: computed(() => {
54+
return route.data.title
55+
? route.data.title + ' | ' + site.value.title
56+
: site.value.title
57+
}),
58+
description: computed(() => {
59+
return route.data.description || site.value.description
60+
})
61+
}
62+
}
63+
64+
export function useData(): VitePressData {
65+
const data = inject(dataSymbol)
66+
if (!data) {
67+
throw new Error('vitepress data not properly injected in app')
68+
}
69+
return data
70+
}

src/client/app/index.ts

+19-11
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,32 @@ import {
22
App,
33
createApp as createClientApp,
44
createSSRApp,
5+
defineAsyncComponent,
56
h,
67
onMounted,
78
watch
89
} from 'vue'
910
import { inBrowser, pathToFile } from './utils'
1011
import { Router, RouterSymbol, createRouter } from './router'
11-
import { mixinGlobalComputed, mixinGlobalComponents } from './mixin'
12-
import { siteDataRef } from './composables/siteData'
13-
import { useSiteDataByRoute } from './composables/siteDataByRoute'
14-
import { usePageData } from './composables/pageData'
12+
import { siteDataRef, useData } from './data'
1513
import { useUpdateHead } from './composables/head'
1614
import Theme from '/@theme/index'
1715
import { usePrefetch } from './composables/preFetch'
16+
import { dataSymbol, initData } from './data'
17+
import { Content } from './components/Content'
18+
import { ClientOnly } from './components/ClientOnly'
1819

1920
const NotFound = Theme.NotFound || (() => '404 Not Found')
2021

2122
const VitePressApp = {
2223
name: 'VitePressApp',
2324
setup() {
24-
const siteData = useSiteDataByRoute()
25+
const { site } = useData()
2526

2627
// change the language on the HTML element based on the current lang
2728
onMounted(() => {
2829
watch(
29-
() => siteData.value.lang,
30+
() => site.value.lang,
3031
(lang: string) => {
3132
document.documentElement.lang = lang
3233
},
@@ -51,16 +52,23 @@ export function createApp() {
5152

5253
app.provide(RouterSymbol, router)
5354

54-
const siteDataByRouteRef = useSiteDataByRoute(router.route)
55-
const pageDataRef = usePageData(router.route)
55+
const data = initData(router.route)
56+
app.provide(dataSymbol, data)
5657

5758
if (inBrowser) {
5859
// dynamically update head tags
59-
useUpdateHead(router.route, siteDataByRouteRef)
60+
useUpdateHead(router.route, data.site)
6061
}
6162

62-
mixinGlobalComputed(app, siteDataRef, siteDataByRouteRef, pageDataRef)
63-
mixinGlobalComponents(app)
63+
// install global components
64+
app.component('Content', Content)
65+
app.component('ClientOnly', ClientOnly)
66+
app.component(
67+
'Debug',
68+
import.meta.env.PROD
69+
? () => null
70+
: defineAsyncComponent(() => import('./components/Debug.vue'))
71+
)
6472

6573
if (Theme.enhanceApp) {
6674
Theme.enhanceApp({

src/client/app/mixin.ts

-95
This file was deleted.

src/client/app/utils.ts

+5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { siteDataRef } from './data'
12
import { inBrowser } from '/@shared/config'
23

34
export { inBrowser }
@@ -9,6 +10,10 @@ export function joinPath(base: string, path: string): string {
910
return `${base}${path}`.replace(/\/+/g, '/')
1011
}
1112

13+
export function withBase(path: string) {
14+
return joinPath(siteDataRef.value.base, path)
15+
}
16+
1217
/**
1318
* Converts a url path to the corresponding js chunk filename.
1419
*/

src/client/index.ts

+2-5
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,11 @@ export type { Router, Route } from './app/router'
88
export type { Theme, EnhanceAppContext } from './app/theme'
99

1010
// composables
11+
export { useData } from './app/data'
1112
export { useRouter, useRoute } from './app/router'
12-
export { useSiteData } from './app/composables/siteData'
13-
export { useSiteDataByRoute } from './app/composables/siteDataByRoute'
14-
export { usePageData } from './app/composables/pageData'
15-
export { useFrontmatter } from './app/composables/frontmatter'
1613

1714
// utilities
18-
export { inBrowser, joinPath } from './app/utils'
15+
export { inBrowser, joinPath, withBase } from './app/utils'
1916

2017
// components
2118
export { Content } from './app/components/Content'

0 commit comments

Comments
 (0)