62 lines
1.8 KiB
TypeScript
62 lines
1.8 KiB
TypeScript
import fs from 'node:fs'
|
||
import { pathToFileURL } from 'node:url'
|
||
import type { App, PluginFunction } from 'vuepress'
|
||
|
||
const HMR_TAIL = `if (import.meta.webpackHot) {
|
||
import.meta.webpackHot.accept()
|
||
if (__VUE_HMR_RUNTIME__.updateBlogPostData) {
|
||
__VUE_HMR_RUNTIME__.updateBlogPostData(blogPostData)
|
||
}
|
||
}
|
||
|
||
if (import.meta.hot) {
|
||
import.meta.hot.accept(({ blogPostData }) => {
|
||
__VUE_HMR_RUNTIME__.updateBlogPostData(blogPostData)
|
||
})
|
||
}
|
||
`
|
||
|
||
async function enrichBlogData(app: App): Promise<void> {
|
||
const tempFile = app.dir.temp('internal/blogData.js')
|
||
if (!fs.existsSync(tempFile)) return
|
||
|
||
let blogPostData: Record<string, unknown>[]
|
||
try {
|
||
const url = `${pathToFileURL(tempFile).href}?t=${Date.now()}`
|
||
const mod = await import(url) as { blogPostData: Record<string, unknown>[] }
|
||
blogPostData = mod.blogPostData.map(p => ({ ...p }))
|
||
}
|
||
catch {
|
||
return
|
||
}
|
||
|
||
const byPath = new Map<string, { minutes: number; words: number }>()
|
||
for (const page of app.pages) {
|
||
const rt = page.data.readingTime as { minutes: number; words: number } | undefined
|
||
if (rt && typeof rt.words === 'number') byPath.set(page.path, rt)
|
||
}
|
||
|
||
for (const post of blogPostData) {
|
||
const rt = byPath.get(post.path as string)
|
||
if (rt) post.readingTime = rt
|
||
}
|
||
|
||
await app.writeTemp(
|
||
'internal/blogData.js',
|
||
`export const blogPostData = ${JSON.stringify(blogPostData)}\n\n${HMR_TAIL}\n`,
|
||
)
|
||
}
|
||
|
||
/**
|
||
* 在主题写入 blogData 之后,把各页的 readingTime(字数、分钟)并入博客列表数据,
|
||
* 供自定义 VPPostItem 在 /blog/ 列表展示。
|
||
*/
|
||
export function enrichBlogReadingTimePlugin(): PluginFunction {
|
||
return () => ({
|
||
name: 'enrich-blog-reading-time',
|
||
onPrepared: async (app: App) => {
|
||
await enrichBlogData(app)
|
||
},
|
||
})
|
||
}
|