[muzzik教程]:在插件内使用代码编辑器

# 效果

# 前言

由于使用坑比较多,所以开贴记录

# 选择

市面上流行的编辑器有Ace,Monaco,还有比较小众的 CodeMirror
这里有比较帖,可以看看,跳转链接

这里说说自己的使用感受

  • Ace

    • 好处: 轻量级,有官方文档,使用简单
    • 坏处: Typescript 没有类型提示,没有报错提示,全部需要自己接
  • Monaco

    • 好处:vscode核心,使用体验堪比 vscode,还可以接入部分插件
    • 坏处:没有官方文档,入门困难

经过体验后最终选择了 monaco 编辑器,只怪语法提示太香

# 接入

1. 安装 npm 包

npm i monaco-editor

2. 添加 css
    将下面的 link 标签放在 Editor.Panel.define 导出的 template 中

<link rel="stylesheet" href="替换为插件目录/node_modules/monaco-editor/min/vs/editor/editor.main.css"></link>

3. 使用加载器

ps: 由于 monaco 编辑器只有 esm 模块和 amd 模块,我们的插件不能直接使用,除了 webpack 等打包工具,还可以直接用 min 版本提供的 loader 加载器加载

/** monaco 加载器 */
const monaco_loader = require(path.join(
	替换为插件目录,
	"node_modules/monaco-editor/min/vs/loader"
));

// monaco 加载器配置
monaco_loader.require.config({
	paths: {
		vs: path.join(替换为插件目录, "node_modules/monaco-editor/min/vs"),
	},
	// 本地化
	"vs/nls": {
		availableLanguages: { "*": "zh-cn" },
	},
});

4. 加载编辑器并初始化
    这里注意我们查找的标签类名为 editor,也就是 <div class="editor"></div>才是编辑器的标签,当然也可以自行修改

  • ts:typescript 模块,自行 npm i typescriptimport ts from "typescript";
// 加载编辑器并初始化
monaco_loader.require(
	["vs/editor/editor.main"],
	(monaco: typeof import("monaco-editor")) => {
		/** 编辑器元素 */
		let editor_element_as = (this.$el as HTMLElement).getElementsByClassName(
			"editor"
		);
		if (!editor_element_as.length) {
			return;
		}

		// 引用 cc.d.ts
		{
			let file_s = fs.readFileSync(
				path.join(Editor.Project.path, "temp/declarations/cc.d.ts"),
				"utf-8"
			);
			let reg_as = file_s.match(/(?<=<reference path=")([^"]*)(?=")/g);
			if (reg_as?.length) {
				monaco.languages.typescript.typescriptDefaults.addExtraLib(
					fs.readFileSync(reg_as[0], "utf-8").replace('"cc"', "cc"),
					"cc.d.ts"
				);
			}
		}

		/** 当前编辑器 model */
		let curr_model = monaco.editor.createModel(
			``,
			"typescript",
			monaco.Uri.parse(`main.ts`)
		);

		/** 项目 tsconfig 解析 */
		let tsconfig_parse: ts.ParsedCommandLine;
		{
			/** 配置路径 */
			let tsconfig_path_s = path.join(Editor.Project.path, "tsconfig.json");
			let tsconfig = ts.readConfigFile(
				path.join(Editor.Project.path, "tsconfig.json"),
				ts.sys.readFile
			);
			if (!tsconfig.error) {
				 tsconfig_parse = ts.parseJsonConfigFileContent(
					tsconfig.config,
					ts.sys,
					path.dirname(tsconfig_path_s)
				);
			}
		}

		for (let k_n = 0, length_n = editor_element_as.length; k_n < length_n; k_n++) {
			let element = editor_element_as.item(k_n) as HTMLElement;

			// 初始化编辑器
			let editor = monaco.editor.create(element, {
				value: [""].join("\n"),
				language: "typescript",
				theme: "vs-dark",
				model: curr_model,
			});

			// 设置编译配置
			if (tsconfig_parse) {
				monaco.languages.typescript.typescriptDefaults.setCompilerOptions(
					tsconfig_parse.options as any
				);
			}

			// 防止编辑器初始化时元素未展示导致展示错误
			new ResizeObserver(() => {
				editor.layout();
			}).observe(element);
		}
	}
);

# 使用

1. 如何将文件夹设为工作区?
    这里大家记住,monaco编辑器没有工作区的概念,而是将每个文件都视为一个Model,我们只需要使用 monaco.editor.createModel 接口即可将文件导入我们的编辑器,如果要导入文件夹就需要遍历导入

// 示例
monaco.editor.createModel(
	// 文件内容字符串
	`export class Test {}`,
	// 语言类型
	"typescript",
	// 文件路径,xxx/xxx.ts
	monaco.Uri.parse(`Test.ts`)
);

结语

4赞

好贴没人围观么?

帖是好帖但是需求不是很强烈,主要还是已经习惯了vscode