Skip to content

Commit

Permalink
fix(theme-default): avoid calling hooks in computed
Browse files Browse the repository at this point in the history
  • Loading branch information
Mister-Hope committed Jan 26, 2024
1 parent 5aea0d3 commit 6d78f5d
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 41 deletions.
19 changes: 14 additions & 5 deletions themes/theme-default/src/client/components/NavbarItems.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import NavbarDropdown from '@theme/NavbarDropdown.vue'
import { computed, ref } from 'vue'
import type { ComputedRef } from 'vue'
import { useRouter } from 'vue-router'
import type { Router } from 'vue-router'
import { useRouteLocale, useSiteData, useSiteLocaleData } from 'vuepress/client'
import { isLinkHttp, isString } from 'vuepress/shared'
import type {
Expand All @@ -13,12 +14,11 @@ import type {
} from '../../shared/index.js'
import {
DeviceType,
useNavLink,
useThemeData,
useThemeLocaleData,
useUpdateDeviceStatus,
} from '../composables/index.js'
import { resolveRepoType } from '../utils/index.js'
import { getNavLink, resolveRepoType } from '../utils/index.js'
/**
* Get navbar config of select language dropdown
Expand Down Expand Up @@ -129,23 +129,32 @@ const useNavbarRepo = (): ComputedRef<ResolvedNavbarItem[]> => {
}
const resolveNavbarItem = (
router: Router,
item: NavbarItem | NavbarGroup | string,
): ResolvedNavbarItem => {
if (isString(item)) {
return useNavLink(item)
return getNavLink(router, item)
}
if ((item as NavbarGroup).children) {
return {
...item,
children: (item as NavbarGroup).children.map(resolveNavbarItem),
children: (item as NavbarGroup).children.map((item) =>
resolveNavbarItem(router, item),
),
}
}
return item as ResolvedNavbarItem
}
const useNavbarConfig = (): ComputedRef<ResolvedNavbarItem[]> => {
const router = useRouter()
const themeLocale = useThemeLocaleData()
return computed(() => (themeLocale.value.navbar || []).map(resolveNavbarItem))
return computed(() =>
(themeLocale.value.navbar || []).map((item) =>
resolveNavbarItem(router, item),
),
)
}
const isMobile = ref(false)
Expand Down
20 changes: 15 additions & 5 deletions themes/theme-default/src/client/components/PageNav.vue
Original file line number Diff line number Diff line change
@@ -1,28 +1,31 @@
<script setup lang="ts">
import AutoLink from '@theme/AutoLink.vue'
import { computed } from 'vue'
import { useRoute } from 'vue-router'
import type { Router } from 'vue-router'
import { useRoute, useRouter } from 'vue-router'
import { usePageFrontmatter } from 'vuepress/client'
import { isPlainObject, isString } from 'vuepress/shared'
import type {
DefaultThemeNormalPageFrontmatter,
NavLink,
ResolvedSidebarItem,
} from '../../shared/index.js'
import { useNavLink, useSidebarItems } from '../composables/index.js'
import { useSidebarItems } from '../composables/index.js'
import { getNavLink } from '../utils/index.js'
/**
* Resolve `prev` or `next` config from frontmatter
*/
const resolveFromFrontmatterConfig = (
router: Router,
conf: unknown,
): null | false | NavLink => {
if (conf === false) {
return null
}
if (isString(conf)) {
return useNavLink(conf)
return getNavLink(router, conf)
}
if (isPlainObject<NavLink>(conf)) {
Expand Down Expand Up @@ -68,9 +71,13 @@ const resolveFromSidebarItems = (
const frontmatter = usePageFrontmatter<DefaultThemeNormalPageFrontmatter>()
const sidebarItems = useSidebarItems()
const route = useRoute()
const router = useRouter()
const prevNavLink = computed(() => {
const prevConfig = resolveFromFrontmatterConfig(frontmatter.value.prev)
const prevConfig = resolveFromFrontmatterConfig(
router,
frontmatter.value.prev,
)
if (prevConfig !== false) {
return prevConfig
}
Expand All @@ -79,7 +86,10 @@ const prevNavLink = computed(() => {
})
const nextNavLink = computed(() => {
const nextConfig = resolveFromFrontmatterConfig(frontmatter.value.next)
const nextConfig = resolveFromFrontmatterConfig(
router,
frontmatter.value.next,
)
if (nextConfig !== false) {
return nextConfig
}
Expand Down
2 changes: 0 additions & 2 deletions themes/theme-default/src/client/composables/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
export * from './useDarkMode.js'
export * from './useNavLink.js'
export * from './useResolveRouteWithRedirect.js'
export * from './useScrollPromise.js'
export * from './useSidebarItems.js'
export * from './useThemeData.js'
Expand Down
75 changes: 53 additions & 22 deletions themes/theme-default/src/client/composables/useSidebarItems.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { computed, inject, provide } from 'vue'
import type { ComputedRef, InjectionKey } from 'vue'
import { useRoute } from 'vue-router'
import { useRoute, useRouter } from 'vue-router'
import type { Router } from 'vue-router'
import { usePageData, usePageFrontmatter } from 'vuepress/client'
import type { PageHeader } from 'vuepress/client'
import type { PageData, PageHeader } from 'vuepress/client'
import { isPlainObject, isString, resolveLocalePath } from 'vuepress/shared'
import type {
DefaultThemeData,
Expand All @@ -12,7 +13,7 @@ import type {
SidebarConfigObject,
SidebarItem,
} from '../../shared/index.js'
import { useNavLink } from './useNavLink.js'
import { getNavLink } from '../utils/index.js'
import { useThemeLocaleData } from './useThemeData.js'

export type SidebarItemsRef = ComputedRef<ResolvedSidebarItem[]>
Expand All @@ -37,8 +38,18 @@ export const useSidebarItems = (): SidebarItemsRef => {
export const setupSidebarItems = (): void => {
const themeLocale = useThemeLocaleData()
const frontmatter = usePageFrontmatter<DefaultThemeNormalPageFrontmatter>()
const page = usePageData()
const route = useRoute()
const router = useRouter()

const sidebarItems = computed(() =>
resolveSidebarItems(frontmatter.value, themeLocale.value),
resolveSidebarItems(
frontmatter.value,
themeLocale.value,
page.value,
router,
route.path,
),
)
provide(sidebarItemsSymbol, sidebarItems)
}
Expand All @@ -51,6 +62,9 @@ export const setupSidebarItems = (): void => {
export const resolveSidebarItems = (
frontmatter: DefaultThemeNormalPageFrontmatter,
themeLocale: DefaultThemeData,
page: PageData,
router: Router,
path: string,
): ResolvedSidebarItem[] => {
// get sidebar config from frontmatter > theme data
const sidebarConfig = frontmatter.sidebar ?? themeLocale.sidebar ?? 'auto'
Expand All @@ -62,15 +76,27 @@ export const resolveSidebarItems = (
}

if (sidebarConfig === 'auto') {
return resolveAutoSidebarItems(sidebarDepth)
return resolveAutoSidebarItems(page, sidebarDepth)
}

if (Array.isArray(sidebarConfig)) {
return resolveArraySidebarItems(sidebarConfig, sidebarDepth)
return resolveArraySidebarItems(
page,
router,
path,
sidebarConfig,
sidebarDepth,
)
}

if (isPlainObject(sidebarConfig)) {
return resolveMultiSidebarItems(sidebarConfig, sidebarDepth)
return resolveMultiSidebarItems(
page,
router,
path,
sidebarConfig,
sidebarDepth,
)
}

return []
Expand Down Expand Up @@ -100,14 +126,13 @@ export const headersToSidebarItemChildren = (
* Resolve sidebar items if the config is `auto`
*/
export const resolveAutoSidebarItems = (
page: PageData,
sidebarDepth: number,
): ResolvedSidebarItem[] => {
const page = usePageData()

return [
{
text: page.value.title,
children: headersToSidebarItemChildren(page.value.headers, sidebarDepth),
text: page.title,
children: headersToSidebarItemChildren(page.headers, sidebarDepth),
},
]
}
Expand All @@ -116,18 +141,18 @@ export const resolveAutoSidebarItems = (
* Resolve sidebar items if the config is an array
*/
export const resolveArraySidebarItems = (
page: PageData,
router: Router,
path: string,
sidebarConfig: SidebarConfigArray,
sidebarDepth: number,
): ResolvedSidebarItem[] => {
const route = useRoute()
const page = usePageData()

const handleChildItem = (
item: ResolvedSidebarItem | SidebarItem | string,
): ResolvedSidebarItem => {
let childItem: ResolvedSidebarItem
if (isString(item)) {
childItem = useNavLink(item)
childItem = getNavLink(router, item)
} else {
childItem = item as ResolvedSidebarItem
}
Expand All @@ -141,12 +166,10 @@ export const resolveArraySidebarItems = (

// if the sidebar item is current page and children is not set
// use headers of current page as children
if (childItem.link === route.path) {
if (childItem.link === path) {
// skip h1 header
const headers =
page.value.headers[0]?.level === 1
? page.value.headers[0].children
: page.value.headers
page.headers[0]?.level === 1 ? page.headers[0].children : page.headers
return {
...childItem,
children: headersToSidebarItemChildren(headers, sidebarDepth),
Expand All @@ -163,12 +186,20 @@ export const resolveArraySidebarItems = (
* Resolve sidebar items if the config is a key -> value (path-prefix -> array) object
*/
export const resolveMultiSidebarItems = (
page: PageData,
router: Router,
path: string,
sidebarConfig: SidebarConfigObject,
sidebarDepth: number,
): ResolvedSidebarItem[] => {
const route = useRoute()
const sidebarPath = resolveLocalePath(sidebarConfig, route.path)
const sidebarPath = resolveLocalePath(sidebarConfig, path)
const matchedSidebarConfig = sidebarConfig[sidebarPath] ?? []

return resolveArraySidebarItems(matchedSidebarConfig, sidebarDepth)
return resolveArraySidebarItems(
page,
router,
path,
matchedSidebarConfig,
sidebarDepth,
)
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Router } from 'vue-router'
import type { NavLink } from '../../shared/index.js'
import { useResolveRouteWithRedirect } from './useResolveRouteWithRedirect.js'
import { getResolveRouteWithRedirect } from './getResolveRouteWithRedirect.js'

declare module 'vue-router' {
interface RouteMeta {
Expand All @@ -14,11 +15,11 @@ declare module 'vue-router' {
* - Input: '/README.md'
* - Output: { text: 'Home', link: '/' }
*/
export const useNavLink = (item: string): NavLink => {
export const getNavLink = (router: Router, item: string): NavLink => {
// the route path of vue-router is url-encoded, and we expect users are using
// non-url-encoded string in theme config, so we need to url-encode it first to
// resolve the route correctly
const resolved = useResolveRouteWithRedirect(encodeURI(item))
const resolved = getResolveRouteWithRedirect(router, encodeURI(item))
return {
text: resolved.meta.title || item,
link: resolved.name === '404' ? item : resolved.fullPath,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { useRouter } from 'vue-router'
import type { Router } from 'vue-router'
import { isFunction, isString } from 'vuepress/shared'

/**
* Resolve a route with redirection
*/
export const useResolveRouteWithRedirect = (
export const getResolveRouteWithRedirect = (
router: Router,
...args: Parameters<Router['resolve']>
): ReturnType<Router['resolve']> => {
const router = useRouter()
const route = router.resolve(...args)
const lastMatched = route.matched[route.matched.length - 1]
if (!lastMatched?.redirect) {
Expand All @@ -19,7 +18,7 @@ export const useResolveRouteWithRedirect = (
const resolvedRedirectObj = isString(resolvedRedirect)
? { path: resolvedRedirect }
: resolvedRedirect
return useResolveRouteWithRedirect({
return getResolveRouteWithRedirect(router, {
hash: route.hash,
query: route.query,
params: route.params,
Expand Down
2 changes: 2 additions & 0 deletions themes/theme-default/src/client/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export * from './getNavLink.js'
export * from './getResolveRouteWithRedirect.js'
export * from './isActiveSidebarItem.js'
export * from './resolveEditLink.js'
export * from './resolveRepoType.js'

0 comments on commit 6d78f5d

Please sign in to comment.