Skip to content

Commit

Permalink
fix(client): avoid mismatching between route path and page data (close
Browse files Browse the repository at this point in the history
  • Loading branch information
meteorlxy authored Aug 28, 2023
1 parent 1c2125c commit acbdc7f
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 24 deletions.
30 changes: 13 additions & 17 deletions packages/client/src/composables/pageData.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import type { PageData } from '@vuepress/shared'
import { readonly, ref } from 'vue'
import type { Ref } from 'vue'
import { pagesData } from './pagesData.js'
import { inject, type InjectionKey, readonly, type Ref } from 'vue'

export type { PageData }

Expand All @@ -11,6 +9,13 @@ export type { PageData }
export type PageDataRef<T extends Record<any, any> = Record<never, never>> =
Ref<PageData<T>>

/**
* Injection key for page data
*/
export const pageDataSymbol: InjectionKey<PageDataRef> = Symbol(
__VUEPRESS_DEV__ ? 'pageData' : '',
)

/**
* Empty page data to be used as the fallback value
*/
Expand All @@ -23,24 +28,15 @@ export const pageDataEmpty = readonly({
headers: [],
} as PageData) as PageData

/**
* Global page data ref
*/
export const pageData: PageDataRef = ref(pageDataEmpty)

/**
* Returns the ref of the data of current page
*/
export const usePageData = <
T extends Record<any, any> = Record<never, never>,
>(): PageDataRef<T> => pageData as PageDataRef<T>

if (__VUEPRESS_DEV__ && (import.meta.webpackHot || import.meta.hot)) {
// reuse vue HMR runtime
__VUE_HMR_RUNTIME__.updatePageData = (data: PageData) => {
pagesData.value[data.key] = () => Promise.resolve(data)
if (data.key === pageData.value.key) {
pageData.value = data
}
>(): PageDataRef<T> => {
const pageData = inject(pageDataSymbol)
if (!pageData) {
throw new Error('pageData() is called without provider.')
}
return pageData as PageDataRef<T>
}
20 changes: 16 additions & 4 deletions packages/client/src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import {
createMemoryHistory,
createRouter,
createWebHistory,
type Router,
START_LOCATION,
} from 'vue-router'
import type { Router } from 'vue-router'
import { pageData } from './composables/index.js'
import type { PageData } from './composables/index.js'
import { resolvers } from './resolvers.js'
import { createRoutes } from './routes.js'

Expand All @@ -32,10 +32,11 @@ export const createVueRouter = (): Router => {
},
})

// ensure page data and page component have been loaded before resolving the route,
// and save page data to route meta
router.beforeResolve(async (to, from) => {
if (to.path !== from.path || from === START_LOCATION) {
// ensure page data and page component have been loaded
;[pageData.value] = await Promise.all([
;[to.meta._data] = await Promise.all([
resolvers.resolvePageData(to.name as string),
pagesComponents[to.name as string]?.__asyncLoader(),
])
Expand All @@ -44,3 +45,14 @@ export const createVueRouter = (): Router => {

return router
}

declare module 'vue-router' {
interface RouteMeta {
/**
* Store page data to route meta
*
* @internal only for internal use
*/
_data: PageData
}
}
26 changes: 23 additions & 3 deletions packages/client/src/setupGlobalComputed.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { computedEager } from '@vueuse/core'
import { computedEager, computedWithControl } from '@vueuse/core'
import { type App, computed } from 'vue'
import type { Router } from 'vue-router'
import {
type LayoutsRef,
layoutsSymbol,
type PageData,
pageData,
type PageDataRef,
pageDataSymbol,
type PageFrontmatter,
type PageFrontmatterRef,
pageFrontmatterSymbol,
Expand All @@ -21,6 +21,7 @@ import {
pageLangSymbol,
type PageLayoutRef,
pageLayoutSymbol,
pagesData,
type RouteLocale,
type RouteLocaleRef,
routeLocaleSymbol,
Expand Down Expand Up @@ -59,13 +60,31 @@ export const setupGlobalComputed = (
router: Router,
clientConfigs: ClientConfig[],
): GlobalComputed => {
const layouts = computed(() => resolvers.resolveLayouts(clientConfigs))
// create eager computed for route path and locale, so that route changes
// won't make all downstream computed re-evaluate
const routePath = computedEager(() => router.currentRoute.value.path)
const routeLocale = computedEager(() =>
resolvers.resolveRouteLocale(siteData.value.locales, routePath.value),
)

// load page data from route meta
const pageData = computedWithControl(
routePath,
() => router.currentRoute.value.meta._data,
)
// handle page data HMR
if (__VUEPRESS_DEV__ && (import.meta.webpackHot || import.meta.hot)) {
__VUE_HMR_RUNTIME__.updatePageData = (data: PageData) => {
pagesData.value[data.key] = () => Promise.resolve(data)
if (data.key === router.currentRoute.value.meta._data.key) {
router.currentRoute.value.meta._data = data
pageData.trigger()
}
}
}

// create other global computed
const layouts = computed(() => resolvers.resolveLayouts(clientConfigs))
const siteLocaleData = computed(() =>
resolvers.resolveSiteLocaleData(siteData.value, routeLocale.value),
)
Expand All @@ -91,6 +110,7 @@ export const setupGlobalComputed = (

// provide global computed
app.provide(layoutsSymbol, layouts)
app.provide(pageDataSymbol, pageData)
app.provide(pageFrontmatterSymbol, pageFrontmatter)
app.provide(pageHeadTitleSymbol, pageHeadTitle)
app.provide(pageHeadSymbol, pageHead)
Expand Down

0 comments on commit acbdc7f

Please sign in to comment.