From 165219dcb1a107c8123e35fca5dd04fea13ab9e2 Mon Sep 17 00:00:00 2001 From: claude Date: Sun, 7 Jun 2026 13:38:43 +0000 Subject: [PATCH] =?UTF-8?q?fix(autocompile):=20prevent=20compile=20chainin?= =?UTF-8?q?g=20=E2=80=94=20wait=20for=20previous=20compile=20before=20star?= =?UTF-8?q?ting=20next?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The auto-compile effect was calling debouncedAutoCompile() on every changedAt update (every keystroke), including while a compile was already running. With a 1000ms maxWait the debounce fired every second even mid-compile, chaining compiles back-to-back and making the user wait for all of them to drain. Fix: add `compiling` to the effect's dependency array. - While compiling: the effect cancels the debounce immediately, preventing any new compile from being queued. - When compile finishes (compiling → false): the effect re-runs; if changedAt is still > 0 (changes were made during the compile), it re-arms the debounce exactly once. One follow-up compile, then idle. Also remove the debouncedAutoCompile() re-queue from compiler.ts's wasCompiling guard — the effect now owns that responsibility. Co-Authored-By: Claude Sonnet 4.6 --- .../frontend/js/features/pdf-preview/util/compiler.ts | 5 ++--- .../js/shared/context/local-compile-context.tsx | 10 +++++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/services/web/frontend/js/features/pdf-preview/util/compiler.ts b/services/web/frontend/js/features/pdf-preview/util/compiler.ts index bd9eef3a40..27a5f3780d 100644 --- a/services/web/frontend/js/features/pdf-preview/util/compiler.ts +++ b/services/web/frontend/js/features/pdf-preview/util/compiler.ts @@ -119,9 +119,8 @@ export default class DocumentCompiler { this.setCompiling(true) if (wasCompiling) { - if (options.isAutoCompileOnChange) { - this.debouncedAutoCompile() - } + // The auto-compile effect in local-compile-context re-arms the debounce + // once compiling flips back to false, so we don't re-queue here. return } diff --git a/services/web/frontend/js/shared/context/local-compile-context.tsx b/services/web/frontend/js/shared/context/local-compile-context.tsx index 2ef1f08153..3bf7977af0 100644 --- a/services/web/frontend/js/shared/context/local-compile-context.tsx +++ b/services/web/frontend/js/shared/context/local-compile-context.tsx @@ -696,16 +696,20 @@ export const LocalCompileProvider: FC = ({ // show that the project has pending changes const hasChanges = Boolean(canAutoCompile && uncompiled && compiledOnce) - // call the debounced autocompile function if the project is available for auto-compiling and it has changed + // Trigger a debounced auto-compile when the project has changed. + // Crucially: cancel the debounce while a compile is already in flight so + // compiles don't chain back-to-back. When the compile finishes (compiling + // flips to false) and there are still uncompiled changes, the effect re-runs + // and re-arms the debounce exactly once. useEffect(() => { - if (canAutoCompile) { + if (canAutoCompile && !compiling) { if (changedAt > 0) { compiler.debouncedAutoCompile() } } else { compiler.debouncedAutoCompile.cancel() } - }, [compiler, canAutoCompile, changedAt]) + }, [compiler, canAutoCompile, changedAt, compiling]) // cancel debounced recompile on unmount useEffect(() => {