perf: 优化代码结构

This commit is contained in:
pengzhanbo 2023-12-28 15:30:56 +08:00
parent 0dc441a0e6
commit 7ab06863e7
7 changed files with 192 additions and 186 deletions

View File

@ -1,11 +1,3 @@
## scripts/autoInstall
检查各个 workspace package 中的 vuepress 相关依赖,并更新到最新版本。
``` sh
pnpm autoUpdate
```
## scripts/create
`packages/` 目录下生成一个新的 插件包

View File

@ -11,7 +11,6 @@ import NotFound from './layouts/NotFound.vue'
export default defineClientConfig({
enhance({ app, router }) {
// global component
app.component('Badge', Badge)
app.component('ExternalLinkIcon', ExternalLinkIcon)

View File

@ -1,6 +1,4 @@
import fs from 'node:fs'
import path from 'node:path'
import process from 'node:process'
import type { App } from '@vuepress/core'
import { resolveLocalePath } from '@vuepress/shared'
import type {
@ -8,28 +6,13 @@ import type {
FrontmatterArray,
FrontmatterObject,
} from '@vuepress-plume/plugin-auto-frontmatter'
import type { NotesItem } from '@vuepress-plume/plugin-notes-data'
import { format } from 'date-fns'
import { customAlphabet } from 'nanoid'
import { uniq } from '@pengzhanbo/utils'
import type {
PlumeThemeLocaleOptions,
PlumeThemePluginOptions,
} from '../shared/index.js'
const nanoid = customAlphabet('0123456789abcdefghijklmnopqrstuvwxyz', 8)
function getPackage() {
let pkg = {} as any
try {
const content = fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf-8')
pkg = JSON.parse(content)
}
catch {}
return pkg
}
function normalizePath(dir: string) {
return dir.replace(/\\+/g, '/')
}
import { getCurrentDirname, getPackage, nanoid, pathJoin } from './utils.js'
export default function autoFrontmatter(
app: App,
@ -38,17 +21,17 @@ export default function autoFrontmatter(
): AutoFrontmatterOptions {
const sourceDir = app.dir.source()
const pkg = getPackage()
const articlePrefix = localeOption.article || '/article/'
const { locales = {}, avatar, article: articlePrefix = '/article/' } = localeOption
const { frontmatter } = options
const locales = (app.siteData.locales || {}) as PlumeThemeLocaleOptions
const localesNotesDirs = Object.keys(locales)
const localesNotesDirs = Object.keys(app.siteData.locales || {})
.map((locale) => {
// fixed: #15
const notes = localeOption.locales?.[locale]?.notes
const notes = locales[locale]?.notes
if (!notes)
return ''
const dir = notes.dir
return dir ? normalizePath(path.join(locale, dir)).replace(/^\//, '') : ''
return notes.dir ? pathJoin(locale, notes.dir).replace(/^\//, '') : ''
})
.filter(Boolean)
@ -58,7 +41,7 @@ export default function autoFrontmatter(
return author
if (data.friends)
return
return localeOption.avatar?.name || pkg.author || ''
return avatar?.name || pkg.author || ''
},
createTime(formatTime: string, { createTime }, data: any) {
if (formatTime)
@ -70,20 +53,20 @@ export default function autoFrontmatter(
}
const resolveLocale = (filepath: string) => {
const file = normalizePath(
path.join('/', path.relative(sourceDir, filepath)),
)
const file = pathJoin('/', path.relative(sourceDir, filepath))
return resolveLocalePath(localeOption.locales!, file)
}
const notesByLocale = (locale: string) => {
const notes = localeOption.locales![locale]?.notes || localeOption.notes
const notes = locales[locale]?.notes || localeOption.notes
if (notes === false)
return undefined
return notes
}
const findNote = (filepath: string) => {
const file = path.join('/', path.relative(sourceDir, filepath))
const locale = resolveLocalePath(localeOption.locales!, normalizePath(file))
const file = pathJoin('/', path.relative(sourceDir, filepath))
const locale = resolveLocalePath(locales, file)
const notes = notesByLocale(locale)
if (!notes)
return undefined
@ -94,22 +77,15 @@ export default function autoFrontmatter(
)
}
const getCurrentDirname = (note: NotesItem | undefined, filepath: string) => {
const dirList = normalizePath(note?.dir || path.dirname(filepath))
.replace(/^\/|\/$/g, '')
.split('/')
return dirList.length > 0 ? dirList[dirList.length - 1] : ''
}
return {
include: options.frontmatter?.include ?? ['**/*.md'],
exclude: options.frontmatter?.exclude ?? ['.vuepress/**/*', 'node_modules'],
frontmatter: options.frontmatter?.frontmatter ?? [
include: frontmatter?.include ?? ['**/*.md'],
exclude: uniq(['.vuepress/**/*', 'node_modules', ...(frontmatter?.exclude ?? [])]),
frontmatter: [
localesNotesDirs.length
? {
// note 首页链接
include: localesNotesDirs.map(dir =>
normalizePath(path.join(dir, '**/{readme,README,index}.md')),
),
include: localesNotesDirs.map(dir => pathJoin(dir, '**/{readme,README,index}.md')),
frontmatter: {
title(title: string, { filepath }) {
if (title)
@ -117,7 +93,7 @@ export default function autoFrontmatter(
const note = findNote(filepath)
if (note?.text)
return note.text
return getCurrentDirname(note, filepath) || ''
return getCurrentDirname(note?.dir, filepath) || ''
},
...baseFrontmatter,
permalink(permalink: string, { filepath }, data: any) {
@ -128,13 +104,11 @@ export default function autoFrontmatter(
const locale = resolveLocale(filepath)
const notes = notesByLocale(locale)
const note = findNote(filepath)
return normalizePath(
path.join(
locale,
notes?.link || '',
note?.link || getCurrentDirname(note, filepath),
'/',
),
return pathJoin(
locale,
notes?.link || '',
note?.link || getCurrentDirname(note?.dir, filepath),
'/',
)
},
},
@ -142,9 +116,7 @@ export default function autoFrontmatter(
: '',
localesNotesDirs.length
? {
include: localesNotesDirs.map(dir =>
normalizePath(path.join(dir, '**/**.md')),
),
include: localesNotesDirs.map(dir => pathJoin(dir, '**/**.md')),
frontmatter: {
title(title: string, { filepath }) {
if (title)
@ -161,14 +133,12 @@ export default function autoFrontmatter(
const locale = resolveLocale(filepath)
const note = findNote(filepath)
const notes = notesByLocale(locale)
return normalizePath(
path.join(
locale,
notes?.link || '',
note?.link || getCurrentDirname(note, filepath),
nanoid(),
'/',
),
return pathJoin(
locale,
notes?.link || '',
note?.link || getCurrentDirname(note?.dir, filepath),
nanoid(),
'/',
)
},
},
@ -192,9 +162,7 @@ export default function autoFrontmatter(
if (permalink)
return permalink
const locale = resolveLocale(filepath)
return normalizePath(
path.join(locale, articlePrefix, nanoid(), '/'),
)
return pathJoin(locale, articlePrefix, nanoid(), '/')
},
},
},

View File

@ -18,8 +18,8 @@ import { iconifyPlugin } from '@vuepress-plume/plugin-iconify'
import { notesDataPlugin } from '@vuepress-plume/plugin-notes-data'
import { shikijiPlugin } from '@vuepress-plume/plugin-shikiji'
import { commentPlugin } from 'vuepress-plugin-comment2'
import { mdEnhancePlugin } from 'vuepress-plugin-md-enhance'
import { useReadingTimePlugin } from 'vuepress-plugin-reading-time2'
import { type MarkdownEnhanceOptions, mdEnhancePlugin } from 'vuepress-plugin-md-enhance'
import { readingTimePlugin } from 'vuepress-plugin-reading-time2'
import { seoPlugin } from 'vuepress-plugin-seo2'
import { sitemapPlugin } from 'vuepress-plugin-sitemap2'
import type {
@ -41,10 +41,7 @@ export function setupPlugins(app: App, options: PlumeThemePluginOptions, localeO
})
.filter(Boolean)
if (options.readingTime !== false)
useReadingTimePlugin(app, options.readingTime || {}, true)
return [
const plugins: PluginConfig = [
palettePlugin({ preset: 'sass' }),
themeDataPlugin({
@ -55,6 +52,7 @@ export function setupPlugins(app: App, options: PlumeThemePluginOptions, localeO
: undefined,
} as any,
}),
autoFrontmatterPlugin(autoFrontmatter(app, options, localeOptions)),
blogDataPlugin({
@ -85,8 +83,6 @@ export function setupPlugins(app: App, options: PlumeThemePluginOptions, localeO
},
}),
localeOptions.notes ? notesDataPlugin(localeOptions.notes) : [],
iconifyPlugin(),
activeHeaderLinksPlugin({
@ -95,103 +91,124 @@ export function setupPlugins(app: App, options: PlumeThemePluginOptions, localeO
delay: 200,
offset: 20,
}),
options.nprogress !== false ? nprogressPlugin() : [],
options.git !== false
? gitPlugin({
createdTime: false,
updatedTime: localeOptions.lastUpdated !== false,
contributors: localeOptions.contributors !== false,
})
: [],
options.mediumZoom !== false
? mediumZoomPlugin({
selector: '.plume-content > img, .plume-content :not(a) > img',
zoomOptions: {
background: 'var(--vp-c-bg)',
},
delay: 300,
})
: [],
options.caniuse !== false
? caniusePlugin(
options.caniuse || {
mode: 'embed',
},
)
: [],
options.externalLinkIcon !== false
? externalLinkIconPlugin({
locales: Object.entries(localeOptions.locales || {}).reduce(
(result: Record<string, any>, [key, value]) => {
result[key] = {
openInNewWindow:
value.openInNewWindow ?? localeOptions.openInNewWindow,
}
return result
},
{},
),
})
: [],
options.search !== false ? searchPlugin(options.search) : [],
options.docsearch !== false && !options.search
? docsearchPlugin(options.docsearch!)
: [],
options.shikiji !== false
? shikijiPlugin({
theme: { light: 'vitesse-light', dark: 'vitesse-dark' },
...(options.shikiji ?? {}),
})
: [],
options.copyCode !== false
? copyCodePlugin({
selector: '.plume-content div[class*="language-"] pre',
...options.copyCode,
})
: [],
options.markdownEnhance !== false
? mdEnhancePlugin(
Object.assign(
{
hint: true, // info note tip warning danger details d
codetabs: true,
tabs: true,
align: true,
mark: true,
tasklist: true,
demo: true,
attrs: true,
},
options.markdownEnhance || {},
),
)
: [],
options.comment !== false ? commentPlugin(options.comment || {}) : [],
options.baiduTongji !== false && options.baiduTongji?.key
? baiduTongjiPlugin(options.baiduTongji)
: [],
options.sitemap !== false && localeOptions.hostname && isProd
? sitemapPlugin({
hostname: localeOptions.hostname,
})
: [],
options.seo !== false && localeOptions.hostname && isProd
? seoPlugin({
hostname: localeOptions.hostname || '',
author: localeOptions.avatar?.name,
})
: [],
]
if (options.readingTime !== false)
plugins.push(readingTimePlugin(options.readingTime || {}))
if (localeOptions.notes)
plugins.push(notesDataPlugin(localeOptions.notes))
if (options.nprogress !== false)
plugins.push(nprogressPlugin())
if (options.git !== false) {
plugins.push(gitPlugin({
createdTime: false,
updatedTime: localeOptions.lastUpdated !== false,
contributors: localeOptions.contributors !== false,
}))
}
if (options.mediumZoom !== false) {
plugins.push(mediumZoomPlugin({
selector: '.plume-content > img, .plume-content :not(a) > img',
zoomOptions: {
background: 'var(--vp-c-bg)',
},
delay: 300,
}))
}
if (options.caniuse !== false) {
plugins.push(caniusePlugin(
options.caniuse || {
mode: 'embed',
},
))
}
if (options.externalLinkIcon !== false) {
plugins.push(externalLinkIconPlugin({
locales: Object.entries(localeOptions.locales || {}).reduce(
(result: Record<string, any>, [key, value]) => {
result[key] = {
openInNewWindow:
value.openInNewWindow ?? localeOptions.openInNewWindow,
}
return result
},
{},
),
}))
}
if (options.search !== false)
plugins.push(searchPlugin(options.search))
if (options.docsearch !== false && !options.search) {
if (options.docsearch?.appId && options.docsearch?.apiKey) {
plugins.push(docsearchPlugin(options.docsearch))
}
else {
console.error(
'docsearch plugin: appId and apiKey are both required',
)
}
}
if (options.shikiji !== false) {
plugins.push(shikijiPlugin({
theme: { light: 'vitesse-light', dark: 'vitesse-dark' },
...(options.shikiji ?? {}),
}))
}
if (options.copyCode !== false) {
plugins.push(copyCodePlugin({
selector: '.plume-content div[class*="language-"] pre',
...options.copyCode,
}))
}
if (options.markdownEnhance !== false) {
plugins.push(mdEnhancePlugin(
Object.assign(
{
hint: true, // info note tip warning danger details
codetabs: true,
tabs: true,
align: true,
mark: true,
tasklist: true,
demo: true,
attrs: true,
sup: true,
sub: true,
} as MarkdownEnhanceOptions,
options.markdownEnhance || {},
),
))
}
if (options.comment !== false)
plugins.push(commentPlugin(options.comment || {}))
if (options.baiduTongji !== false && options.baiduTongji?.key)
plugins.push(baiduTongjiPlugin(options.baiduTongji))
if (options.sitemap !== false && localeOptions.hostname && isProd) {
plugins.push(sitemapPlugin({
hostname: localeOptions.hostname,
}))
}
if (options.seo !== false && localeOptions.hostname && isProd) {
plugins.push(seoPlugin({
hostname: localeOptions.hostname || '',
author: localeOptions.avatar?.name,
}))
}
return plugins
}

View File

@ -6,10 +6,7 @@ import type {
PlumeThemeLocaleOptions,
PlumeThemePageData,
} from '../shared/index.js'
function normalizePath(dir: string) {
return dir.replace(/\\+/g, '/')
}
import { normalizePath } from './utils.js'
export async function setupPage(
app: App,

33
theme/src/node/utils.ts Normal file
View File

@ -0,0 +1,33 @@
import fs from 'node:fs'
import path from 'node:path'
import process from 'node:process'
import { customAlphabet } from 'nanoid'
export const nanoid = customAlphabet('0123456789abcdefghijklmnopqrstuvwxyz', 8)
export function getPackage() {
let pkg = {} as any
try {
const content = fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf-8')
pkg = JSON.parse(content)
}
catch { }
return pkg
}
const RE_SLASH = /\\+/g
export function normalizePath(dir: string) {
return dir.replace(RE_SLASH, '/')
}
export function pathJoin(...args: string[]) {
return normalizePath(path.join(...args))
}
const RE_START_END_SLASH = /^\/|\/$/g
export function getCurrentDirname(basePath: string | undefined, filepath: string) {
const dirList = normalizePath(basePath || path.dirname(filepath))
.replace(RE_START_END_SLASH, '')
.split('/')
return dirList.length > 0 ? dirList[dirList.length - 1] : ''
}

View File

@ -50,7 +50,7 @@ export interface PlumeThemePluginOptions {
baiduTongji?: false | BaiduTongjiOptions
frontmatter?: AutoFrontmatterOptions
frontmatter?: Omit<AutoFrontmatterOptions, 'frontmatter'>
readingTime?: false | ReadingTimeOptions
}