fix: harden core build system against silent failures

- Wrap rebuild() in try/finally to guarantee mutex release (prevents deadlock)
- Surface rebuild errors via .catch() instead of discarding with void
- Add null checks for vfile.data.relativePath (prevents crash on virtual files)
- Add try-finally for worker pool cleanup in parse.ts (prevents thread leaks)
- Remove process.exit(1) from parse error handler (let errors propagate)
- Add per-emitter error handling in emit phase with degraded-build warning
- Replace unsafe Map.get()! assertions with null-checked access in config-loader
This commit is contained in:
saberzero1
2026-05-24 17:09:46 +02:00
parent 17aa8ab233
commit caa55037f7
4 changed files with 192 additions and 160 deletions
+33 -35
View File
@@ -171,11 +171,6 @@ export async function parseMarkdown(ctx: BuildCtx, fps: FilePath[]): Promise<Pro
maxWorkers: concurrency,
workerType: "thread",
})
const errorHandler = (err: any) => {
console.error(err)
process.exit(1)
}
const serializableCtx: WorkerSerializableBuildCtx = {
buildId: ctx.buildId,
argv: ctx.argv,
@@ -185,37 +180,40 @@ export async function parseMarkdown(ctx: BuildCtx, fps: FilePath[]): Promise<Pro
virtualPages: [],
}
const textToMarkdownPromises: WorkerPromise<MarkdownContent[]>[] = []
let processedFiles = 0
for (const chunk of chunks(fps, CHUNK_SIZE)) {
textToMarkdownPromises.push(pool.exec("parseMarkdown", [serializableCtx, chunk]))
try {
const textToMarkdownPromises: WorkerPromise<MarkdownContent[]>[] = []
let processedFiles = 0
for (const chunk of chunks(fps, CHUNK_SIZE)) {
textToMarkdownPromises.push(pool.exec("parseMarkdown", [serializableCtx, chunk]))
}
const mdResults: Array<MarkdownContent[]> = await Promise.all(
textToMarkdownPromises.map(async (promise) => {
const result = await promise
processedFiles += result.length
log.updateText(`text->markdown ${styleText("gray", `${processedFiles}/${fps.length}`)}`)
return result
}),
)
const markdownToHtmlPromises: WorkerPromise<ProcessedContent[]>[] = []
processedFiles = 0
for (const mdChunk of mdResults) {
markdownToHtmlPromises.push(pool.exec("processHtml", [serializableCtx, mdChunk]))
}
const results: ProcessedContent[][] = await Promise.all(
markdownToHtmlPromises.map(async (promise) => {
const result = await promise
processedFiles += result.length
log.updateText(`markdown->html ${styleText("gray", `${processedFiles}/${fps.length}`)}`)
return result
}),
)
res = results.flat()
} finally {
await pool.terminate()
}
const mdResults: Array<MarkdownContent[]> = await Promise.all(
textToMarkdownPromises.map(async (promise) => {
const result = await promise
processedFiles += result.length
log.updateText(`text->markdown ${styleText("gray", `${processedFiles}/${fps.length}`)}`)
return result
}),
).catch(errorHandler)
const markdownToHtmlPromises: WorkerPromise<ProcessedContent[]>[] = []
processedFiles = 0
for (const mdChunk of mdResults) {
markdownToHtmlPromises.push(pool.exec("processHtml", [serializableCtx, mdChunk]))
}
const results: ProcessedContent[][] = await Promise.all(
markdownToHtmlPromises.map(async (promise) => {
const result = await promise
processedFiles += result.length
log.updateText(`markdown->html ${styleText("gray", `${processedFiles}/${fps.length}`)}`)
return result
}),
).catch(errorHandler)
res = results.flat()
await pool.terminate()
}
log.end(`Parsed ${res.length} Markdown files in ${perf.timeSince()}`)