perf(theme): 优化侧边栏数据自动生成

This commit is contained in:
pengzhanbo 2024-07-10 00:57:52 +08:00
parent cfbea845a4
commit 766285e8f8
5 changed files with 91 additions and 15 deletions

View File

@ -116,7 +116,7 @@ export const zhNotes = definePlumeNotesConfig({
{
text: 'plugin-netlify-functions',
dir: 'netlify-functions',
link: '/plugins/plugin-netlify-functions/',
link: 'plugin-netlify-functions/',
items: [
'介绍',
'使用',

View File

@ -23,6 +23,7 @@ import { isActive, normalizeLink, normalizePrefix, resolveNavLink } from '../uti
import type { Sidebar, SidebarItem } from '../../shared/index.js'
import type { ResolvedSidebarItem } from '../../shared/resolved/sidebar.js'
import { useData } from './data.js'
import { useEncrypt } from './encrypt.js'
export type SidebarData = Record<string, Sidebar>
@ -229,6 +230,7 @@ export function useSidebar(): UseSidebarReturn {
const { theme, frontmatter, page } = useData()
const routeLocal = useRouteLocale()
const is960 = useMediaQuery('(min-width: 960px)')
const { isPageDecrypted } = useEncrypt()
const isOpen = ref(false)
@ -257,6 +259,13 @@ export function useSidebar(): UseSidebarReturn {
const hasAside = computed(() => {
if (frontmatter.value.pageLayout === 'home' || frontmatter.value.home)
return false
if (frontmatter.value.pageLayout === 'friends' || frontmatter.value.friends)
return false
if (!isPageDecrypted.value)
return false
if (frontmatter.value.aside != null)
return !!frontmatter.value.aside
return theme.value.aside !== false

View File

@ -101,7 +101,7 @@ export function resolveOptions(
const note = findNote(relativePath)
if (note?.text)
return note.text
return getCurrentDirname(note?.dir, relativePath) || ''
return getCurrentDirname('', relativePath) || ''
},
...baseFrontmatter,
permalink(permalink: string, { relativePath }, data: any) {

View File

@ -1,6 +1,17 @@
import type { App, Page } from 'vuepress'
import { entries, isArray, isPlainObject, removeLeadingSlash } from '@vuepress/helper'
import type { PlumeThemeLocaleOptions, PlumeThemePageData, Sidebar, SidebarItem, ThemeIcon } from '../../shared/index.js'
import {
entries,
isArray,
isPlainObject,
removeLeadingSlash,
} from '@vuepress/helper'
import type {
PlumeThemeLocaleOptions,
PlumeThemePageData,
Sidebar,
SidebarItem,
ThemeIcon,
} from '../../shared/index.js'
import { normalizeLink, resolveContent, writeTemp } from '../utils/index.js'
import type { ResolvedSidebarItem } from '../../shared/resolved/sidebar.js'
@ -53,6 +64,14 @@ function getSidebarData(
return resolved
}
const MD_RE = /\.md$/
const NUMBER_RE = /^\d+\./
function resolveTitle(dirname: string) {
return dirname
.replace(MD_RE, '')
.replace(NUMBER_RE, '')
}
function getAutoDirSidebar(
app: App,
localePath: string,
@ -80,6 +99,7 @@ function getAutoDirSidebar(
}
const RE_INDEX = ['index.md', 'README.md', 'readme.md']
const result: ResolvedSidebarItem[] = []
for (const page of pages) {
const { data, title, path, frontmatter } = page
@ -90,25 +110,37 @@ function getAutoDirSidebar(
let index = 0
let dir: string
let items = result
let parent: ResolvedSidebarItem | undefined
// eslint-disable-next-line no-cond-assign
while ((dir = paths[index])) {
const text = dir.replace(/\.md$/, '').replace(/^\d+\./, '')
const text = resolveTitle(dir)
const isHome = RE_INDEX.includes(dir)
let current = items.find(item => item.text === text)
if (!current) {
current = { text, link: undefined, items: [] } as ResolvedSidebarItem
!RE_INDEX.includes(dir) ? items.push(current) : items.unshift(current)
if (!isHome) {
items.push(current)
}
else {
!parent && items.unshift(current)
}
}
if (dir.endsWith('.md')) {
current.link = path
current.text = title
if (isHome && parent) {
parent.link = path
}
else {
current.link = path
current.text = title
}
}
if (frontmatter.icon)
if (frontmatter.icon) {
current.icon = frontmatter.icon as ThemeIcon
if (index > 0) {
current.collapsed = false
}
if (parent?.items?.length) {
parent.collapsed = true
}
parent = current
items = current.items as ResolvedSidebarItem[]
index++
}

View File

@ -2,17 +2,19 @@ import {
ensureLeadingSlash,
getRootLang,
getRootLangPath,
removeLeadingSlash,
} from '@vuepress/helper'
import type { App, Page } from 'vuepress/core'
import { createPage } from 'vuepress/core'
import { createFilter } from 'create-filter'
import type {
PageCategoryData,
PlumeThemeLocaleOptions,
PlumeThemePageData,
} from '../shared/index.js'
import { withBase } from './utils/index.js'
import { normalizePath, withBase } from './utils/index.js'
import { PRESET_LOCALES } from './locales/index.js'
import { resolveNotesLinkList } from './config/index.js'
import { resolveNotesLinkList, resolveNotesOptions } from './config/index.js'
export async function setupPage(
app: App,
@ -56,6 +58,35 @@ export async function setupPage(
app.pages.push(...await Promise.all(pageList))
}
const weakFilter = new WeakMap<PlumeThemeLocaleOptions, (id: string | undefined) => boolean>()
function createBlogFilter(localeOptions: PlumeThemeLocaleOptions) {
if (weakFilter.has(localeOptions))
return weakFilter.get(localeOptions)!
const blog = localeOptions.blog || {}
const notesList = resolveNotesOptions(localeOptions)
const notesDirList = notesList
.map(notes => removeLeadingSlash(normalizePath(`${notes.dir}/**`)))
.filter(Boolean)
const filter = createFilter(
blog.include ?? ['**/*.md'],
[
'**/{README,readme,index}.md',
'.vuepress/',
'node_modules/',
...(blog.exclude ?? []),
...notesDirList,
].filter(Boolean),
{ resolve: false },
)
weakFilter.set(localeOptions, filter)
return filter
}
export function extendsPageData(
page: Page<PlumeThemePageData>,
localeOptions: PlumeThemeLocaleOptions,
@ -63,6 +94,10 @@ export function extendsPageData(
page.data.filePathRelative = page.filePathRelative
page.routeMeta.title = page.frontmatter.title || page.title
if (createBlogFilter(localeOptions)(page.filePathRelative || '')) {
page.data.isBlogPost = true
}
if (page.frontmatter.icon) {
page.routeMeta.icon = page.frontmatter.icon
}