前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Diff:如何用 MoncaoEditor 实现 JS 代码比对?

Diff:如何用 MoncaoEditor 实现 JS 代码比对?

作者头像
WEBJ2EE
发布2023-11-22 14:18:01
7900
发布2023-11-22 14:18:01
举报
文章被收录于专栏:WebJ2EEWebJ2EE

MonacoEditor是什么?

Monaco Editor 是一个从 VS Code 中分离出来的、网页版代码编辑器,由微软开源、界面美观、功能强大、开箱即用。(PS:要吐槽一下 Monaco Editor 的官方文档 ...... 是真的难读😕 )

❓ What is the relationship between VS Code and the Monaco Editor? The Monaco Editor is generated straight from VS Code's sources with some shims around services the code needs to make it run in a web browser outside of its home.

Monaco Editor 在开源社区也是非常火爆的一个项目(36.2k star),如果你需要在产品中嵌入一个代码编辑器组件,可以先试试 Monaco Editor。😄

MonacoEditor用来做代码比对

Monaco Editor 不仅是一个功能强大的代码编辑器,它还内置了一个代码比对组件(DiffEditor)(如下图)。

在Vite-React环境下接入DiffEditor

下面将完整演示如何在Vite、React环境下接入微软开源组件 Monaco Editor,并使用它的代码比对(DiffEditor)特性。

创建应用

首先,使用Vite脚手架快速搭建一个基于 Vite 的 React 应用。

npm create vite@latest react-monaco-diff -- --template react-ts

安装MonacoEditor

然后,在项目中安装 Monaco Editor 组件。

npm install monaco-editor

使用MonacoEditor

配置WebWorkers

Moncao Editor 的运行,需要一些 web worker 支撑,它们负责对 Monaco Editor 提供语言服务(例如:语法高亮、语法检验等)。(PS:我们不需了解这些 web worker 的工作细节,只需要让它们跑起来😄)

❓ Why all these web workers and why should I care? Language services create web workers to compute heavy stuff outside of the UI thread. They cost hardly anything in terms of resource overhead and you shouldn't worry too much about them, as long as you get them to work (see above the cross-domain case).

在 Vite 环境下,Monaco Editor在官方文档已经给出了配置方法,我们可以选择在应用入口引入如下代码:

代码语言:javascript
复制
// Since packaging is done by you, you need
// to instruct the editor how you named the
// bundles that contain the web workers.
self.MonacoEnvironment = {
  getWorkerUrl: function (moduleId, label) {
    if (label === 'json') {
      return './json.worker.bundle.js';
    }
    if (label === 'css' || label === 'scss' || label === 'less') {
      return './css.worker.bundle.js';
    }
    if (label === 'html' || label === 'handlebars' || label === 'razor') {
      return './html.worker.bundle.js';
    }
    if (label === 'typescript' || label === 'javascript') {
      return './ts.worker.bundle.js';
    }
    return './editor.worker.bundle.js';
  }
};
代码语言:javascript
复制

PS:如果你使用的是Webpack,MonacoEditor也给出了相关说明。

准备渲染容器

MonacoEditor 需要一个 div 作为渲染容器。

注:MonacoEditor 不会自动“撑开”这个渲染容器,所以别忘了给容器设置样式,让它可见。

代码语言:javascript
复制
const diffDOM = useRef<HTMLDivElement>(null);

<div ref={diffDOM} style={{ height: 400 }}></div>
代码语言:javascript
复制

创建DiffEditor

MonacoEditor 的代码比对能力,由 DiffEditor 组件提供,可以通过monaco.editor.createDiffEditor创建,并通过setModel接口设置需要比对的代码片段。

代码语言:javascript
复制
// 创建 DiffEditor 实例
const editorRef = useRef<monaco.editor.IStandaloneDiffEditor>(null);
editorRef.current = monaco.editor.createDiffEditor(diffDOM.current!, {
   diffCodeLens: true,
   readOnly: true,
   automaticLayout: true,
});

// 给 DiffEditor 设置需要比对的代码
const originalModel = monaco.editor.createModel(oldCode, "text/plain");
const modifiedModel = monaco.editor.createModel(newCode, "text/plain");
editorRef.current.setModel({
   original: originalModel,
   modified: modifiedModel,
});
代码语言:javascript
复制

及时销毁

MonacoEditor 使用完成后,别忘了及时销毁前面创建出来的实例对象。

代码语言:javascript
复制
// 销毁 DiffEditor 实例
editorRef.current?.dispose();
代码语言:javascript
复制

运行效果

完整代码

代码语言:javascript
复制
import { useRef, useEffect } from "react";

import * as monaco from "monaco-editor";
self.MonacoEnvironment = {
  getWorker: function (workerId, label) {
    const getWorkerModule = (moduleUrl, label) => {
      return new Worker(self.MonacoEnvironment.getWorkerUrl(moduleUrl), {
        name: label,
        type: "module",
      });
    };

    switch (label) {
      case "json":
        return getWorkerModule(
          "/monaco-editor/esm/vs/language/json/json.worker?worker",
          label
        );
      case "css":
      case "scss":
      case "less":
        return getWorkerModule(
          "/monaco-editor/esm/vs/language/css/css.worker?worker",
          label
        );
      case "html":
      case "handlebars":
      case "razor":
        return getWorkerModule(
          "/monaco-editor/esm/vs/language/html/html.worker?worker",
          label
        );
      case "typescript":
      case "javascript":
        return getWorkerModule(
          "/monaco-editor/esm/vs/language/typescript/ts.worker?worker",
          label
        );
      default:
        return getWorkerModule(
          "/monaco-editor/esm/vs/editor/editor.worker?worker",
          label
        );
    }
  },
};

const oldCode = `function bubble() {
  const arr = new Array(100).fill(1).map(() => Math.random());
  for (let i = 0; i < arr.length; i++) {
    for (let j = i + 1; j < arr.length; j++) {
      if (arr[i] > arr[j]) {
        const t = arr[i];
        arr[i] = arr[j];
        arr[j] = t;
      }
    }
  }
}`;

const newCode = `function bubble() {
  const arr = new Array(100).fill(1).map((t, i) => '张三'+i);
  for (let i = 0; i < arr.length; i++) {
    console.log('round:'+i);
    for (let j = i + 1; j < arr.length; j++) {
      if (arr[i] > arr[j]) {
        const t = arr[i];
        arr[i] = arr[j];
        arr[j] = t;
      }
    }
  }
}`;

function App() {
  const diffDOM = useRef<HTMLDivElement>(null);
  const editorRef = useRef<monaco.editor.IStandaloneDiffEditor>(null);

  useEffect(() => {
    editorRef.current = monaco.editor.createDiffEditor(diffDOM.current!, {
      diffCodeLens: true,
      readOnly: true,
      automaticLayout: true,
    });

    const originalModel = monaco.editor.createModel(oldCode, "text/plain");
    const modifiedModel = monaco.editor.createModel(newCode, "text/plain");

    editorRef.current.setModel({
      original: originalModel,
      modified: modifiedModel,
    });

    return () => {
      editorRef.current?.dispose();
    };
  }, []);

  return (
    <div style={{ padding: 32 }}>
      <div ref={diffDOM} style={{ height: 400 }}></div>
    </div>
  );
}

export default App;
代码语言:javascript
复制
参考

  • https://vitejs.dev/guide/
    • Vite 的脚手架
  • https://microsoft.github.io/monaco-editor/
    • https://github.com/microsoft/monaco-editor/blob/main/docs/integrate-esm.md#using-vite
    • https://github.com/microsoft/monaco-editor
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-11-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 WebJ2EE 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • MonacoEditor是什么?
  • MonacoEditor用来做代码比对
  • 在Vite-React环境下接入DiffEditor
    • 创建应用
      • 安装MonacoEditor
        • 使用MonacoEditor
          • 配置WebWorkers
          • 准备渲染容器
          • 创建DiffEditor
          • 及时销毁
          • 运行效果
          • 完整代码
      相关产品与服务
      容器服务
      腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档