From 1b84c17420be4c51d3179d98f936ca71b62cb230 Mon Sep 17 00:00:00 2001 From: Jeesun Kim Date: Wed, 4 Mar 2026 10:15:23 -0800 Subject: [PATCH 1/4] fix nextjs throwing an error for monaco-editor --- src/components/CodeEditor/index.tsx | 34 +++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/src/components/CodeEditor/index.tsx b/src/components/CodeEditor/index.tsx index a582b596a..b6bd63350 100644 --- a/src/components/CodeEditor/index.tsx +++ b/src/components/CodeEditor/index.tsx @@ -2,7 +2,8 @@ import { useEffect, useRef, useState } from "react"; import { Button, CopyText, Icon, Select } from "@stellar/design-system"; -import MonacoEditor, { useMonaco, type OnMount } from "@monaco-editor/react"; +import MonacoEditor, { type OnMount } from "@monaco-editor/react"; +import loader from "@monaco-editor/loader"; import { useStore } from "@/store/useStore"; import { Box } from "@/components/layout/Box"; @@ -47,10 +48,13 @@ export const CodeEditor = ({ maxHeightInRem, }: CodeEditorProps) => { const { theme } = useStore(); - const monaco = useMonaco(); const headerEl = useRef(null); - const [isReady, setIsReady] = useState(false); + const [isReady, setIsReady] = useState( + // If Monaco is already loaded (e.g., another editor was mounted first), + // skip the async init to avoid a flicker. + () => loader.__getMonacoInstance() !== null, + ); const [isExpanded, setIsExpanded] = useState(false); // Default header height is 43px @@ -58,11 +62,27 @@ export const CodeEditor = ({ const [autoHeight, setAutoHeight] = useState(null); + // Load Monaco without the unhandled-rejection bug that exists in the + // useMonaco() hook shipped by @monaco-editor/react: its internal + // loader.init().then(...) call has NO .catch(), so when React StrictMode + // double-invokes effects the cleanup calls loader.cancel() which rejects + // the promise with a plain { type: 'cancelation' } object, surfacing as + // '[object Object]' in Next.js's onUnhandledRejection handler. useEffect(() => { - if (typeof window !== "undefined" && monaco) { - setIsReady(true); - } - }, [monaco]); + if (isReady) return; + + const initPromise = loader.init(); + initPromise + .then(() => setIsReady(true)) + // Swallow both intentional cancellations and unexpected errors so the + // promise rejection never escapes to the global unhandledrejection event. + .catch(() => {}); + + return () => { + initPromise.cancel(); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); if (!isReady) { return null; From 5e4927d6075963630983dac708132fdd7488a3c2 Mon Sep 17 00:00:00 2001 From: Jeesun Kim Date: Mon, 9 Mar 2026 16:31:37 -0700 Subject: [PATCH 2/4] fix import --- src/components/CodeEditor/index.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/CodeEditor/index.tsx b/src/components/CodeEditor/index.tsx index b6bd63350..fd756bac7 100644 --- a/src/components/CodeEditor/index.tsx +++ b/src/components/CodeEditor/index.tsx @@ -2,8 +2,7 @@ import { useEffect, useRef, useState } from "react"; import { Button, CopyText, Icon, Select } from "@stellar/design-system"; -import MonacoEditor, { type OnMount } from "@monaco-editor/react"; -import loader from "@monaco-editor/loader"; +import MonacoEditor, { type OnMount, loader } from "@monaco-editor/react"; import { useStore } from "@/store/useStore"; import { Box } from "@/components/layout/Box"; From f7de19bdabe87a86c8584d5e63c6661a680aae84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?jeesun=20=EC=A7=80=EC=84=A0?= Date: Tue, 10 Mar 2026 10:25:56 -0700 Subject: [PATCH 3/4] Update src/components/CodeEditor/index.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/components/CodeEditor/index.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/CodeEditor/index.tsx b/src/components/CodeEditor/index.tsx index fd756bac7..950de319f 100644 --- a/src/components/CodeEditor/index.tsx +++ b/src/components/CodeEditor/index.tsx @@ -52,7 +52,10 @@ export const CodeEditor = ({ const [isReady, setIsReady] = useState( // If Monaco is already loaded (e.g., another editor was mounted first), // skip the async init to avoid a flicker. - () => loader.__getMonacoInstance() !== null, + () => { + const getMonacoInstance = (loader as any).__getMonacoInstance; + return typeof getMonacoInstance === "function" && getMonacoInstance() !== null; + }, ); const [isExpanded, setIsExpanded] = useState(false); From 6bb812d92aefc7e9cec505e3b0bb19437b589ab8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?jeesun=20=EC=A7=80=EC=84=A0?= Date: Tue, 10 Mar 2026 10:26:04 -0700 Subject: [PATCH 4/4] Update src/components/CodeEditor/index.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/components/CodeEditor/index.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/CodeEditor/index.tsx b/src/components/CodeEditor/index.tsx index 950de319f..db1887e72 100644 --- a/src/components/CodeEditor/index.tsx +++ b/src/components/CodeEditor/index.tsx @@ -83,8 +83,7 @@ export const CodeEditor = ({ return () => { initPromise.cancel(); }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + }, [isReady]); if (!isReady) { return null;