monaco-editor 加载优化

This commit is contained in:
cnwhy
2024-05-30 18:48:13 +08:00
parent 1514a710e5
commit 2ef6d93601
10 changed files with 204 additions and 184 deletions
+6 -2
View File
@@ -6,8 +6,12 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" href="/favicon.ico" />
<link rel="manifest" href="/manifest.json">
<script src="%VITE_MONACO_URL%/min/vs/loader.js"></script>
<!-- <script src="//unpkg.com/monaco-editor@0.47.0/min/vs/loader.js"></script> -->
<script id="nonaco" src="%VITE_MONACO_URL%/min/vs/loader.js"></script>
<script>
(function(){
require.config({ paths: { vs: document.getElementById("nonaco").src.replace(/\/loader\.js/,'') } });
})();
</script>
</head>
<body>
<div id="root"></div>
-1
View File
@@ -7,7 +7,6 @@
"": {
"name": "gost-ui",
"version": "0.0.0",
"hasInstallScript": true,
"dependencies": {
"@ant-design/icons": "^5.2.6",
"antd": "^5.11.0",
+1 -4
View File
@@ -10,10 +10,7 @@
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview",
"init:monaco": "cpx ./node_modules/monaco-editor/min/** ./public/monaco-editor/min",
"postinstall": "npm run init:monaco",
"predev": "npm run init:monaco",
"prebuild": "npm run init:monaco",
"preanalyzer": "npm run init:monaco"
"prebuild": "npm run init:monaco"
},
"dependencies": {
"@ant-design/icons": "^5.2.6",
+2
View File
@@ -14,6 +14,8 @@ body {
.g-boder {
border: 1px solid #ccc;
border-radius: 5px;
overflow: hidden;
}
:root.theme-dark {
+7 -5
View File
@@ -105,12 +105,14 @@ function App() {
}
}, [info]);
useEffect(() => {
if(isDark){
document.documentElement.classList.add("theme-dark")
}else{
document.documentElement.classList.remove("theme-dark")
if (isDark) {
document.documentElement.classList.add("theme-dark");
(window as any)?.monaco?.editor.setTheme("vs-dark");
} else {
document.documentElement.classList.remove("theme-dark");
(window as any)?.monaco?.editor.setTheme("vs");
}
},[isDark])
}, [isDark]);
return (
<Ctx.Provider
value={{
+69 -71
View File
@@ -141,14 +141,12 @@ const Manage = () => {
key: "new",
label: "打开新链接",
onClick: () => {
console.log(location.href);
window.open(location.href, undefined, "noopener");
},
});
return items;
}, [locals]);
console.log("gostInfo", info);
return (
<Layout style={{ height: "100vh", overflow: "hidden" }}>
<Layout.Header style={{ color: "#FFF", paddingInline: 20 }}>
@@ -215,7 +213,6 @@ const Manage = () => {
layout="horizontal"
labelCol={{ span: 4 }}
onValuesChange={(v, vs) => {
console.log(v, vs);
Object.assign(info, v);
useInfo.set(info);
if (info.isLocal) {
@@ -238,74 +235,75 @@ const Manage = () => {
</Form>
</Modal>
</Layout.Header>
<Layout.Content style={{ height: "100%", overflow: "auto" }}>
<Row style={{ padding: 16, overflow: "hidden" }}>
<Row gutter={[16, 16]}>
{/* <Col {...colSpan} xxl={16}> */}
<ServiceCard colSpan={colSpan}></ServiceCard>
{/* </Col> */}
<Col {...colSpan}>
<ChainCard></ChainCard>
</Col>
<Col {...colSpan}>
<HopsCard />
</Col>
<Col {...colSpan}>
<ListCard module="auther" />
</Col>
<Col {...colSpan}>
<ListCard module="admission" />
</Col>
<Col {...colSpan}>
<ListCard module="bypass" />
</Col>
<Col {...colSpan}>
<ListCard module="host" />
</Col>
<Col {...colSpan}>
<ListCard module="ingress" />
</Col>
<Col {...colSpan}>
<ListCard module="resolver" />
</Col>
<Col {...colSpan}>
<ListCard module="sd" />
</Col>
<Col {...colSpan}>
<ListCard module="observer" />
</Col>
<Col span={24}>
<ProCard boxShadow title="限速限流">
<Row gutter={[16, 16]}>
<Col {...colSpan1}>
<ListCard module="limiter" bordered boxShadow={false} />
</Col>
<Col {...colSpan1}>
<ListCard module="rlimiter" bordered boxShadow={false} />
</Col>
<Col {...colSpan1}>
<ListCard module="climiter" bordered boxShadow={false} />
</Col>
</Row>
</ProCard>
</Col>
<Col span={24}>
<ProCard boxShadow title="All Config JSON">
{/* <pre>{jsonFormat(gostConfig!)}</pre> */}
<CodeEditor
className={"g-boder"}
value={jsonFormat(gostConfig!)}
height={500}
language="json"
options={{
// selectOnLineNumbers: true,
minimap: { enabled: false },
readOnly: true,
}}
></CodeEditor>
</ProCard>
</Col>
</Row>
<Layout.Content style={{ height: "100%", padding: 16, boxSizing:'border-box', overflow: "auto" }}>
<Row gutter={[16, 16]} style={{ overflow: "hidden" }}>
{/* <Col {...colSpan} xxl={16}> */}
<ServiceCard colSpan={colSpan}></ServiceCard>
{/* </Col> */}
<Col {...colSpan}>
<ChainCard></ChainCard>
</Col>
<Col {...colSpan}>
<HopsCard />
</Col>
<Col {...colSpan}>
<ListCard module="auther" />
</Col>
<Col {...colSpan}>
<ListCard module="admission" />
</Col>
<Col {...colSpan}>
<ListCard module="bypass" />
</Col>
<Col {...colSpan}>
<ListCard module="host" />
</Col>
<Col {...colSpan}>
<ListCard module="ingress" />
</Col>
<Col {...colSpan}>
<ListCard module="resolver" />
</Col>
<Col {...colSpan}>
<ListCard module="sd" />
</Col>
<Col {...colSpan}>
<ListCard module="observer" />
</Col>
<Col span={24}>
<ProCard boxShadow title="限速限流">
<Row gutter={[16, 16]}>
<Col {...colSpan1}>
<ListCard module="limiter" bordered boxShadow={false} />
</Col>
<Col {...colSpan1}>
<ListCard module="rlimiter" bordered boxShadow={false} />
</Col>
<Col {...colSpan1}>
<ListCard module="climiter" bordered boxShadow={false} />
</Col>
</Row>
</ProCard>
</Col>
<Col span={24}>
<ProCard
boxShadow
title="All Config JSON"
styles={{ body: { padding: 20 } }}
>
<CodeEditor
className={"g-boder"}
value={jsonFormat(gostConfig!)}
height={500}
language="json"
options={{
// selectOnLineNumbers: true,
minimap: { enabled: false },
readOnly: true,
}}
></CodeEditor>
</ProCard>
</Col>
</Row>
</Layout.Content>
</Layout>
-1
View File
@@ -213,7 +213,6 @@ export const showJsonForm = (props: JsonFromProps) => {
}
function destroy() {
console.log("destroy");
root.unmount();
document.body.removeChild(container);
}
+1 -1
View File
@@ -38,7 +38,7 @@ export const jsonParse = (str: string) => {
const errs: any[] = [];
const obj = parse(str, errs, { allowTrailingComma: true });
if (errs.length) {
console.log(errs);
console.error(errs);
throw errs[0];
}
return obj;
+116 -96
View File
@@ -3,37 +3,41 @@ import { useBindValue } from "./use";
import type * as Monaco from "monaco-editor";
import classnames from "classnames";
import { useIsDark } from "./useTheme";
import { Input } from "antd";
(function () {
const require = (window as any).require;
let monacoURL;
const MONACO_URL = import.meta.env.VITE_MONACO_URL || '/monaco-editor';
if(/^(http[s]:)?\/\//.test(MONACO_URL)){
monacoURL = MONACO_URL + '/min/vs'
}else{
const baseURL = new URL(import.meta.env.BASE_URL, location.href).href;
monacoURL = new URL(`${MONACO_URL}/min/vs`, baseURL).href;
}
// let monacoURL;
// const MONACO_URL = import.meta.env.VITE_MONACO_URL || '/monaco-editor';
// if(/^(http[s]:)?\/\//.test(MONACO_URL)){
// monacoURL = MONACO_URL + '/min/vs'
// }else{
// const baseURL = new URL(import.meta.env.BASE_URL, location.href).href;
// monacoURL = new URL(`${MONACO_URL}/min/vs`, baseURL).href;
// }
// if(import.meta.env.PROD && import.meta.env.VITE_MONACO_URL){
// monacoURL = import.meta.env.VITE_MONACO_URL + '/min/vs';
// }else{
// const baseURL = new URL(import.meta.env.BASE_URL, location.href).href;
// monacoURL = new URL("./monaco-editor/min/vs", baseURL).href;
// }
// console.log(`import_meta_env_BASE_URL`, import.meta.env.BASE_URL);
// console.log("baseURL", baseURL);
// const monacoURL = `//unpkg.com/monaco-editor@0.47.0/min/vs`
require.config({ paths: { vs: `${monacoURL}` } });
require.config({
"vs/nls": {
availableLanguages: {
"*": "zh-cn",
// require.config({ paths: { vs: `${monacoURL}` } });
if (require) {
require.config({
"vs/nls": {
availableLanguages: {
"*": "zh-cn",
},
},
},
});
});
}
(window as any).monacoIsReady = new Promise((resolve, reject) => {
if (!require) return reject("Not loaded monaco loader.js");
require(["vs/editor/editor.main"], function () {
resolve(monaco);
});
@@ -79,10 +83,10 @@ const CodeEditor_: React.ForwardRefRenderFunction<
const editor = useRef<any>(null);
const self = useRef<any>({});
const isDark = useIsDark();
const _theme = useMemo(()=>{
if(theme) return theme;
return isDark ? 'vs-dark' : 'vs'
},[theme, isDark])
const _theme = useMemo(() => {
if (theme) return theme;
return isDark ? "vs-dark" : "vs";
}, [theme, isDark]);
React.useImperativeHandle(ref, () => {
return editor.current!;
@@ -97,82 +101,87 @@ const CodeEditor_: React.ForwardRefRenderFunction<
},
[onChange]
);
useEffect(() => {
// let editor: any;
if (divEl.current) {
const el = divEl.current;
let _editor: Monaco.editor.IStandaloneCodeEditor;
monacoIsReady.then(() => {
_editor = editor.current = monaco.editor.create(el, {
value: value,
language: language,
theme: _theme,
...defOptions,
...options,
});
console.log("editor.current", editor.current.getDomNode());
_editor.onDidChangeModelContent(function (event: any) {
const _value = _editor.getValue();
setValue(_value);
self.current?.onChange?.(_value);
});
_editor.addCommand(monaco.KeyMod.Alt | monaco.KeyCode.KeyX, (e) => {
_editor.getAction("my-autoWrap-toggle")?.run();
});
_editor.addAction({
id: "my-autoWrap-toggle",
label: "切换自动换行",
keybindings: [
monaco.KeyMod.Alt | monaco.KeyCode.KeyZ,
// monaco.KeyMod.chord(
// monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyK,
// monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyM
// ),
],
// A precondition for this action.
// precondition: null,
// A rule to evaluate on top of the precondition in order to dispatch the keybindings.
// keybindingContext: null,
// contextMenuGroupId: "navigation",
// contextMenuOrder: 1.5,
// Method that will be executed when the action is triggered.
// @param editor The editor instance is passed in as a convenience
run: function (ed, arg) {
// alert("i'm running => " + ed.getPosition());
// console.log("my-autoWrap-toggle", arg);
const workWrap = ed.getOption(monaco.editor.EditorOption.wordWrap);
ed.updateOptions({
wordWrap: workWrap === "on" ? "off" : "on",
});
},
});
setReady(true);
});
// let xc: any;
// const resizeObserver = new ResizeObserver((entries) => {
// // _editor?.layout();
// // console.log("resizeObserver");
// if (xc) clearTimeout(xc);
// xc = setTimeout(() => {
// _editor?.layout();
// }, 100);
// });
// resizeObserver.observe(el);
return () => {
_editor?.dispose?.();
// resizeObserver.unobserve(el);
// resizeObserver.disconnect();
};
}
monacoIsReady.then(() => {
setReady(true);
});
}, []);
useEffect(() => {
if (isReady) {
if (divEl.current) {
const devel = divEl.current;
let _editor: Monaco.editor.IStandaloneCodeEditor;
monacoIsReady.then(() => {
_editor = editor.current = monaco.editor.create(devel, {
value: value,
language: language,
theme: _theme,
...defOptions,
...options,
});
_editor.onDidChangeModelContent(function (event: any) {
const _value = _editor.getValue();
setValue(_value);
self.current?.onChange?.(_value);
});
_editor.addCommand(monaco.KeyMod.Alt | monaco.KeyCode.KeyX, (e) => {
_editor.getAction("my-autoWrap-toggle")?.run();
});
_editor.addAction({
id: "my-autoWrap-toggle",
label: "切换自动换行",
keybindings: [
monaco.KeyMod.Alt | monaco.KeyCode.KeyZ,
// monaco.KeyMod.chord(
// monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyK,
// monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyM
// ),
],
// A precondition for this action.
// precondition: null,
// A rule to evaluate on top of the precondition in order to dispatch the keybindings.
// keybindingContext: null,
// contextMenuGroupId: "navigation",
// contextMenuOrder: 1.5,
// Method that will be executed when the action is triggered.
// @param editor The editor instance is passed in as a convenience
run: function (ed, arg) {
// alert("i'm running => " + ed.getPosition());
// console.log("my-autoWrap-toggle", arg);
const workWrap = ed.getOption(
monaco.editor.EditorOption.wordWrap
);
ed.updateOptions({
wordWrap: workWrap === "on" ? "off" : "on",
});
},
});
});
// let xc: any;
// const resizeObserver = new ResizeObserver((entries) => {
// // _editor?.layout();
// // console.log("resizeObserver");
// if (xc) clearTimeout(xc);
// xc = setTimeout(() => {
// _editor?.layout();
// }, 100);
// });
// resizeObserver.observe(el);
return () => {
_editor?.dispose?.();
// resizeObserver.unobserve(el);
// resizeObserver.disconnect();
};
}
}
// let editor: any;
}, [isReady]);
useEffect(() => {
if (editor.current) {
@@ -182,7 +191,7 @@ const CodeEditor_: React.ForwardRefRenderFunction<
}
}, [value]);
return (
return isReady ? (
<div
className={classnames(className)}
style={{
@@ -194,6 +203,17 @@ const CodeEditor_: React.ForwardRefRenderFunction<
}}
ref={divEl}
></div>
) : (
<Input.TextArea
style={{ height: height || "100%" }}
className={classnames(className)}
value={value}
onChange={(event) => {
const _value = event.target.value;
setValue(_value);
self.current?.onChange?.(_value);
}}
></Input.TextArea>
);
};
+2 -3
View File
@@ -6,9 +6,8 @@ import { analyzer } from "vite-bundle-analyzer";
export default defineConfig(({ command, mode }) => {
const config: UserConfig = {
base: "./",
plugins: [
react()
],
plugins: [react()],
define: {},
};
if (mode === "development") {