perf: optimize auto-frontmatter

This commit is contained in:
pengzhanbo 2023-02-25 23:06:23 +08:00
parent 547860c4b1
commit dab3f46257
6 changed files with 51 additions and 36 deletions

View File

@ -15,7 +15,7 @@ export default {
plugins: [
autoFrontmatterPlugin({
formatter: {
createTime(formatTime, matter, file) {
createTime(formatTime, file, matter) {
if (formatTime) return formatTime
return file.createTime
}
@ -48,10 +48,11 @@ export default {
relativePath: string
content: string
createTime: Date
stats: fs.Stats
}
interface FormatterFn<T = any, K = object> {
(value: T, data: K, file: MarkdownFile): T
(value: T, file: MarkdownFile, data: K): T
}
type FormatterObject<K = object, T = any> = Record<
@ -60,7 +61,7 @@ export default {
>
type FormatterArray = {
include: string
include: string | string[]
formatter: FormatterObject
}[]
@ -75,7 +76,7 @@ export default {
* ---
*/
const formatterObj: Formatter = {
createTime(formatTime, matter, file) {
createTime(formatTime, file, matter) {
if (formatTime) return formatTime
return file.createTime
}
@ -87,7 +88,7 @@ export default {
include: '**/{README,index}.md',
// formatter 仅对 glob命中的文件有效
formatter: {
home(value, matter, file) {
home(value, file, matter) {
return value
}
},

View File

@ -1,8 +1,12 @@
import type { AutoFrontmatterOptions } from '../shared/index.js'
import type {
AutoFrontmatterOptions,
FormatterArray,
FormatterObject,
} from '../shared/index.js'
import { autoFrontmatterPlugin } from './plugin.js'
export * from './plugin.js'
export { AutoFrontmatterOptions }
export { AutoFrontmatterOptions, FormatterArray, FormatterObject }
export default autoFrontmatterPlugin

View File

@ -40,26 +40,26 @@ export const autoFrontmatterPlugin = ({
}
})
function formatMarkdown(file: MarkdownFile): void {
async function formatMarkdown(file: MarkdownFile): Promise<void> {
const { filepath, relativePath } = file
const current = otherFormatters.find(({ filter }) => filter(relativePath))
const formatter = current?.formatter || globFormatter
const { data, content } = grayMatter(file.content)
Object.keys(formatter).forEach((key) => {
const value = formatter[key](data[key], data, file)
for (const key in formatter) {
const value = await formatMarkdown[key](data[key], file, data)
data[key] = value ?? data[key]
})
}
try {
const yaml = isEmptyObject(data)
? '---\n'
? ''
: jsonToYaml
.stringify(data)
.replace(/\n\s{2}/g, '\n')
.replace(/"/g, '')
const newContent = `${yaml}---\n${content}`
const newContent = yaml ? `${yaml}---\n${content}` : content
fs.writeFileSync(filepath, newContent, 'utf-8')
} catch (e) {
@ -71,7 +71,9 @@ export const autoFrontmatterPlugin = ({
name: '@vuepress-plume/vuepress-plugin-auto-frontmatter',
onInitialized: async (app) => {
const markdownList = await readMarkdownList(app.dir.source(), globFilter)
markdownList.forEach((file) => formatMarkdown(file))
for (const file of markdownList) {
await formatMarkdown(file)
}
},
onWatched: async (app, watchers) => {
const watcher = chokidar.watch('**/*.md', {
@ -80,9 +82,9 @@ export const autoFrontmatterPlugin = ({
ignored: /(node_modules|\.vuepress)\//,
})
watcher.on('add', (relativePath) => {
watcher.on('add', async (relativePath) => {
if (!globFilter(relativePath)) return
formatMarkdown(readMarkdown(app.dir.source(), relativePath))
await formatMarkdown(readMarkdown(app.dir.source(), relativePath))
})
watchers.push(watcher)

View File

@ -24,14 +24,16 @@ export const readMarkdown = (
relativePath: string
): MarkdownFile => {
const filepath = path.join(sourceDir, relativePath)
const stats = fs.statSync(filepath)
return {
filepath,
relativePath,
content: fs.readFileSync(filepath, 'utf-8'),
createTime: getFileCreateTime(fs.statSync(filepath)),
createTime: getFileCreateTime(stats),
stats,
}
}
export const getFileCreateTime = (stat: fs.Stats): Date => {
return stat.birthtime.getFullYear() !== 1970 ? stat.birthtime : stat.atime
export const getFileCreateTime = (stats: fs.Stats): Date => {
return stats.birthtime.getFullYear() !== 1970 ? stats.birthtime : stats.atime
}

View File

@ -1,21 +1,24 @@
import type fs from 'node:fs'
export interface MarkdownFile {
filepath: string
relativePath: string
content: string
createTime: Date
stats: fs.Stats
}
export interface FormatterFn<T = any, K = object> {
(value: T, data: K, file: MarkdownFile): T
}
export type FormatterFn<T = any, K = object> = (
value: T,
file: MarkdownFile,
data: K
) => T | PromiseLike<T>
export type FormatterObject<K = object, T = any> = Record<
string,
FormatterFn<T, K>
>
export type FormatterObject<K = object, T = any> = {
[P: string]: FormatterFn<T, K>
}
export type FormatterArray = {
include: string
include: string | string[]
formatter: FormatterObject
}[]
@ -29,10 +32,10 @@ export interface AutoFrontmatterOptions {
/**
* {
* key(value, data, file) {
* key(value, file, data) {
* return value
* }
* }
*/
formatter?: FormatterObject | FormatterArray
formatter?: FormatterArray | FormatterObject
}

View File

@ -1,6 +1,9 @@
import { createRequire } from 'node:module'
import path from 'node:path'
import type { AutoFrontmatterOptions } from '@vuepress-plume/vuepress-plugin-auto-frontmatter'
import type {
AutoFrontmatterOptions,
FormatterArray,
} from '@vuepress-plume/vuepress-plugin-auto-frontmatter'
import type {
NotesDataOptions,
NotesItem,
@ -60,14 +63,14 @@ export default function (
// note 首页链接
include: path.join(notesDir, `**/{readme,README,index}.md`),
formatter: {
title(title: string, _, { filepath }) {
title(title: string, { filepath }) {
if (title) return title
const note = findNote(filepath)
if (note?.text) return note.text
return getCurrentDirname(note, filepath) || ''
},
...baseFormatter,
permalink(permalink: string, _, { filepath }) {
permalink(permalink: string, { filepath }) {
if (permalink) return permalink
const note = findNote(filepath)
const dirname = getCurrentDirname(note, filepath)
@ -78,13 +81,13 @@ export default function (
{
include: path.join(notesDir, '**/*.md'),
formatter: {
title(title: string, _, { filepath }) {
title(title: string, { filepath }) {
if (title) return title
const basename = path.basename(filepath, '.md')
return basename
},
...baseFormatter,
permalink(permalink: string, _, { filepath }) {
permalink(permalink: string, { filepath }) {
if (permalink) return permalink
const note = findNote(filepath)
const dirname = getCurrentDirname(note, filepath)
@ -99,7 +102,7 @@ export default function (
{
include: '*',
formatter: {
title(title: string, _, { filepath }) {
title(title: string, { filepath }) {
if (title) return title
const basename = path.basename(filepath, '.md')
return basename
@ -111,6 +114,6 @@ export default function (
},
},
},
],
] as FormatterArray,
}
}