diff --git a/UPDATELOG.md b/UPDATELOG.md index f0898dbc7..c26123b1d 100644 --- a/UPDATELOG.md +++ b/UPDATELOG.md @@ -8,6 +8,9 @@
🚀 优化改进 + +- 替换前端信息编辑组件,提供更好性能 +
## v2.4.3 diff --git a/package.json b/package.json index 1c76cb634..bdbe35bc0 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.1", "@juggle/resize-observer": "^3.4.0", + "@monaco-editor/react": "^4.7.0", "@mui/icons-material": "^7.3.5", "@mui/lab": "7.0.0-beta.17", "@mui/material": "^7.3.5", @@ -70,7 +71,6 @@ "react-hook-form": "^7.66.0", "react-i18next": "16.2.4", "react-markdown": "10.1.0", - "react-monaco-editor": "0.59.0", "react-router": "^7.9.5", "react-virtuoso": "^4.14.1", "swr": "^2.3.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5777499e0..63720b241 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,6 +26,9 @@ importers: '@juggle/resize-observer': specifier: ^3.4.0 version: 3.4.0 + '@monaco-editor/react': + specifier: ^4.7.0 + version: 4.7.0(monaco-editor@0.54.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@mui/icons-material': specifier: ^7.3.5 version: 7.3.5(@mui/material@7.3.5(@emotion/react@11.14.0(@types/react@19.2.2)(react@19.2.0))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@types/react@19.2.2)(react@19.2.0) @@ -116,9 +119,6 @@ importers: react-markdown: specifier: 10.1.0 version: 10.1.0(@types/react@19.2.2)(react@19.2.0) - react-monaco-editor: - specifier: 0.59.0 - version: 0.59.0(monaco-editor@0.54.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) react-router: specifier: ^7.9.5 version: 7.9.5(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -1127,6 +1127,16 @@ packages: '@juggle/resize-observer@3.4.0': resolution: {integrity: sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==} + '@monaco-editor/loader@1.6.1': + resolution: {integrity: sha512-w3tEnj9HYEC73wtjdpR089AqkUPskFRcdkxsiSFt3SoUc3OHpmu+leP94CXBm4mHfefmhsdfI0ZQu6qJ0wgtPg==} + + '@monaco-editor/react@4.7.0': + resolution: {integrity: sha512-cyzXQCtO47ydzxpQtCGSQGOC8Gk3ZUeBXFAxD+CWXYFo5OqZyZUonFl0DwUlTyAfRHntBfw2p3w4s9R6oe1eCA==} + peerDependencies: + monaco-editor: '>= 0.25.0 < 1' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + '@mui/core-downloads-tracker@7.3.5': resolution: {integrity: sha512-kOLwlcDPnVz2QMhiBv0OQ8le8hTCqKM9cRXlfVPL91l3RGeOsxrIhNRsUt3Xb8wb+pTVUolW+JXKym93vRKxCw==} @@ -3241,6 +3251,9 @@ packages: lru-queue@0.1.0: resolution: {integrity: sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==} + magic-string@0.30.19: + resolution: {integrity: sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==} + magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} @@ -3652,13 +3665,6 @@ packages: '@types/react': '>=18' react: '>=18' - react-monaco-editor@0.59.0: - resolution: {integrity: sha512-SggqfZCdUauNk7GI0388bk5n25zYsQ1ai1i+VhxAgwbCH+MTGl7L1fBNTJ6V+oXeUApf+bpzikprHJEZm9J/zA==} - peerDependencies: - monaco-editor: ^0.52.0 - react: '>=16.8.0 <20.0.0' - react-dom: '>=16.8.0 <20.0.0' - react-router@7.9.5: resolution: {integrity: sha512-JmxqrnBZ6E9hWmf02jzNn9Jm3UqyeimyiwzD69NjxGySG6lIz/1LVPsoTCwN7NBX2XjCEa1LIX5EMz1j2b6u6A==} engines: {node: '>=20.0.0'} @@ -3875,6 +3881,9 @@ packages: stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + state-local@1.0.7: + resolution: {integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==} + std-env@3.10.0: resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} @@ -5378,6 +5387,17 @@ snapshots: '@juggle/resize-observer@3.4.0': {} + '@monaco-editor/loader@1.6.1': + dependencies: + state-local: 1.0.7 + + '@monaco-editor/react@4.7.0(monaco-editor@0.54.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@monaco-editor/loader': 1.6.1 + monaco-editor: 0.54.0 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + '@mui/core-downloads-tracker@7.3.5': {} '@mui/icons-material@7.3.5(@mui/material@7.3.5(@emotion/react@11.14.0(@types/react@19.2.2)(react@19.2.0))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@types/react@19.2.2)(react@19.2.0)': @@ -6171,7 +6191,7 @@ snapshots: browserslist: 4.25.1 browserslist-to-esbuild: 2.1.1(browserslist@4.25.1) core-js: 3.45.0 - magic-string: 0.30.21 + magic-string: 0.30.19 regenerator-runtime: 0.14.1 systemjs: 6.15.1 terser: 5.44.1 @@ -7666,6 +7686,10 @@ snapshots: dependencies: es5-ext: 0.10.64 + magic-string@0.30.19: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -8216,12 +8240,6 @@ snapshots: transitivePeerDependencies: - supports-color - react-monaco-editor@0.59.0(monaco-editor@0.54.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0): - dependencies: - monaco-editor: 0.54.0 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - react-router@7.9.5(react-dom@19.2.0(react@19.2.0))(react@19.2.0): dependencies: cookie: 1.0.2 @@ -8499,6 +8517,8 @@ snapshots: stackback@0.0.2: {} + state-local@1.0.7: {} + std-env@3.10.0: {} stop-iteration-iterator@1.1.0: diff --git a/src/components/profile/editor-viewer.tsx b/src/components/profile/editor-viewer.tsx index c28f57382..016344617 100644 --- a/src/components/profile/editor-viewer.tsx +++ b/src/components/profile/editor-viewer.tsx @@ -1,7 +1,8 @@ +import MonacoEditor from "@monaco-editor/react"; import { + CloseFullscreenRounded, FormatPaintRounded, OpenInFullRounded, - CloseFullscreenRounded, } from "@mui/icons-material"; import { Button, @@ -22,7 +23,6 @@ import { configureMonacoYaml } from "monaco-yaml"; import { nanoid } from "nanoid"; import { ReactNode, useEffect, useMemo, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; -import MonacoEditor from "react-monaco-editor"; import pac from "types-pac/pac.d.ts?raw"; import { showNotice } from "@/services/noticeService"; @@ -103,17 +103,15 @@ export const EditorViewer = (props: Props) => { [initialData], ); - const editorRef = useRef(undefined); + const editorRef = useRef(null); const prevData = useRef(""); const currData = useRef(""); - const editorWillMount = () => { + const beforeMount = () => { monacoInitialization(); // initialize monaco }; - const editorDidMount = async ( - editor: monaco.editor.IStandaloneCodeEditor, - ) => { + const onMount = async (editor: monaco.editor.IStandaloneCodeEditor) => { editorRef.current = editor; // retrieve initial data @@ -177,12 +175,12 @@ export const EditorViewer = (props: Props) => { return () => { unlistenResized.then((fn) => fn()); editorRef.current?.dispose(); - editorRef.current = undefined; + editorRef.current = null; }; }, [editorResize]); return ( - + {resolvedTitle} (props: Props) => { fontLigatures: false, // 连字符 smoothScrolling: true, // 平滑滚动 }} - editorWillMount={editorWillMount} - editorDidMount={editorDidMount} + beforeMount={beforeMount} + onMount={onMount} onChange={handleChange} /> diff --git a/src/components/profile/groups-editor-viewer.tsx b/src/components/profile/groups-editor-viewer.tsx index f41178305..e329e2485 100644 --- a/src/components/profile/groups-editor-viewer.tsx +++ b/src/components/profile/groups-editor-viewer.tsx @@ -1,19 +1,20 @@ import { DndContext, - closestCenter, + DragEndEvent, KeyboardSensor, PointerSensor, + closestCenter, useSensor, useSensors, - DragEndEvent, } from "@dnd-kit/core"; import { SortableContext, sortableKeyboardCoordinates, } from "@dnd-kit/sortable"; +import MonacoEditor from "@monaco-editor/react"; import { - VerticalAlignTopRounded, VerticalAlignBottomRounded, + VerticalAlignTopRounded, } from "@mui/icons-material"; import { Autocomplete, @@ -32,8 +33,8 @@ import { } from "@mui/material"; import { useLockFn } from "ahooks"; import { - requestIdleCallback, cancelIdleCallback, + requestIdleCallback, } from "foxact/request-idle-callback"; import yaml from "js-yaml"; import { @@ -45,7 +46,6 @@ import { } from "react"; import { Controller, useForm } from "react-hook-form"; import { useTranslation } from "react-i18next"; -import MonacoEditor from "react-monaco-editor"; import { Virtuoso } from "react-virtuoso"; import { Switch } from "@/components/base"; @@ -1000,7 +1000,7 @@ export const GroupsEditorViewer = (props: Props) => { fontLigatures: false, // 连字符 smoothScrolling: true, // 平滑滚动 }} - onChange={(value) => setCurrData(value)} + onChange={(value) => setCurrData(value ?? "")} /> )} diff --git a/src/components/profile/proxies-editor-viewer.tsx b/src/components/profile/proxies-editor-viewer.tsx index ccf2891c4..9143ef8de 100644 --- a/src/components/profile/proxies-editor-viewer.tsx +++ b/src/components/profile/proxies-editor-viewer.tsx @@ -1,19 +1,20 @@ import { DndContext, - closestCenter, + DragEndEvent, KeyboardSensor, PointerSensor, + closestCenter, useSensor, useSensors, - DragEndEvent, } from "@dnd-kit/core"; import { SortableContext, sortableKeyboardCoordinates, } from "@dnd-kit/sortable"; +import MonacoEditor from "@monaco-editor/react"; import { - VerticalAlignTopRounded, VerticalAlignBottomRounded, + VerticalAlignTopRounded, } from "@mui/icons-material"; import { Box, @@ -37,7 +38,6 @@ import { useState, } from "react"; import { useTranslation } from "react-i18next"; -import MonacoEditor from "react-monaco-editor"; import { Virtuoso } from "react-virtuoso"; import { ProxyItem } from "@/components/profile/proxy-item"; @@ -490,7 +490,7 @@ export const ProxiesEditorViewer = (props: Props) => { fontLigatures: false, // 连字符 smoothScrolling: true, // 平滑滚动 }} - onChange={(value) => setCurrData(value)} + onChange={(value) => setCurrData(value ?? "")} /> )} diff --git a/src/components/profile/rules-editor-viewer.tsx b/src/components/profile/rules-editor-viewer.tsx index 8f2aa8454..585d08c4e 100644 --- a/src/components/profile/rules-editor-viewer.tsx +++ b/src/components/profile/rules-editor-viewer.tsx @@ -1,19 +1,20 @@ import { DndContext, - closestCenter, + DragEndEvent, KeyboardSensor, PointerSensor, + closestCenter, useSensor, useSensors, - DragEndEvent, } from "@dnd-kit/core"; import { SortableContext, sortableKeyboardCoordinates, } from "@dnd-kit/sortable"; +import MonacoEditor from "@monaco-editor/react"; import { - VerticalAlignTopRounded, VerticalAlignBottomRounded, + VerticalAlignTopRounded, } from "@mui/icons-material"; import { Autocomplete, @@ -39,7 +40,6 @@ import { useState, } from "react"; import { useTranslation } from "react-i18next"; -import MonacoEditor from "react-monaco-editor"; import { Virtuoso } from "react-virtuoso"; import { Switch } from "@/components/base"; @@ -769,7 +769,7 @@ export const RulesEditorViewer = (props: Props) => { fontLigatures: false, // 连字符 smoothScrolling: true, // 平滑滚动 }} - onChange={(value) => setCurrData(value)} + onChange={(value) => setCurrData(value ?? "")} /> )} diff --git a/src/components/setting/mods/dns-viewer.tsx b/src/components/setting/mods/dns-viewer.tsx index 7a5b12b83..9054ec2ff 100644 --- a/src/components/setting/mods/dns-viewer.tsx +++ b/src/components/setting/mods/dns-viewer.tsx @@ -1,3 +1,4 @@ +import MonacoEditor from "@monaco-editor/react"; import { RestartAltRounded } from "@mui/icons-material"; import { Box, @@ -25,7 +26,6 @@ import { useState, } from "react"; import { useTranslation } from "react-i18next"; -import MonacoEditor from "react-monaco-editor"; import { BaseDialog, DialogRef, Switch } from "@/components/base"; import { useClash } from "@/hooks/use-clash"; @@ -568,12 +568,12 @@ export function DnsViewer({ ref }: { ref?: Ref }) { }); // YAML编辑器内容变更处理 - const handleYamlChange = (value: string) => { + const handleYamlChange = (value?: string) => { setYamlContent(value || ""); // 允许YAML编辑后立即分析和更新表单值 try { - const config = yaml.load(value) as any; + const config = yaml.load(value || "") as any; if (config && typeof config === "object") { setTimeout(() => { updateValuesFromConfig(config);