The Trans Directory
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix: properly lock across source and content refresh by sharing a mutex

+19 -12
+6 -6
quartz/bootstrap-cli.mjs
··· 394 394 395 395 const buildMutex = new Mutex() 396 396 const timeoutIds = new Set() 397 - let firstBuild = true 397 + let cleanupBuild = null 398 398 const build = async (clientRefresh) => { 399 399 const release = await buildMutex.acquire() 400 - if (firstBuild) { 401 - firstBuild = false 402 - } else { 400 + 401 + if (cleanupBuild) { 402 + await cleanupBuild() 403 403 console.log(chalk.yellow("Detected a source code change, doing a hard rebuild...")) 404 404 } 405 405 ··· 408 408 console.log(`Reason: ${chalk.grey(err)}`) 409 409 process.exit(1) 410 410 }) 411 + release() 411 412 412 413 if (argv.bundleInfo) { 413 414 const outputFileName = "quartz/.quartz-cache/transpiled-build.mjs" ··· 423 424 // bypass module cache 424 425 // https://github.com/nodejs/modules/issues/307 425 426 const { default: buildQuartz } = await import(cacheFile + `?update=${randomUUID()}`) 426 - await buildQuartz(argv, clientRefresh) 427 + cleanupBuild = await buildQuartz(argv, buildMutex, clientRefresh) 427 428 clientRefresh() 428 - release() 429 429 } 430 430 431 431 const rebuild = (clientRefresh) => {
+13 -6
quartz/build.ts
··· 18 18 import { options } from "./util/sourcemap" 19 19 import { Mutex } from "async-mutex" 20 20 21 - async function buildQuartz(argv: Argv, clientRefresh: () => void) { 21 + async function buildQuartz(argv: Argv, mut: Mutex, clientRefresh: () => void) { 22 22 const ctx: BuildCtx = { 23 23 argv, 24 24 cfg, ··· 38 38 console.log(` Emitters: ${pluginNames("emitters").join(", ")}`) 39 39 } 40 40 41 + const release = await mut.acquire() 41 42 perf.addEvent("clean") 42 43 await rimraf(output) 43 44 console.log(`Cleaned output directory \`${output}\` in ${perf.timeSince("clean")}`) ··· 56 57 const filteredContent = filterContent(ctx, parsedFiles) 57 58 await emitContent(ctx, filteredContent) 58 59 console.log(chalk.green(`Done processing ${fps.length} files in ${perf.timeSince()}`)) 60 + release() 59 61 60 62 if (argv.serve) { 61 - return startServing(ctx, parsedFiles, clientRefresh) 63 + return startServing(ctx, mut, parsedFiles, clientRefresh) 62 64 } 63 65 } 64 66 65 67 // setup watcher for rebuilds 66 68 async function startServing( 67 69 ctx: BuildCtx, 70 + mut: Mutex, 68 71 initialContent: ProcessedContent[], 69 72 clientRefresh: () => void, 70 73 ) { ··· 78 81 } 79 82 80 83 const initialSlugs = ctx.allSlugs 81 - const buildMutex = new Mutex() 82 84 const timeoutIds: Set<ReturnType<typeof setTimeout>> = new Set() 83 85 const toRebuild: Set<FilePath> = new Set() 84 86 const toRemove: Set<FilePath> = new Set() ··· 111 113 // debounce rebuilds every 250ms 112 114 timeoutIds.add( 113 115 setTimeout(async () => { 114 - const release = await buildMutex.acquire() 116 + const release = await mut.acquire() 115 117 timeoutIds.forEach((id) => clearTimeout(id)) 116 118 timeoutIds.clear() 117 119 ··· 164 166 .on("add", (fp) => rebuild(fp, "add")) 165 167 .on("change", (fp) => rebuild(fp, "change")) 166 168 .on("unlink", (fp) => rebuild(fp, "delete")) 169 + 170 + return async () => { 171 + timeoutIds.forEach((id) => clearTimeout(id)) 172 + await watcher.close() 173 + } 167 174 } 168 175 169 - export default async (argv: Argv, clientRefresh: () => void) => { 176 + export default async (argv: Argv, mut: Mutex, clientRefresh: () => void) => { 170 177 try { 171 - return await buildQuartz(argv, clientRefresh) 178 + return await buildQuartz(argv, mut, clientRefresh) 172 179 } catch (err) { 173 180 trace("\nExiting Quartz due to a fatal error", err as Error) 174 181 }