An overview of the
MonacoEdit is an online editor library provided by Microsoft, and vscode is based on this implementation, which now integrates MonacoEdit into the vue3 project
The solution is vite + VUe3
Implementation method
Start by initializing a VUe3 project
npm init @vitejs/app editor-proj --template vue
Copy the code
Create a project with the following directory structure
Editor - proj ├ ─ public │ └ ─ the favicon. Ico ├ ─ SRC │ ├ ─ assets │ │ └ ─ logo. The PNG │ ├ ─ components │ │ └ ─ the HelloWorld. Vue │ ├ ─ ├─ download.txt ├─ download.txt ├─ download.txtCopy the code
Next, install the Monaco-Editor dependency
yarn add monaco-editor
Copy the code
Implement a JSON editor component and reference it in app.vue, with the final directory structure as follows
Editor - proj ├ ─ public │ └ ─ the favicon. Ico ├ ─ SRC │ ├ ─ assets │ │ └ ─ logo. The PNG │ ├ ─ components │ │ └ ─ JsonEditor. Vue │ ├ ─ App.vue │ ├─ ├─ download.txt ├─ download.txt ├─ download.txt ├─ download.txtCopy the code
The implementation of jsonEditor. vue is as follows
<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>
Copy the code
App.vue is referenced as follows
<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>
Copy the code
Run the yarn Run Dev project to see the editor effect
However, there were some problems. The input JSON data could not be formatted, and the browser reported an error
Error: Unexpected usage
at EditorSimpleWorker.loadForeignModule (editorSimpleWorker.js:454)
at webWorker.js:38
Copy the code
This is because the monaco-Editor implementation is based on the Web Worker, and the editor’s processing of the grammar is improved by enabling the asynchronous processing of the Worker. At this time, no Worker for processing the grammar has been loaded
Problems and solutions can be found at github.com/vitejs/vite…
The Monaco-Editor will fetch the MonacoEnvironment object in the global variable and execute getWorker getWorkerUrl to load the corresponding syntax processing
Json data syntax processing, modify jsoneditor. vue file, add the following implementation
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 newEditorWorker(); }};Copy the code
The final implementation of jsonEditor.vue is modified as follows
<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>
Copy the code
When I run the project again, I find that THE JSON data is working properly, including the shortcut key formatting
If you want to support more syntax, just reference the corresponding 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';
Copy the code
Fill in the pit
The project was running at development time, but after the build was released, an exception was found
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
Copy the code
As mentioned before, the editor uses webworker and cannot obtain window and Document objects from Webworker. Analysis may be that the function-independent code is packaged together during packaging so that the modules loaded separately are put into Webworker and run away
Vite packaging is implemented based on rollup, where the manual sharding option of Rollup can be used to separately package worker-related items to solve this problem
The final implementation in vite. Config. js is as follows
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import jsx from '@vitejs/plugin-vue-jsx';
const prefix = `monaco-editor/esm/vs`;
export default defineConfig({
base: '/'.build: {
rollupOptions: {
output: {
manualChunks: {
jsonWorker: [`${prefix}/language/json/json.worker`].cssWorker: [`${prefix}/language/css/css.worker`].htmlWorker: [`${prefix}/language/html/html.worker`].tsWorker: [`${prefix}/language/typescript/ts.worker`].editorWorker: [`${prefix}/editor/editor.worker`],},},},},plugins: [vue(), jsx()],
});
Copy the code