imguolao / monaco-vue

Use monaco-editor loaded from CDN in Vue 2&3, no need to bundling.
https://imguolao.github.io/monaco-vue/
MIT License
211 stars 21 forks source link

how to add a custom language for this module? #55

Closed Nobilta closed 4 months ago

Nobilta commented 4 months ago

I use this module via CDN, but now I want to add a custom language, similar to what is described in the documentation at https://microsoft.github.io/monaco-editor/monarch.html. The registration method I usually find online is

monaco.languages.register({ id: 'mylang' });. 

How should I register a custom language in this module? Now I use Like: 我现在使用CDN的方式接入vue-monaco-editor,使用vue2+composition-api的方式接入,接入代码如下,现在我想加入一种自定义语言(NGINX)像 https://github.com/imguolao/monaco-vue/issues/39 一样,但我看都是使用

monaco.languages.register({ id: 'mylang' });.

的方式找到对象并注册语法,在我这种使用方式中应该如何向对象中注册新的语法呢?

import Vue from 'vue'
import VueCompositionAPI from '@vue/composition-api'
Vue.use(VueCompositionAPI)
import { createApp } from '@vue/composition-api';
import App from '../../../../App.vue'
import { install as VueMonacoEditorPlugin, loader } from '@guolao/vue-monaco-editor'
const app = createApp(App)
app.use(VueMonacoEditorPlugin)
loader.config({
  "vs/nls": {
    availableLanguages: {
      "*": "zh-cn",
    }
  },
  "paths": {
    vs: "http://localhost:8081/monaco-editor/min/vs"
  }
})
<vue-monaco-editor style="height: 250px;width: 100%;border-radius: 2px;border: 1px solid #d7dae2;"
                  v-model:value="test"/>
imguolao commented 4 months ago

Get the monaco instance to register a custom language in beforeMount event.

beforeMount 里拿到 monaco 实例注册就可以了。

onBeforeMount: (monaco: Monaco) => void
Nobilta commented 4 months ago

Get the monaco instance to register a custom language in beforeMount event.

beforeMount 里拿到 monaco 实例注册就可以了。

onBeforeMount: (monaco: Monaco) => void

我尝试了一下,但会提示找不到register方法:

beforeMount() {
    const monaco = this.$options.components.VueMonacoEditor;
    monaco.languages.register({
      id: 'nginx',
    });
    }

报错:Error in beforeMount hook: "TypeError: Cannot read properties of undefined (reading 'register')" 感觉像是并没有获取到monaco实例,想请教下应该如何解决呢?

imguolao commented 4 months ago
<template>
  <vue-monaco-editor @before-mount="handleBeforeMount" />
</template>

<script lang="ts" setup>
function handleBeforeMount(monaco) {
  // your action
}
</script>

文档里有写,可以看看。

Nobilta commented 4 months ago
<template>
  <vue-monaco-editor @before-mount="handleBeforeMount" />
</template>

<script lang="ts" setup>
function handleBeforeMount(monaco) {
  // your action
}
</script>

文档里有写,可以看看。

昨天仔细阅读了文档,写了个简单的demo尝试了几种写法,但似乎在我的代码中并不会触发BeforeMount事件,在方法中的console.log也不会被触发:

<vue-monaco-editor style="height: 500px;width: 100%;border-radius: 2px;border: 1px solid #d7dae2;"
          :onBeforeMount="BeforeMount" v-model:value="test" language="nginx" />

<vue-monaco-editor style="height: 500px;width: 100%;border-radius: 2px;border: 1px solid #d7dae2;"
          @before-mount="BeforeMount" v-model:value="test" language="nginx" />
export default {
   methods: {
    BeforeMount(monaco) {
      console.log("BeforeMount")
      monaco.languages.register({ id: 'nginx' });
      let keywords = [ 'class', 'new', 'string', 'number', 'boolean', 'private', 'public' ];
      monaco.languages.setMonarchTokensProvider('nginx', {
        keywords,
        tokenizer: {
          root: [
            [/@?[a-zA-Z][\w$]*/, {
              cases: {
                '@keywords': 'keyword',
                '@default': 'variable',
              }
            }],
            [/".*?"/, 'string'],
            [/\/\//, 'comment'],
          ]
        }
      });
    }
   }
}
imguolao commented 4 months ago

给一个最小复现例子或者 github repo?

这里是 vue@2.6 的 test case: https://github.com/imguolao/monaco-vue/blob/main/packages/vue-test-2.6.14/src/editor/EditorDemo.vue

或者用 UMD 例子也可以:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>UMD Example</title>
  <script src="https://unpkg.com/vue@3.3.7/dist/vue.global.js"></script>
  <script src="https://unpkg.com/vue-demi@0.14.6/lib/index.iife.js"></script>
  <script src="https://unpkg.com/@monaco-editor/loader@1.4.0/lib/umd/monaco-loader.js"></script>
  <script src="https://unpkg.com/@guolao/vue-monaco-editor@1.4.0/lib/umd/monaco-vue.js"></script>
  <style>
    html,
    body,
    #app {
      margin: 0;
      padding: 0;
      height: 100%;
    }
  </style>
</head>
<body>
  <div id="app">
    <!-- Will render here -->
  </div>
</body>

  <script>
    const { createApp, ref, shallowRef } = Vue
    const { VueMonacoEditor } = monaco_vue

    const app = createApp({
      components: {
        VueMonacoEditor,
      },

      template: `
        <vue-monaco-editor
          v-model:value="code"
          theme="vs-dark"
          :options="MONACO_EDITOR_OPTIONS"
          @mount="handleMount"
        />
      `,

      setup() {
        const MONACO_EDITOR_OPTIONS = {
          automaticLayout: true,
          formatOnType: true,
          formatOnPaste: true,
        }

        const code = ref('// some code...')
        const editorRef = shallowRef()
        const handleMount = editor => (editorRef.value = editor)

        return {
          MONACO_EDITOR_OPTIONS,
          code,
          editorRef,
          handleMount,
        }
      }
    })

    app.mount('#app')
</script>
</html>
Nobilta commented 4 months ago

给一个最小复现例子或者 github repo?

这里是 vue@2.6 的 test case: https://github.com/imguolao/monaco-vue/blob/main/packages/vue-test-2.6.14/src/editor/EditorDemo.vue

或者用 UMD 例子也可以:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>UMD Example</title>
  <script src="https://unpkg.com/vue@3.3.7/dist/vue.global.js"></script>
  <script src="https://unpkg.com/vue-demi@0.14.6/lib/index.iife.js"></script>
  <script src="https://unpkg.com/@monaco-editor/loader@1.4.0/lib/umd/monaco-loader.js"></script>
  <script src="https://unpkg.com/@guolao/vue-monaco-editor@1.4.0/lib/umd/monaco-vue.js"></script>
  <style>
    html,
    body,
    #app {
      margin: 0;
      padding: 0;
      height: 100%;
    }
  </style>
</head>
<body>
  <div id="app">
    <!-- Will render here -->
  </div>
</body>

  <script>
    const { createApp, ref, shallowRef } = Vue
    const { VueMonacoEditor } = monaco_vue

    const app = createApp({
      components: {
        VueMonacoEditor,
      },

      template: `
        <vue-monaco-editor
          v-model:value="code"
          theme="vs-dark"
          :options="MONACO_EDITOR_OPTIONS"
          @mount="handleMount"
        />
      `,

      setup() {
        const MONACO_EDITOR_OPTIONS = {
          automaticLayout: true,
          formatOnType: true,
          formatOnPaste: true,
        }

        const code = ref('// some code...')
        const editorRef = shallowRef()
        const handleMount = editor => (editorRef.value = editor)

        return {
          MONACO_EDITOR_OPTIONS,
          code,
          editorRef,
          handleMount,
        }
      }
    })

    app.mount('#app')
</script>
</html>

vue版本:2.6.14 vue/composition-api版本:1.7.2 guolao/vue-monaco-editor版本:1.5.1 现象是不会触发BeforeMount函数中的console函数,注册语言自然也就没效果了

<template>
    <vue-monaco-editor v-model:value="test" language="nginx" :onBeforeMount="BeforeMount" />
</template>

<script>
import Vue from 'vue'
import VueCompositionAPI from '@vue/composition-api'
Vue.use(VueCompositionAPI)
import { createApp } from '@vue/composition-api';
import App from '../../../../App.vue'
import { install as VueMonacoEditorPlugin, loader } from '@guolao/vue-monaco-editor'
const app = createApp(App)
app.use(VueMonacoEditorPlugin)
loader.config({
  "vs/nls": {
    availableLanguages: {
      "*": "zh-cn",
    }
  },
  "paths": {
    vs: "https://cdn.staticfile.org/monaco-editor/0.43.0/min/vs"
  }
})
export default {
  data() {
     test:""
   }
   methods: {
       BeforeMount(monaco) {
           console.log("mounted")
       }
   }
}
</script>
imguolao commented 4 months ago

复现出来了,确实有问题。

beforeMount 就可以,before-mount 不行,mount 也可以。

<template>
  <vue-monaco-editor
    @beforeMount="handleBeforeMount"
    @mount="handleMount"
  />
</template>

<script lang="ts">
export default {
  name: 'TestDemo',
  methods: {
    handleBeforeMount(monaco) {
      console.log(monaco)
    },
    handleMount(editor, monaco) {
      console.log(monaco)
    },
  },
}
</script>
imguolao commented 4 months ago

https://v2.vuejs.org/v2/guide/components-custom-events#Event-Names

vue2 和 vue3 存在不一致的处理,vue2 驼峰命名的事件无法使用短横线触发。

Nobilta commented 4 months ago

https://v2.vuejs.org/v2/guide/components-custom-events#Event-Names

vue2 和 vue3 存在不一致的处理,vue2 驼峰命名的事件无法使用短横线触发。

本地测试了下,直接使用@beforeMount确实没问题,非常感谢提供的技术支持!