The Trans Directory
0
fork

Configure Feed

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

fix: builds should no accumulate on repeated changes (closes #404)

+47 -47
+8 -8
quartz/bootstrap-cli.mjs
··· 393 393 }) 394 394 395 395 const buildMutex = new Mutex() 396 - const timeoutIds = new Set() 396 + let lastBuildMs = 0 397 397 let cleanupBuild = null 398 398 const build = async (clientRefresh) => { 399 + const buildStart = new Date().getTime() 400 + lastBuildMs = buildStart 399 401 const release = await buildMutex.acquire() 402 + if (lastBuildMs > buildStart) { 403 + release() 404 + return 405 + } 400 406 401 407 if (cleanupBuild) { 402 408 await cleanupBuild() ··· 426 432 const { default: buildQuartz } = await import(cacheFile + `?update=${randomUUID()}`) 427 433 cleanupBuild = await buildQuartz(argv, buildMutex, clientRefresh) 428 434 clientRefresh() 429 - } 430 - 431 - const rebuild = (clientRefresh) => { 432 - timeoutIds.forEach((id) => clearTimeout(id)) 433 - timeoutIds.clear() 434 - timeoutIds.add(setTimeout(() => build(clientRefresh), 250)) 435 435 } 436 436 437 437 if (argv.serve) { ··· 539 539 ignoreInitial: true, 540 540 }) 541 541 .on("all", async () => { 542 - rebuild(clientRefresh) 542 + build(clientRefresh) 543 543 }) 544 544 } else { 545 545 await build(() => {})
+39 -39
quartz/build.ts
··· 81 81 } 82 82 83 83 const initialSlugs = ctx.allSlugs 84 - const timeoutIds: Set<ReturnType<typeof setTimeout>> = new Set() 84 + let lastBuildMs = 0 85 85 const toRebuild: Set<FilePath> = new Set() 86 86 const toRemove: Set<FilePath> = new Set() 87 87 const trackedAssets: Set<FilePath> = new Set() ··· 111 111 } 112 112 113 113 // debounce rebuilds every 250ms 114 - timeoutIds.add( 115 - setTimeout(async () => { 116 - const release = await mut.acquire() 117 - timeoutIds.forEach((id) => clearTimeout(id)) 118 - timeoutIds.clear() 119 114 120 - const perf = new PerfTimer() 121 - console.log(chalk.yellow("Detected change, rebuilding...")) 122 - try { 123 - const filesToRebuild = [...toRebuild].filter((fp) => !toRemove.has(fp)) 115 + const buildStart = new Date().getTime() 116 + lastBuildMs = buildStart 117 + const release = await mut.acquire() 118 + if (lastBuildMs > buildStart) { 119 + release() 120 + return 121 + } 124 122 125 - const trackedSlugs = [...new Set([...contentMap.keys(), ...toRebuild, ...trackedAssets])] 126 - .filter((fp) => !toRemove.has(fp)) 127 - .map((fp) => slugifyFilePath(path.posix.relative(argv.directory, fp) as FilePath)) 123 + const perf = new PerfTimer() 124 + console.log(chalk.yellow("Detected change, rebuilding...")) 125 + try { 126 + const filesToRebuild = [...toRebuild].filter((fp) => !toRemove.has(fp)) 128 127 129 - ctx.allSlugs = [...new Set([...initialSlugs, ...trackedSlugs])] 130 - const parsedContent = await parseMarkdown(ctx, filesToRebuild) 131 - for (const content of parsedContent) { 132 - const [_tree, vfile] = content 133 - contentMap.set(vfile.data.filePath!, content) 134 - } 128 + const trackedSlugs = [...new Set([...contentMap.keys(), ...toRebuild, ...trackedAssets])] 129 + .filter((fp) => !toRemove.has(fp)) 130 + .map((fp) => slugifyFilePath(path.posix.relative(argv.directory, fp) as FilePath)) 135 131 136 - for (const fp of toRemove) { 137 - contentMap.delete(fp) 138 - } 132 + ctx.allSlugs = [...new Set([...initialSlugs, ...trackedSlugs])] 133 + const parsedContent = await parseMarkdown(ctx, filesToRebuild) 134 + for (const content of parsedContent) { 135 + const [_tree, vfile] = content 136 + contentMap.set(vfile.data.filePath!, content) 137 + } 139 138 140 - // TODO: we can probably traverse the link graph to figure out what's safe to delete here 141 - // instead of just deleting everything 142 - await rimraf(argv.output) 143 - const parsedFiles = [...contentMap.values()] 144 - const filteredContent = filterContent(ctx, parsedFiles) 145 - await emitContent(ctx, filteredContent) 146 - console.log(chalk.green(`Done rebuilding in ${perf.timeSince()}`)) 147 - } catch { 148 - console.log(chalk.yellow(`Rebuild failed. Waiting on a change to fix the error...`)) 149 - } 139 + for (const fp of toRemove) { 140 + contentMap.delete(fp) 141 + } 142 + 143 + const parsedFiles = [...contentMap.values()] 144 + const filteredContent = filterContent(ctx, parsedFiles) 145 + // TODO: we can probably traverse the link graph to figure out what's safe to delete here 146 + // instead of just deleting everything 147 + await rimraf(argv.output) 148 + await emitContent(ctx, filteredContent) 149 + console.log(chalk.green(`Done rebuilding in ${perf.timeSince()}`)) 150 + } catch { 151 + console.log(chalk.yellow(`Rebuild failed. Waiting on a change to fix the error...`)) 152 + } 150 153 151 - clientRefresh() 152 - toRebuild.clear() 153 - toRemove.clear() 154 - release() 155 - }, 250), 156 - ) 154 + clientRefresh() 155 + toRebuild.clear() 156 + toRemove.clear() 157 + release() 157 158 } 158 159 159 160 const watcher = chokidar.watch(".", { ··· 168 169 .on("unlink", (fp) => rebuild(fp, "delete")) 169 170 170 171 return async () => { 171 - timeoutIds.forEach((id) => clearTimeout(id)) 172 172 await watcher.close() 173 173 } 174 174 }