最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 在 Vue3 项目中集成 VSCode - 实现 Vite + Vue3 + MonacoEdit

    正文概述 掘金(她的哥)   2021-02-26   2193

    概述

    MonacoEdit 是微软提供的在线编辑器库,vscode 就是基于这个实现,现在实现将 MonacoEdit 集成到 vue3 项目中

    方案采用 vite + vue3

    实现方法

    首先初始化一个 vue3 项目

    npm init @vitejs/app editor-proj --template vue
    

    创建完得到一个如下目录结构的项目

    editor-proj
    ├─ public
    │  └─ favicon.ico
    ├─ src
    │  ├─ assets
    │  │  └─ logo.png
    │  ├─ components
    │  │  └─ HelloWorld.vue
    │  ├─ App.vue
    │  └─ main.js
    ├─ index.html
    ├─ package.json
    └─ vite.config.js
    

    接下来安装 monaco-editor 依赖

    yarn add monaco-editor
    

    实现一个 json 编辑器组件并在 App.vue 中引用,最终目录结构如下

    editor-proj
    ├─ public
    │  └─ favicon.ico
    ├─ src
    │  ├─ assets
    │  │  └─ logo.png
    │  ├─ components
    │  │  └─ JsonEditor.vue
    │  ├─ App.vue
    │  └─ main.js
    ├─ index.html
    ├─ package.json
    ├─ vite.config.js
    └─ yarn.lock
    

    其中 JsonEditor.vue 的实现如下

    <template>
      <div class="editor" ref="dom"></div>
    </template>
    
    <script setup>
    import { onMounted, defineProps, defineEmit, ref } from 'vue';
    import * as monaco from 'monaco-editor';
    
    const props = defineProps({
      modelValue: String,
    });
    
    const emit = defineEmit(['update:modelValue']);
    
    const dom = ref();
    
    let instance;
    
    onMounted(() => {
      const jsonModel = monaco.editor.createModel(
        props.modelValue,
        'json',
        monaco.Uri.parse('json://grid/settings.json')
      );
    
      instance = monaco.editor.create(dom.value, {
        model: jsonModel,
        tabSize: 2,
        automaticLayout: true,
        scrollBeyondLastLine: false,
      });
    
      instance.onDidChangeModelContent(() => {
        const value = instance.getValue();
        emit('update:modelValue', value);
      });
    });
    </script>
    
    <style scoped>
    .editor {
      height: 100%;
    }
    </style>
    

    App.vue 的引用方法如下

    <template>
      <div class="container">
        <JsonEditor v-model="code"></JsonEditor>
      </div>
    </template>
    
    <script setup>
    import { ref } from 'vue';
    import JsonEditor from './components/JsonEditor.vue';
    
    const code = ref('');
    </script>
    
    <style scoped>
    #app {
      font-family: Avenir, Helvetica, Arial, sans-serif;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      color: #2c3e50;
    }
    
    .container {
      position: fixed;
      height: 100%;
      width: 100%;
    }
    </style>
    

    这时候运行项目 yarn run dev 已经可以看到编辑器效果

    但是存在一些问题,输入的 json 数据没法格式化,而且浏览器报错

    Error: Unexpected usage
        at EditorSimpleWorker.loadForeignModule (editorSimpleWorker.js:454)
        at webWorker.js:38
    

    这是由于 monaco-editor 的实现是基于 Web Worker 实现的,编辑器对语法的处理是通过开启 Worker 异步处理来提高效率,这时候还没有加载任何用来处理语法的 Worker

    问题以及解决方案可以参考 github.com/vitejs/vite…

    monaco-editor 会去获取全局变量里的 MonacoEnvironment 对象并执行 getWorker getWorkerUrl 来实现加载对应的语法处理

    json 数据的语法处理,修改 JsonEditor.vue 文件,加入如下实现

    import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
    import JsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker';
    
    self.MonacoEnvironment = {
      getWorker(workerId, label) {
        if (label === 'json') {
          return new JsonWorker();
        }
        return new EditorWorker();
      },
    };
    

    最终 JsonEditor.vue 的实现修改如下

    <template>
      <div class="editor" ref="dom"></div>
    </template>
    
    <script setup>
    import { onMounted, defineProps, defineEmit, ref } from 'vue';
    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';
    
    self.MonacoEnvironment = {
      getWorker(workerId, label) {
        if (label === 'json') {
          return new JsonWorker();
        }
        return new EditorWorker();
      },
    };
    
    const props = defineProps({
      modelValue: String,
    });
    
    const emit = defineEmit(['update:modelValue']);
    
    const dom = ref();
    
    let instance;
    
    onMounted(() => {
      const jsonModel = monaco.editor.createModel(props.modelValue, 'json');
    
      instance = monaco.editor.create(dom.value, {
        model: jsonModel,
        tabSize: 2,
        automaticLayout: true,
        scrollBeyondLastLine: false,
      });
    
      instance.onDidChangeModelContent(() => {
        const value = instance.getValue();
        emit('update:modelValue', value);
      });
    });
    </script>
    
    <style scoped>
    .editor {
      height: 100%;
    }
    </style>
    

    再次运行项目时发现已经可以正常处理 json 数据,包括快捷键格式化都正常运行

    在 Vue3 项目中集成 VSCode - 实现 Vite + Vue3 + MonacoEdit

    如果想支持更多的语法只要引用相应 Worker

    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';
    

    填坑

    项目在开发时可以运行,但是构建发布之后发现又出现异常

    Uncaught ReferenceError: window is not defined
        at editor.worker.bfe8d272.js:1
    Error: Unexpected usage
        at xm.loadForeignModule (editor.worker.bfe8d272.js:1)
        at editor.worker.bfe8d272.js:1
    

    之前提到过,编辑器使用了 webworker 而在 webworker 里无法获取 window 和 document 对象,分析可能是打包的时候将功能独立的代码打包到一起了,现在没时间去研究如何解决,给出一个折中的解决方案

    使用 @monaco-editor/loader 这个包,这个包的作用是直接加载 monaco-editor 相关库的 cdn 或远程版本,修改构建和实现如下

    vite.config.js 里复制编辑器的 min 版本到输出目录

    import { defineConfig } from 'vite'
    import vue from '@vitejs/plugin-vue'
    import jsx from '@vitejs/plugin-vue-jsx'
    import copy from 'rollup-plugin-copy'
    
    export default defineConfig({
      build: {
        rollupOptions: {
          plugins: [
            copy({
              targets: [
                {
                  src: 'node_modules/monaco-editor/min/vs/**/*',
                  dest: 'dist/assets/monaco-editor/vs',
                },
              ],
              hook: 'writeBundle',
            }),
          ],
        },
      },
      plugins: [vue(), jsx()],
    })
    

    JsonEditor 的实现里使用 @monaco-editor/loader 加载编辑器,加载的路径就是前面设置的输出目录

    <template>
      <div class="editor" ref="dom"></div>
    </template>
    
    <script setup>
    import { onMounted, defineProps, defineEmit, ref } from 'vue';
    import { editor } from 'monaco-editor';
    import loader from '@monaco-editor/loader'
    
    if (import.meta.env.PROD) {
      // 从静态资源加载编辑器
      loader.config({ paths: { vs: '/assets/monaco-editor/vs' } })
    }
    
    const props = defineProps({
      modelValue: String,
    });
    
    const emit = defineEmit(['update:modelValue']);
    
    const dom = ref();
    
    let instance: editor.IStandaloneCodeEditor;
    
    onMounted(async () => {
      const monaco = await loader.init()
    
      instance = monaco.editor.create(dom.value, {
        model: monaco.editor.createModel(props.modelValue, 'json'),
        tabSize: 2,
        automaticLayout: true,
        scrollBeyondLastLine: false,
      })
    
      instance?.onDidChangeModelContent(() => {
        ctx.emit('update:modelValue', instance?.getValue())
      })
    
    });
    </script>
    
    <style scoped>
    .editor {
      height: 100%;
    }
    </style>
    

    在本地调试时候 @monaco-editor/loader 会加载 cdn 的资源,编译之后加载的是本地资源


    起源地下载网 » 在 Vue3 项目中集成 VSCode - 实现 Vite + Vue3 + MonacoEdit

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元