diff --git a/frontend/src/lib/components/Editor.svelte b/frontend/src/lib/components/Editor.svelte index c3125dd9ce..f518632483 100644 --- a/frontend/src/lib/components/Editor.svelte +++ b/frontend/src/lib/components/Editor.svelte @@ -2203,6 +2203,12 @@ } else { ed.setValue(next) } + // The write above went through `onDidChangeModelContent`, which arms the + // keystroke debounce as if the user had typed. Monaco now holds exactly + // `code`, so there is nothing to flush — and leaving the timer armed makes + // every "is Monaco the newer side?" check (notably the unmount flush) answer + // yes on the strength of our own write. + cancelPendingChanges() } // External `code` prop changes should flow into the Monaco editor. Skip diff --git a/frontend/src/lib/components/ScriptEditor.svelte b/frontend/src/lib/components/ScriptEditor.svelte index dd06a58cde..8110805179 100644 --- a/frontend/src/lib/components/ScriptEditor.svelte +++ b/frontend/src/lib/components/ScriptEditor.svelte @@ -2762,7 +2762,11 @@ awareness={wsProvider?.awareness} on:change={(e) => { if (activeModuleTab === null) { - code = editorCode + // The payload, not `editorCode`: the editor also fires this while it is + // being torn down (the unmount flush), and a destroyed component's + // `bind:` writes no longer reach us — re-reading would take the value + // from before the change and write it back over `code`. + code = e.detail lastSyncedCode = code inferSchema(e.detail) } else {