From b69556c918e2a4a27b047e8de6b02861f04d5a9e Mon Sep 17 00:00:00 2001 From: Jacky Zhao Date: Mon, 21 Aug 2023 16:43:22 -0700 Subject: [PATCH] fix: async-mutex not exclusively locking correectly --- content/layout.md | 2 +- quartz/bootstrap-cli.mjs | 12 +++++++++--- quartz/build.ts | 11 +++++++---- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/content/layout.md b/content/layout.md index 8a74b91..3fabeb7 100644 --- a/content/layout.md +++ b/content/layout.md @@ -30,7 +30,7 @@ These correspond to following parts of the page: Quartz **components**, like plugins, can take in additional properties as configuration options. If you're familiar with React terminology, you can think of them as Higher-order Components. -See [a list of all the components](./tags/component) for all available components along with their configuration options. You can also checkout the guide on [[creating components]] if you're interested in further customizing the behaviour of Quartz. +See [a list of all the components](component.md) for all available components along with their configuration options. You can also checkout the guide on [[creating components]] if you're interested in further customizing the behaviour of Quartz. ### Style diff --git a/quartz/bootstrap-cli.mjs b/quartz/bootstrap-cli.mjs index cb0ff2e..808deba 100755 --- a/quartz/bootstrap-cli.mjs +++ b/quartz/bootstrap-cli.mjs @@ -394,8 +394,15 @@ See the [documentation](https://quartz.jzhao.xyz) for how to get started. const buildMutex = new Mutex() const timeoutIds = new Set() + let firstBuild = true const build = async (clientRefresh) => { - await buildMutex.acquire() + const release = await buildMutex.acquire() + if (firstBuild) { + firstBuild = false + } else { + console.log(chalk.yellow("Detected a source code change, doing a hard rebuild...")) + } + const result = await ctx.rebuild().catch((err) => { console.error(`${chalk.red("Couldn't parse Quartz configuration:")} ${fp}`) console.log(`Reason: ${chalk.grey(err)}`) @@ -418,7 +425,7 @@ See the [documentation](https://quartz.jzhao.xyz) for how to get started. const { default: buildQuartz } = await import(cacheFile + `?update=${randomUUID()}`) await buildQuartz(argv, clientRefresh) clientRefresh() - buildMutex.release() + release() } const rebuild = (clientRefresh) => { @@ -526,7 +533,6 @@ See the [documentation](https://quartz.jzhao.xyz) for how to get started. ignoreInitial: true, }) .on("all", async () => { - console.log(chalk.yellow("Detected a source code change, doing a hard rebuild...")) rebuild(clientRefresh) }) } else { diff --git a/quartz/build.ts b/quartz/build.ts index 78437f8..0af39d0 100644 --- a/quartz/build.ts +++ b/quartz/build.ts @@ -108,12 +108,13 @@ async function startServing( toRemove.add(filePath) } - timeoutIds.forEach((id) => clearTimeout(id)) - // debounce rebuilds every 250ms timeoutIds.add( setTimeout(async () => { - await buildMutex.acquire() + const release = await buildMutex.acquire() + timeoutIds.forEach((id) => clearTimeout(id)) + timeoutIds.clear() + const perf = new PerfTimer() console.log(chalk.yellow("Detected change, rebuilding...")) try { @@ -134,6 +135,8 @@ async function startServing( contentMap.delete(fp) } + // TODO: we can probably traverse the link graph to figure out what's safe to delete here + // instead of just deleting everything await rimraf(argv.output) const parsedFiles = [...contentMap.values()] const filteredContent = filterContent(ctx, parsedFiles) @@ -146,7 +149,7 @@ async function startServing( clientRefresh() toRebuild.clear() toRemove.clear() - buildMutex.release() + release() }, 250), ) }