Browse Source

fix: 解决编辑器的问题

奔跑的面条 3 years ago
parent
commit
6da5c613de

+ 13 - 3
build/constant.ts

@@ -1,4 +1,7 @@
-export const OUTPUT_DIR = 'dist';
+export const OUTPUT_DIR = 'dist'
+
+// monaco-editor 路径
+export const prefix = `monaco-editor/esm/vs`
 
 // chunk 警告大小
 export const chunkSizeWarningLimit = 2000
@@ -11,7 +14,14 @@ export const rollupOptions = {
   output: {
     chunkFileNames: 'static/js/[name]-[hash].js',
     entryFileNames: 'static/js/[name]-[hash].js',
-    assetFileNames: 'static/[ext]/[name]-[hash].[ext]'
+    assetFileNames: 'static/[ext]/[name]-[hash].[ext]',
+    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`]
+    }
   }
 }
 
@@ -22,4 +32,4 @@ export const terserOptions = {
     drop_console: true,
     drop_debugger: true
   }
-}
+}

+ 1 - 0
package.json

@@ -64,6 +64,7 @@
     "vite-plugin-compression": "^0.5.1",
     "vite-plugin-importer": "^0.2.5",
     "vite-plugin-mock": "^2.9.6",
+    "vite-plugin-monaco-editor": "^1.1.0",
     "vue-echarts": "^6.0.2",
     "vue-tsc": "^0.28.10"
   }

+ 10 - 0
pnpm-lock.yaml

@@ -47,6 +47,7 @@ specifiers:
   vite-plugin-compression: ^0.5.1
   vite-plugin-importer: ^0.2.5
   vite-plugin-mock: ^2.9.6
+  vite-plugin-monaco-editor: ^1.1.0
   vue: ^3.2.31
   vue-demi: ^0.13.1
   vue-echarts: ^6.0.2
@@ -113,6 +114,7 @@ devDependencies:
   vite-plugin-compression: 0.5.1_vite@2.9.5
   vite-plugin-importer: 0.2.5
   vite-plugin-mock: 2.9.6_mockjs@1.1.0+vite@2.9.5
+  vite-plugin-monaco-editor: 1.1.0_monaco-editor@0.33.0
   vue-echarts: 6.0.3_echarts@5.3.3+vue@3.2.37
   vue-tsc: 0.28.10_typescript@4.7.3
 
@@ -5111,6 +5113,14 @@ packages:
       - supports-color
     dev: true
 
+  /vite-plugin-monaco-editor/1.1.0_monaco-editor@0.33.0:
+    resolution: {integrity: sha512-IvtUqZotrRoVqwT0PBBDIZPNraya3BxN/bfcNfnxZ5rkJiGcNtO5eAOWWSgT7zullIAEqQwxMU83yL9J5k7gww==}
+    peerDependencies:
+      monaco-editor: '>=0.33.0'
+    dependencies:
+      monaco-editor: 0.33.0
+    dev: true
+
   /vite/2.9.5_sass@1.52.3:
     resolution: {integrity: sha512-dvMN64X2YEQgSXF1lYabKXw3BbN6e+BL67+P3Vy4MacnY+UzT1AfkHiioFSi9+uiDUiaDy7Ax/LQqivk6orilg==}
     engines: {node: '>=12.2.0'}

+ 68 - 31
src/components/Pages/MonacoEditor/index.hook.ts

@@ -1,46 +1,83 @@
+import { ref, onBeforeUnmount, nextTick } from 'vue'
 import * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js'
+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'
 
-export const useMonacoEditor = (language = 'json') => {
+export const useMonacoEditor = (language = 'javascript') => {
   let monacoEditor: monaco.editor.IStandaloneCodeEditor | null = null
   let initReadOnly = false
-  const updateVal = async (val: string) => {
-    monacoEditor?.setValue(val)
-    setTimeout(async () => {
+  const el = ref<HTMLElement | null>(null)
+  
+  // @ts-ignore
+  self.MonacoEnvironment = {
+    getWorker(_: any, label: string) {
+      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 onFormatDoc = async () => {
+    await monacoEditor?.getAction('monacoEditor.action.formatDocument')?.run()
+  }
+
+  // 更新
+  const updateVal = (val: string) => {
+    nextTick(async () => {
+      monacoEditor?.setValue(val)
       initReadOnly && monacoEditor?.updateOptions({ readOnly: false })
-      // await monacoEditor?.getAction('editor.action.formatDocument')?.run()
+      await onFormatDoc()
       initReadOnly && monacoEditor?.updateOptions({ readOnly: true })
-    }, 100)
+    })
   }
 
-  const createEditor = (
-    el: HTMLElement | null,
-    editorOption: monaco.editor.IStandaloneEditorConstructionOptions = {}
-  ) => {
-    if (monacoEditor) {
-      return
-    }
+  // 创建实例
+  const createEditor = (editorOption: monaco.editor.IStandaloneEditorConstructionOptions = {}) => {
+    if (!el.value) return
+    const javascriptModel = monaco.editor.createModel('', language)
     initReadOnly = !!editorOption.readOnly
-    monacoEditor =
-      el &&
-      monaco.editor.create(el, {
-        language,
-        minimap: { enabled: false },
-        theme: 'vs-dark',
-        multiCursorModifier: 'ctrlCmd',
-        scrollbar: {
-          verticalScrollbarSize: 8,
-          horizontalScrollbarSize: 8
-        },
-        tabSize: 2,
-        automaticLayout: true, // 自适应宽高
-        ...editorOption
-      })
+    // 创建
+    monacoEditor = monaco.editor.create(el.value, {
+      model: javascriptModel,
+      minimap: { enabled: true },
+      roundedSelection: false,
+      theme: 'vs-dark',
+      multiCursorModifier: 'ctrlCmd',
+      scrollbar: {
+        verticalScrollbarSize: 8,
+        horizontalScrollbarSize: 8
+      },
+      tabSize: 2,
+      fontSize: 16, //字体大小
+      autoIndent: 'advanced', //自动布局
+      automaticLayout: true, // 自适应宽高
+      ...editorOption
+    })
+
     return monacoEditor
   }
-  const onFormatDoc = () => {
-    monacoEditor?.getAction('editor.action.formatDocument').run()
-  }
+
+  // 卸载
+  onBeforeUnmount(() => {
+    if (monacoEditor) monacoEditor.dispose()
+  })
+
   return {
+    el,
     updateVal,
     getEditor: () => monacoEditor,
     createEditor,

+ 52 - 62
src/components/Pages/MonacoEditor/index.vue

@@ -1,75 +1,65 @@
 <template>
-  <div class="editor-area" :style="{ width, height }">
-  </div>
+  <div ref="el" class="editor-area" :style="{ width, height }"></div>
 </template>
 
-<script lang='ts'>
-import { defineComponent, ref } from 'vue'
+<script lang="ts" setup>
+import { onMounted, watch, PropType } from 'vue'
 import { useMonacoEditor } from './index.hook'
 
-export default defineComponent({
-  props: {
-    width: {
-      type: String,
-      default: '100%'
-    },
-    height: {
-      type: String,
-      default: '90vh'
-    },
-    language: {
-      type: String,
-      default: 'json'
-    },
-    preComment: {
-      type: String,
-      default: ''
-    },
-    modelValue: {
-      type: String,
-      default: ''
-    },
-    editorOptions: {
-      type: Object,
-      default: () => ({})
-    },
+const props = defineProps({
+  width: {
+    type: String as PropType<string>,
+    default: '100%'
   },
-  watch: {
-    modelValue(val) {
-      val !== this.getEditor()?.getValue() && this.updateMonacoVal(val)
-    }
+  height: {
+    type: String as PropType<string>,
+    default: '90vh'
   },
-  setup(props) {
-    const { updateVal, getEditor, createEditor, onFormatDoc } = useMonacoEditor(props.language)
-    const isFull = ref(false)
-    return {
-      isFull,
-      updateVal,
-      getEditor,
-      createEditor,
-      onFormatDoc
-    }
+  language: {
+    type: String as PropType<string>,
+    default: 'javascript'
   },
-  methods: {
-    updateMonacoVal(_val?: string) {
-      const { modelValue, preComment } = this.$props
-      const val = preComment ? `${preComment}\n${_val || modelValue}` : (_val || modelValue)
-      this.updateVal(val)
-    }
+  preComment: {
+    type: String as PropType<string>,
+    default: ''
   },
-  mounted() {
-    if (this.$el) {
-      const monacoEditor = this.createEditor(this.$el, this.$props.editorOptions)
-      this.updateMonacoVal()
-      monacoEditor!.onDidChangeModelContent(() => {
-        this.$emit('update:modelValue', monacoEditor!.getValue())
-      })
-      monacoEditor!.onDidBlurEditorText(() => {
-        this.$emit('blur')
-      })
-    }
+  modelValue: {
+    type: String as PropType<string>,
+    default: ''
+  },
+  editorOptions: {
+    type: Object as PropType<object>,
+    default: () => ({})
   }
 })
+
+const emits = defineEmits(['blur', 'update:modelValue'])
+
+const { el, updateVal, getEditor, createEditor } = useMonacoEditor(props.language)
+
+const updateMonacoVal = (_val?: string) => {
+  const { modelValue, preComment } = props
+  const val = preComment ? `${preComment}\n${_val || modelValue}` : _val || modelValue
+  updateVal(val)
+}
+
+onMounted(() => {
+  const monacoEditor = createEditor(props.editorOptions)
+  monacoEditor!.onDidChangeModelContent(() => {
+    emits('update:modelValue', monacoEditor!.getValue())
+  })
+  monacoEditor!.onDidBlurEditorText(() => {
+    emits('blur')
+  })
+  updateMonacoVal()
+})
+
+watch(
+  () => props.modelValue,
+  (val: string) => {
+    val !== getEditor()?.getValue() && updateMonacoVal(val)
+  }
+)
 </script>
 
 <style lang="scss" scoped>
@@ -81,4 +71,4 @@ export default defineComponent({
   padding-left: 0;
   box-sizing: border-box;
 }
-</style>
+</style>

+ 5 - 6
src/views/chart/ContentConfigurations/components/ChartData/components/ChartDataMonacoEditor/index.vue

@@ -56,9 +56,11 @@
           <div>
             <n-space vertical>
               <n-text depth="3">// 数据参数 => data </n-text>
-              <p><span class="func-keyword">function</span>&nbsp;&nbsp;filter(data)&nbsp;&nbsp;{</p>
-              <monaco-editor width="460px" height="380px" v-model:modelValue="filter" language="json" />
-              <p>}</p>
+              <n-tag type="info">
+                <span class="func-keyword">function</span>&nbsp;&nbsp;filter(data)&nbsp;&nbsp;{
+              </n-tag>
+              <monaco-editor v-model:modelValue="filter" width="460px" height="380px" language="javascript" />
+              <n-tag type="info">}</n-tag>
             </n-space>
           </div>
           <n-divider vertical style="height: 480px" />
@@ -171,9 +173,6 @@ const saveFilter = () => {
   targetData.value.filter = filter.value
   closeFilter()
 }
-
-// 执行过滤处理
-const filterData = (data: any) => {}
 </script>
 
 <style lang="scss" scoped>

+ 9 - 5
vite.config.ts

@@ -3,7 +3,8 @@ import vue from '@vitejs/plugin-vue'
 import { resolve } from 'path'
 import { OUTPUT_DIR, brotliSize, chunkSizeWarningLimit, terserOptions, rollupOptions } from './build/constant'
 import viteCompression from 'vite-plugin-compression'
-import { viteMockServe} from "vite-plugin-mock";
+import { viteMockServe } from 'vite-plugin-mock'
+import monacoEditorPlugin from 'vite-plugin-monaco-editor'
 
 function pathResolve(dir: string) {
   return resolve(process.cwd(), '.', dir)
@@ -36,17 +37,20 @@ export default defineConfig({
   },
   plugins: [
     vue(),
+    monacoEditorPlugin({
+      languageWorkers: ['editorWorkerService', 'typescript', 'json']
+    }),
     viteMockServe({
-			mockPath: "/src/api/mock",
+      mockPath: '/src/api/mock',
       // 开发打包开关
-			localEnabled: true,
+      localEnabled: true,
       // 生产打包开关
       prodEnabled: true,
       // 打开后,可以读取 ts 文件模块。 请注意,打开后将无法监视.js 文件
       supportTs: true,
       // 监视文件更改
-      watchFiles: true,
-		}),
+      watchFiles: true
+    }),
     // 压缩
     viteCompression({
       verbose: true,