From 08949d516774253e35cf9d8eb0ab793aa477bf2f Mon Sep 17 00:00:00 2001 From: Jonathan Brennan Date: Wed, 11 Mar 2026 05:45:27 -0500 Subject: [PATCH] fix: clean up monaco diff editor (#7819) --- .../web/app/src/components/v2/diff-editor.tsx | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/packages/web/app/src/components/v2/diff-editor.tsx b/packages/web/app/src/components/v2/diff-editor.tsx index 9a28a13e2..667903691 100644 --- a/packages/web/app/src/components/v2/diff-editor.tsx +++ b/packages/web/app/src/components/v2/diff-editor.tsx @@ -1,4 +1,4 @@ -import { ReactElement, useEffect, useRef, useState } from 'react'; +import { ReactElement, useEffect, useLayoutEffect, useRef, useState } from 'react'; import { parse, print } from 'graphql'; import { editor } from 'monaco-editor'; import { MonacoDiffEditor, MonacoEditor } from '@/components/schema-editor'; @@ -35,10 +35,32 @@ export const DiffEditor = (props: { } }, []); const editorRef = useRef(null); + const modelsRef = useRef<{ + original: editor.ITextModel | null; + modified: editor.ITextModel | null; + }>({ original: null, modified: null }); + + // useLayoutEffect cleanup runs before @monaco-editor/react's useEffect cleanup. + // This lets us call setModel(null) to detach models from the widget, removing + // Monaco's onWillDispose listeners that throw "TextModel got disposed before + // DiffEditorWidget model got reset". + useLayoutEffect(() => { + return () => { + editorRef.current?.setModel(null); + modelsRef.current.original?.dispose(); + modelsRef.current.modified?.dispose(); + modelsRef.current = { original: null, modified: null }; + editorRef.current = null; + }; + }, []); function handleEditorDidMount(editor: OriginalMonacoDiffEditor, monaco: Monaco) { addKeyBindings(editor, monaco); editorRef.current = editor; + modelsRef.current = { + original: editor.getOriginalEditor().getModel(), + modified: editor.getModifiedEditor().getModel(), + }; props.onMount?.(editor.getModifiedEditor()); editor.getModifiedEditor().onDidChangeModelContent(() => { @@ -121,6 +143,8 @@ export const DiffEditor = (props: { loading={} original={sdlBefore ?? undefined} modified={sdlAfter ?? undefined} + keepCurrentOriginalModel + keepCurrentModifiedModel options={{ originalEditable: false, renderLineHighlightOnlyWhenFocus: true,