diff --git a/src/pages/components/CodeEditor/index.tsx b/src/pages/components/CodeEditor/index.tsx
index 6cde1e74d..894ad2437 100644
--- a/src/pages/components/CodeEditor/index.tsx
+++ b/src/pages/components/CodeEditor/index.tsx
@@ -135,6 +135,8 @@ const CodeEditor: React.ForwardRefRenderFunction<{ editor: editor.IStandaloneCod
largeFileOptimizations: true,
colorDecorators: true,
} as const;
+ let originalModel: editor.ITextModel | undefined;
+ let modifiedModel: editor.ITextModel | undefined;
if (diffCode) {
edit = editor.createDiffEditor(inlineDiv, {
hideUnchangedRegions: {
@@ -146,9 +148,12 @@ const CodeEditor: React.ForwardRefRenderFunction<{ editor: editor.IStandaloneCod
diffWordWrap: "off",
...commonEditorOptions,
});
+ // standalone model 不会随 editor.dispose 自动清理,需手动跟踪并在 cleanup 释放
+ originalModel = editor.createModel(diffCode, "javascript");
+ modifiedModel = editor.createModel(code, "javascript");
edit.setModel({
- original: editor.createModel(diffCode, "javascript"),
- modified: editor.createModel(code, "javascript"),
+ original: originalModel,
+ modified: modifiedModel,
});
} else {
edit = editor.create(inlineDiv, {
@@ -165,6 +170,8 @@ const CodeEditor: React.ForwardRefRenderFunction<{ editor: editor.IStandaloneCod
// 目前会出现:Uncaught (in promise) Canceled: Canceled
// 问题追踪:https://github.com/microsoft/monaco-editor/issues/4702
edit?.dispose();
+ originalModel?.dispose();
+ modifiedModel?.dispose();
};
}, [div, code, diffCode, editable, id]);
diff --git a/src/pages/options/routes/script/ScriptEditor.tsx b/src/pages/options/routes/script/ScriptEditor.tsx
index 8fc3322d8..51a511745 100644
--- a/src/pages/options/routes/script/ScriptEditor.tsx
+++ b/src/pages/options/routes/script/ScriptEditor.tsx
@@ -1,9 +1,9 @@
import type { Script } from "@App/app/repo/scripts";
import { SCRIPT_TYPE_NORMAL, ScriptCodeDAO, ScriptDAO } from "@App/app/repo/scripts";
import CodeEditor from "@App/pages/components/CodeEditor";
-import React, { useCallback, useEffect, useMemo, useState } from "react";
+import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useParams, useSearchParams } from "react-router-dom";
-import type { editor } from "monaco-editor";
+import type { editor, IDisposable } from "monaco-editor";
import { KeyCode, KeyMod } from "monaco-editor";
import { Button, Dropdown, Grid, Input, Menu, Message, Modal, Space, Tabs, Tooltip } from "@arco-design/web-react";
import TabPane from "@arco-design/web-react/es/Tabs/tab-pane";
@@ -53,6 +53,17 @@ const Editor: React.FC<{
},
[node]
);
+ // 用 ref 拿到最新的 hotKeys/onChange/callbackEditor,避免 stale closure
+ // 同时让 effect 仅在 editor 实例变化时重跑(不会因父组件重渲染重复 addAction)
+ const hotKeysRef = useRef(hotKeys);
+ const onChangeRef = useRef(onChange);
+ const callbackEditorRef = useRef(callbackEditor);
+ const scriptRef = useRef(script);
+ hotKeysRef.current = hotKeys;
+ onChangeRef.current = onChange;
+ callbackEditorRef.current = callbackEditor;
+ scriptRef.current = script;
+
useEffect(() => {
if (!node || !node.editor) {
return;
@@ -60,24 +71,32 @@ const Editor: React.FC<{
// @ts-ignore
if (!node.editor.uuid) {
// @ts-ignore
- node.editor.uuid = script.uuid;
+ node.editor.uuid = scriptRef.current.uuid;
}
- hotKeys.forEach((item) => {
- node.editor.addAction({
- id: item.id,
- label: item.title,
- keybindings: [item.hotKey],
- run(editor) {
- // @ts-ignore
- item.action(script, editor);
- },
- });
- });
- node.editor.onKeyUp(() => {
- onChange(node.editor.getValue() || "");
+ const disposables: IDisposable[] = [];
+ hotKeysRef.current.forEach((item) => {
+ disposables.push(
+ node.editor.addAction({
+ id: item.id,
+ label: item.title,
+ keybindings: [item.hotKey],
+ run(editor) {
+ // @ts-ignore
+ item.action(scriptRef.current, editor);
+ },
+ })
+ );
});
- callbackEditor(node.editor);
- return node.editor.dispose.bind(node.editor);
+ disposables.push(
+ node.editor.onKeyUp(() => {
+ onChangeRef.current(node.editor.getValue() || "");
+ })
+ );
+ callbackEditorRef.current(node.editor);
+ // editor 实例本身由 CodeEditor 自身负责 dispose,这里仅清理本 effect 注册的 listener/action
+ return () => {
+ disposables.forEach((d) => d.dispose());
+ };
}, [node?.editor]);
return ;
diff --git a/src/pkg/utils/monaco-editor/index.ts b/src/pkg/utils/monaco-editor/index.ts
index 6c91de174..c1505e0b6 100644
--- a/src/pkg/utils/monaco-editor/index.ts
+++ b/src/pkg/utils/monaco-editor/index.ts
@@ -15,6 +15,7 @@ const langs = {
quickfix: "修复 {0} 问题",
addEslintDisableNextLine: "添加 eslint-disable-next-line 注释",
addEslintDisable: "添加 eslint-disable 注释",
+ declareGlobal: "将 '{0}' 声明为全局变量 (/* global */)",
prompt: {
name: "脚本名称",
namespace: "脚本命名空间",
@@ -84,6 +85,7 @@ tracking:该脚本会追踪你的用户信息`.replace(/\n/g, "
"),
quickfix: "Fix {0} Issue",
addEslintDisableNextLine: "Add eslint-disable-next-line Comment",
addEslintDisable: "Add eslint-disable Comment",
+ declareGlobal: "Declare '{0}' as a global variable (/* global */)",
prompt: {
name: "Script name",
namespace: "Script namespace",
@@ -146,6 +148,7 @@ tracking:该脚本会追踪你的用户信息`.replace(/\n/g, "
"),
quickfix: "修復 {0} 問題",
addEslintDisableNextLine: "新增 eslint-disable-next-line 註解",
addEslintDisable: "新增 eslint-disable 註解",
+ declareGlobal: "將 '{0}' 宣告為全域變數 (/* global */)",
prompt: {
name: "腳本名稱",
namespace: "腳本命名空間",
@@ -208,6 +211,7 @@ tracking:该脚本会追踪你的用户信息`.replace(/\n/g, "
"),
quickfix: "{0} の問題を修正",
addEslintDisableNextLine: "eslint-disable-next-line コメントを追加",
addEslintDisable: "eslint-disable コメントを追加",
+ declareGlobal: "'{0}' をグローバル変数として宣言 (/* global */)",
prompt: {
name: "スクリプト名",
namespace: "スクリプトの名前空間",
@@ -270,6 +274,7 @@ tracking:该脚本会追踪你的用户信息`.replace(/\n/g, "
"),
quickfix: "{0}-Problem beheben",
addEslintDisableNextLine: "eslint-disable-next-line Kommentar hinzufügen",
addEslintDisable: "eslint-disable Kommentar hinzufügen",
+ declareGlobal: "'{0}' als globale Variable deklarieren (/* global */)",
prompt: {
name: "Skriptname",
namespace: "Skript-Namensraum",
@@ -332,6 +337,7 @@ tracking:该脚本会追踪你的用户信息`.replace(/\n/g, "
"),
quickfix: "Sửa lỗi {0}",
addEslintDisableNextLine: "Thêm chú thích eslint-disable-next-line",
addEslintDisable: "Thêm chú thích eslint-disable",
+ declareGlobal: "Khai báo '{0}' là biến toàn cục (/* global */)",
prompt: {
name: "Tên script",
namespace: "Namespace của script",
@@ -394,6 +400,7 @@ tracking:该脚本会追踪你的用户信息`.replace(/\n/g, "
"),
quickfix: "Исправить проблему {0}",
addEslintDisableNextLine: "Добавить комментарий eslint-disable-next-line",
addEslintDisable: "Добавить комментарий eslint-disable",
+ declareGlobal: "Объявить '{0}' как глобальную переменную (/* global */)",
prompt: {
name: "Имя скрипта",
namespace: "Пространство имён скрипта",
@@ -587,7 +594,7 @@ export default function registerEditor() {
}
actions.push({
- title: `将 '${globalName}' 声明为全局变量 (/* global */)`,
+ title: multiLang.declareGlobal.replace("{0}", globalName),
diagnostics: [val],
kind: "quickfix",
edit: {