feat: rewrite app.writeTemp to resolve IO race conditions (#862)

This commit is contained in:
pengzhanbo 2026-02-25 21:50:50 +08:00 committed by GitHub
parent 948c31779b
commit c109d54961
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 56 additions and 0 deletions

53
theme/src/node/enhance.ts Normal file
View File

@ -0,0 +1,53 @@
/**
* vuepress/core
* vuepress/core
*/
import type { App } from 'vuepress'
import { fs, hash } from '@vuepress/utils'
interface WriteTempCache {
hash?: string // content hash
current?: Promise<void> // the current writing promise
next?: () => Promise<void> // the next writing promise
}
export function enhanceApp(app: App): void {
// rewrite writeTemp to cache the writing promise
const cache = new Map<string, WriteTempCache>()
app.writeTemp = async function (file: string, content: string): Promise<string> {
const filePath = app.dir.temp(file)
const contentHash = hash(content)
let item = cache.get(filePath)
if (!item) {
cache.set(filePath, (item = {}))
}
// if content hash is the same as the last one, skip writing
if (item.hash === contentHash) {
return filePath
}
item.hash = contentHash
if (!item.current) {
item.current = (async () => {
await fs.outputFile(filePath, content)
// if there is a next writing promise, chain it with the current one
item.current = item.next?.()
return item.current
})()
}
else {
// if there is a current writing promise, save the next writing promise
item.next = async () => {
await fs.outputFile(filePath, content)
item.next = undefined
item.current = undefined
}
}
await item.current
return filePath
}
}

View File

@ -12,6 +12,7 @@ import {
templateBuildRenderer,
} from './config/index.js'
import { detectThemeOptions, detectVersions } from './detector/index.js'
import { enhanceApp } from './enhance.js'
import { configLoader } from './loadConfig/index.js'
import { createPages, extendsPageData } from './pages/index.js'
import { setupPlugins } from './plugins/index.js'
@ -39,6 +40,8 @@ import { perf, resolve, setTranslateLang, templates, THEME_NAME } from './utils/
*/
export function plumeTheme(options: ThemeOptions = {}): Theme {
return (app) => {
enhanceApp(app)
setTranslateLang(app.options.lang)
perf.init(app.env.isDebug)