refactor(theme): improve theme options (#463)

This commit is contained in:
pengzhanbo 2025-02-16 15:02:57 +08:00 committed by GitHub
parent 6442ffa25a
commit b7ced3b501
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 80 additions and 53 deletions

View File

@ -3,8 +3,6 @@ import type {
AutoFrontmatterArray,
AutoFrontmatterMarkdownFile,
AutoFrontmatterObject,
AutoFrontmatterOptions,
PlumeThemeLocaleOptions,
} from '../../shared/index.js'
import { isArray, isEmptyObject, promiseParallel, toArray } from '@pengzhanbo/utils'
import chokidar from 'chokidar'
@ -34,10 +32,11 @@ export interface Generate {
let generate: Generate | null = null
export function initAutoFrontmatter(
localeOptions: PlumeThemeLocaleOptions,
autoFrontmatter: AutoFrontmatterOptions = {},
) {
export function initAutoFrontmatter() {
const { localeOptions, autoFrontmatter = {} } = getThemeConfig()
if (autoFrontmatter === false)
return
const { include, exclude, frontmatter = {} } = resolveOptions(localeOptions, autoFrontmatter)
const globFilter = createFilter(include, exclude, { resolve: false })

View File

@ -15,7 +15,11 @@ export function extendsBundlerOptions(bundlerOptions: any, app: App): void {
},
})
addViteOptimizeDepsInclude(bundlerOptions, app, '@vueuse/core', true)
addViteOptimizeDepsInclude(
bundlerOptions,
app,
['@vueuse/core', 'bcrypt-ts/browser', '@vuepress/helper/client', '@iconify/vue', '@iconify/vue/offline'],
)
addViteOptimizeDepsExclude(bundlerOptions, app, '@theme')
addViteSsrNoExternal(bundlerOptions, app, [

View File

@ -1,13 +1,13 @@
import type { TemplateRendererContext } from 'vuepress/utils'
import type { PlumeThemeLocaleOptions } from '../../shared/index.js'
import { templateRenderer } from 'vuepress/utils'
import { getThemeConfig } from '../loadConfig/index.js'
import { getThemePackage } from '../utils/index.js'
export function templateBuildRenderer(
template: string,
context: TemplateRendererContext,
options: PlumeThemeLocaleOptions,
) {
const { localeOptions: options } = getThemeConfig()
const pkg = getThemePackage()
template = template
.replace('{{ themeVersion }}', pkg.version || '')

View File

@ -1,19 +1,30 @@
import type { App, Page } from 'vuepress/core'
import type { PlumeThemeLocaleOptions } from '../../shared/index.js'
import { getRootLang } from '@vuepress/helper'
import { createPage } from 'vuepress/core'
import { getThemeConfig } from '../loadConfig/index.js'
import { perfLog, perfMark, withBase } from '../utils/index.js'
export async function createPages(app: App, localeOption: PlumeThemeLocaleOptions) {
if (localeOption.blog === false)
function getRootLang(app: App): string {
// infer from siteLocale
const siteLocales = app.siteData.locales
if (siteLocales['/']?.lang)
return siteLocales['/'].lang
return app.siteData.lang
}
export async function createPages(app: App) {
const { localeOptions } = getThemeConfig()
if (localeOptions.blog === false)
return
perfMark('create:blog-pages')
const pageList: Promise<Page>[] = []
const locales = localeOption.locales || {}
const locales = localeOptions.locales || {}
const rootLang = getRootLang(app)
const blog = localeOption.blog || {}
const blog = localeOptions.blog || {}
const link = blog.link || '/blog/'
for (const localePath of Object.keys(locales)) {
@ -24,7 +35,7 @@ export async function createPages(app: App, localeOption: PlumeThemeLocaleOption
if (blog.postList !== false) {
pageList.push(createPage(app, {
path: withBase(link, localePath),
frontmatter: { lang, _pageLayout: 'blog', title: opt.blogText || localeOption.blogText || 'Blog' },
frontmatter: { lang, _pageLayout: 'blog', title: opt.blogText || localeOptions.blogText || 'Blog' },
}))
}
@ -32,7 +43,7 @@ export async function createPages(app: App, localeOption: PlumeThemeLocaleOption
if (blog.tags !== false) {
pageList.push(createPage(app, {
path: withBase(blog.tagsLink || `${link}/tags/`, localePath),
frontmatter: { lang, _pageLayout: 'blog-tags', title: opt.tagText || localeOption.tagText || 'Tags' },
frontmatter: { lang, _pageLayout: 'blog-tags', title: opt.tagText || localeOptions.tagText || 'Tags' },
}))
}
@ -40,7 +51,7 @@ export async function createPages(app: App, localeOption: PlumeThemeLocaleOption
if (blog.archives !== false) {
pageList.push(createPage(app, {
path: withBase(blog.archivesLink || `${link}/archives/`, localePath),
frontmatter: { lang, _pageLayout: 'blog-archives', title: opt.archiveText || localeOption.archiveText || 'Archives' },
frontmatter: { lang, _pageLayout: 'blog-archives', title: opt.archiveText || localeOptions.archiveText || 'Archives' },
}))
}
@ -48,7 +59,7 @@ export async function createPages(app: App, localeOption: PlumeThemeLocaleOption
if (blog.categories !== false) {
pageList.push(createPage(app, {
path: withBase(blog.categoriesLink || `${link}/categories/`, localePath),
frontmatter: { lang, _pageLayout: 'blog-categories', title: opt.categoryText || localeOption.categoryText || 'Categories' },
frontmatter: { lang, _pageLayout: 'blog-categories', title: opt.categoryText || localeOptions.categoryText || 'Categories' },
}))
}
}

View File

@ -1,12 +1,13 @@
import type { Page } from 'vuepress/core'
import type { PlumeThemeLocaleOptions, PlumeThemePageData } from '../../shared/index.js'
import type { PlumeThemePageData } from '../../shared/index.js'
import { getThemeConfig } from '../loadConfig/index.js'
import { autoCategory } from './autoCategory.js'
import { enableBulletin } from './pageBulletin.js'
export function extendsPageData(
page: Page<PlumeThemePageData>,
localeOptions: PlumeThemeLocaleOptions,
) {
const { localeOptions } = getThemeConfig()
cleanPageData(page)
autoCategory(page, localeOptions)
enableBulletin(page, localeOptions)

View File

@ -1,7 +1,7 @@
import type { SeoPluginOptions } from '@vuepress/plugin-seo'
import type { SitemapPluginOptions } from '@vuepress/plugin-sitemap'
import type { App, PluginConfig } from 'vuepress/core'
import type { PlumeThemeLocaleOptions, PlumeThemePluginOptions } from '../../shared/index.js'
import type { PlumeThemePluginOptions } from '../../shared/index.js'
import { contentUpdatePlugin } from '@vuepress-plume/plugin-content-update'
import { fontsPlugin } from '@vuepress-plume/plugin-fonts'
import { searchPlugin } from '@vuepress-plume/plugin-search'
@ -23,6 +23,7 @@ import { sitemapPlugin } from '@vuepress/plugin-sitemap'
import { watermarkPlugin } from '@vuepress/plugin-watermark'
import { mdEnhancePlugin } from 'vuepress-plugin-md-enhance'
import { markdownPowerPlugin } from 'vuepress-plugin-md-power'
import { getThemeConfig } from '../loadConfig/index.js'
export interface SetupPluginOptions {
app: App
@ -31,16 +32,14 @@ export interface SetupPluginOptions {
cache?: false | 'memory' | 'filesystem'
}
export function getPlugins(
options: PlumeThemeLocaleOptions,
{
app,
pluginOptions,
hostname,
cache,
}: SetupPluginOptions,
): PluginConfig {
export function getPlugins({
app,
pluginOptions,
hostname,
cache,
}: SetupPluginOptions): PluginConfig {
const isProd = app.env.isBuild
const { localeOptions: options } = getThemeConfig()
const plugins: PluginConfig = [
fontsPlugin(),

View File

@ -1,12 +1,13 @@
import type { FSWatcher } from 'chokidar'
import type { App } from 'vuepress'
import type { PlumeThemeData, PlumeThemeLocaleOptions, PlumeThemePluginOptions } from '../../shared/index.js'
import type { PlumeThemeData, PlumeThemePluginOptions } from '../../shared/index.js'
import fs from 'node:fs/promises'
import process from 'node:process'
import { watch } from 'chokidar'
import { resolveImageSize } from 'vuepress-plugin-md-power'
import { hash } from 'vuepress/utils'
import { resolveThemeData } from '../config/resolveThemeData.js'
import { getThemeConfig } from '../loadConfig/index.js'
import { perfLog, perfMark, resolveContent, writeTemp } from '../utils/index.js'
let bulletinFileWatcher: FSWatcher | null = null
@ -16,10 +17,10 @@ process.on('exit', () => bulletinFileWatcher?.close())
export async function prepareThemeData(
app: App,
localeOptions: PlumeThemeLocaleOptions,
pluginOptions: PlumeThemePluginOptions,
): Promise<void> {
perfMark('prepare:theme-data')
const { localeOptions } = getThemeConfig()
const resolvedThemeData = resolveThemeData(app, localeOptions)
await resolveProfileImage(app, resolvedThemeData, pluginOptions)

View File

@ -1,9 +1,19 @@
import type { Page, Theme } from 'vuepress/core'
import type { PlumeThemeOptions, PlumeThemePageData } from '../shared/index.js'
import { sleep } from '@pengzhanbo/utils'
import { generateAutoFrontmatter, initAutoFrontmatter, watchAutoFrontmatter } from './autoFrontmatter/index.js'
import { extendsBundlerOptions, resolveAlias, resolveProvideData, resolveThemeOptions, templateBuildRenderer } from './config/index.js'
import { getThemeConfig, initConfigLoader, waitForConfigLoaded, watchConfigFile } from './loadConfig/index.js'
import {
generateAutoFrontmatter,
initAutoFrontmatter,
watchAutoFrontmatter,
} from './autoFrontmatter/index.js'
import {
extendsBundlerOptions,
resolveAlias,
resolveProvideData,
resolveThemeOptions,
templateBuildRenderer,
} from './config/index.js'
import { initConfigLoader, waitForConfigLoaded, watchConfigFile } from './loadConfig/index.js'
import { createPages, extendsPageData } from './pages/index.js'
import { getPlugins } from './plugins/index.js'
import { prepareData, watchPrepare } from './prepare/index.js'
@ -11,15 +21,18 @@ import { prepareThemeData } from './prepare/prepareThemeData.js'
import { resolve, templates, THEME_NAME } from './utils/index.js'
export function plumeTheme(options: PlumeThemeOptions = {}): Theme {
const { localeOptions, pluginOptions, hostname, configFile, cache } = resolveThemeOptions(options)
const {
localeOptions,
pluginOptions,
hostname,
configFile,
cache,
} = resolveThemeOptions(options)
return (app) => {
initConfigLoader(app, localeOptions, {
configFile,
onChange: ({ localeOptions, autoFrontmatter }) => {
if (autoFrontmatter !== false)
initAutoFrontmatter(localeOptions, autoFrontmatter)
},
onChange: initAutoFrontmatter,
})
return {
@ -33,17 +46,16 @@ export function plumeTheme(options: PlumeThemeOptions = {}): Theme {
alias: resolveAlias(),
plugins: getPlugins(getThemeConfig().localeOptions, { app, pluginOptions, hostname, cache }),
plugins: getPlugins({ app, pluginOptions, hostname, cache }),
extendsBundlerOptions,
templateBuildRenderer: (template, context) =>
templateBuildRenderer(template, context, getThemeConfig().localeOptions),
templateBuildRenderer,
extendsMarkdown: async (_, app) => {
const { autoFrontmatter, localeOptions } = await waitForConfigLoaded()
const { autoFrontmatter } = await waitForConfigLoaded()
if (autoFrontmatter !== false) {
initAutoFrontmatter(localeOptions, autoFrontmatter)
initAutoFrontmatter()
await generateAutoFrontmatter(app)
// wait for autoFrontmatter generated
// i/o performance
@ -51,22 +63,22 @@ export function plumeTheme(options: PlumeThemeOptions = {}): Theme {
}
},
extendsPage: async (page) => {
extendsPageData(page as Page<PlumeThemePageData>, getThemeConfig().localeOptions)
extendsPage: (page) => {
extendsPageData(page as Page<PlumeThemePageData>)
},
onInitialized: async (app) => {
await createPages(app, getThemeConfig().localeOptions)
await createPages(app)
},
onPrepared: async (app) => {
await prepareThemeData(app, getThemeConfig().localeOptions, pluginOptions)
await prepareThemeData(app, pluginOptions)
await prepareData(app)
},
onWatched: (app, watchers) => {
watchConfigFile(app, watchers, async ({ localeOptions }) => {
await prepareThemeData(app, localeOptions, pluginOptions)
watchConfigFile(app, watchers, async () => {
await prepareThemeData(app, pluginOptions)
await prepareData(app)
})
watchAutoFrontmatter(app, watchers)

View File

@ -16,5 +16,5 @@ export function getPackage() {
}
export function getThemePackage() {
return readJsonFileAsync(resolve('.../../package.json'))
return readJsonFileAsync(resolve('../../package.json'))
}