前言
对于 Monaco 这个编辑器我在两个项目中都用到了,第一个项目是 Open-Lineage,体验地址:openbytecode.com/openLineage… 效果如下:
第二个项目就是 OpenByteCode,体验地址:openbytecode.com/
市面上编辑器有很多,由于我这里选择了 Monaco,所以本文主要讲 Monaco 的使用方法。
在 react 中使用方法(使用 webpack 打包)
- 安装依赖
yarn add react-monaco-editor
- 安装插件
yarn add monaco-editor-webpack-plugin -D
- 安装重写 webpack 配置依赖
yarn add react-app-rewired -D
- 创建如下文件 config-overrides.js 覆盖默认的 webpack plugin 配置
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
module.exports = function override(config, env) {
if (!config.plugins){
config.plugins = [];
}
config.plugins.push(new MonacoWebpackPlugin({
languages: ["sql", "json", "javascript", "typescript"],
}))
return config;
};
- 编写组件
import { useRef, useState } from 'react';
import MonacoEditor from 'react-monaco-editor';
interface SqlEditorProps {
theme?: string;
}
const SqlEditor = ({ theme }: SqlEditorProps) => {
const editorRef = useRef();
const [code, setCode] = useState('select * from ');
const options: any = {
// selectOnLineNumbers: true,
// roundedSelection: false,
// readOnly: false,
// cursorStyle: 'line',
// automaticLayout: true,
// selectOnLineNumbers: true,
// renderSideBySide: false,
// scrollBeyondLastLine: false,
// formatOnPaste: true,
// automaticLayout: true,
// contextmenu: false, // 禁止右键
// fixedOverflowWidgets: true, // 超出编辑器大小的使用fixed属性显示
// quickSuggestions: true, // 默认的提示关掉
// minimap: {
// // 缩略图
// enabled: false,
// },
// scrollbar: {
// // 滚动条
// horizontalScrollbarSize: 6,
// verticalScrollbarSize: 6,
// },
// lineNumbersMinChars: 3, // 最少显示3位长的行号
// lineNumbers: 'on', // 是否显示行号
};
const editorDidMount = (editor: any, monaco: any) => {
console.log('editorDidMount', editor);
editor.focus();
};
const onChange = (newValue: any, e: any) => {
console.log('onChange', newValue, e);
};
return (
<>
<MonacoEditor
width='340'
height='600'
language='sql'
theme={theme || 'vs-light'}
value={code}
options={options}
onChange={onChange}
//editorDidMount={editorDidMount}
/>
</>
);
};
export default SqlEditor;
- 使用组件
<div className='layout-sider-edit'>
<SqlEditor theme={theme} />
</div>
在 react 中使用方法(使用 Vite 打包)
- 安装依赖
yarn add monaco-editor
注意:这回就不需要安装其他插件了
- 编写组件
import { useEffect, useMemo, useRef, useState } from 'react';
import * as monaco from 'monaco-editor';
import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
import JsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker';
import CssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker';
import HtmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker';
import TsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker';
import { MonacoEditorProps } from './types';
import { noop, processSize } from './utils';
(self as any).MonacoEnvironment = {
getWorker(_: any, label: any) {
if (label === 'json') {
return new JsonWorker();
}
if (label === 'css' || label === 'scss' || label === 'less') {
return new CssWorker();
}
if (label === 'html' || label === 'handlebars' || label === 'razor') {
return new HtmlWorker();
}
if (label === 'typescript' || label === 'javascript') {
return new TsWorker();
}
return new EditorWorker();
},
};
const MonacoEditor = ({
width,
height,
value,
defaultValue,
language,
theme,
options,
onChange,
className,
}: MonacoEditorProps) => {
const containerElement = useRef<HTMLDivElement | null>(null);
const editor = useRef<monaco.editor.IStandaloneCodeEditor | null>(null);
const fixedWidth = processSize(width || '');
const fixedHeight = processSize(height || '');
const style = useMemo(
() => ({
width: fixedWidth,
height: fixedHeight,
}),
[fixedWidth, fixedHeight]
);
const initMonaco = () => {
const finalValue = value !== null ? value : defaultValue;
if (!editor.current && containerElement.current) {
const finalOptions = { ...options };
editor.current = monaco.editor.create(containerElement.current, {
value: finalValue,
language,
...(className ? { extraEditorClassName: className } : {}),
...finalOptions,
...(theme ? { theme } : {}),
});
editor.current.onDidChangeModelContent((event) => {
onChange && onChange(editor.current?.getValue() || '', event);
});
}
};
useEffect(() => {
initMonaco();
editor.current?.focus();
}, []);
useEffect(() => {
editor.current?.layout();
}, [width, height]);
useEffect(() => {
monaco.editor.setTheme(theme || '');
}, [theme]);
useEffect(() => {
if (editor.current) {
const model: any = editor.current.getModel();
monaco.editor.setModelLanguage(model, language || '');
}
}, [language]);
return (
<div
ref={containerElement}
style={style}
/>
);
};
MonacoEditor.defaultProps = {
width: '100%',
height: '100%',
value: null,
defaultValue: '',
language: 'javascript',
theme: null,
options: {},
onChange: noop,
className: null,
};
export default MonacoEditor;
- 使用组件
<div className='layout-sidebar-edit'>
<MonacoEditor
width='340'
height='600'
language='sql'
theme={theme}
value={code}
onChange={(value) => setCode(value)}
/>
</div>
在 NextJs 中使用方法(使用 turbopack 打包)
- 安装依赖
pnpm install @monaco-editor/react
注意:这回也不需要安装其他插件
- 编写组件
import MonacoEditor from '@monaco-editor/react';
interface EditorCodeProps {
lang?: string;
theme: string;
input: string;
setInput: (value: any) => void;
}
const EditorCode = ({
lang = 'markdown',
theme,
setInput,
input,
}: EditorCodeProps) => {
return (
<div className='absolute inset-0 h-full w-full bg-wash dark:bg-[#1e293b]'>
<MonacoEditor
onChange={setInput}
theme={theme}
defaultLanguage={lang}
defaultValue={input}
options={{
// https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.IEditorConstructionOptions.html
minimap: {
enabled: false,
},
lineNumbers: 'on',
scrollBeyondLastLine: false,
hideCursorInOverviewRuler: true,
matchBrackets: 'never',
overviewRulerBorder: false,
renderLineHighlight: 'none',
wordWrap: 'on',
tabSize: 2,
}}
/>
</div>
);
};
export default EditorCode;
- 使用组件
<div className='flex flex-auto border-t border-gray-200 dark:border-white/10'>
<EditorCode
setInput={setInput}
theme={editorTheme}
input={input}
/>
</div>
总结
上面我按照不同的打包工具分别讲了 Monaco 编辑器的使用方法,当然,如果是用 Vite 打包的话,那么也是可以用第三种方案的