e-chan1007 / nuxt-monaco-editor

Integrate monaco-editor with Nuxt
https://e-chan1007.github.io/nuxt-monaco-editor
MIT License
119 stars 16 forks source link

Nuxt 3.9.0 - Shadow DOM issues? #46

Closed L422Y closed 9 months ago

L422Y commented 10 months ago

Fresh install of Nuxt 3.9.0 and nuxt-monaco-editor fails when trying to access the shadow root - stepped through and domNode is null..

Cannot read properties of undefined (reading 'parentNode')

at getShadowRoot (.../_nuxt/node_modules/monaco-editor/esm/vs/base/browser/dom.js?v=2a224e56:520:20)
at Module.isInShadowDOM (.../_nuxt/node_modules/monaco-editor/esm/vs/base/browser/dom.js?v=2a224e56:516:14)
at StandaloneThemeService.registerEditorContainer (.../_nuxt/node_modules/monaco-editor/esm/vs/editor/standalone/browser/standaloneThemeService.js?v=2a224e56:207:17)
at new StandaloneEditor (.../_nuxt/node_modules/monaco-editor/esm/vs/editor/standalone/browser/standaloneCodeEditor.js?v=2a224e56:174:51)
at InstantiationService._createInstance (.../_nuxt/node_modules/monaco-editor/esm/vs/platform/instantiation/common/instantiationService.js?v=2a224e56:97:24)
at InstantiationService.createInstance (.../_nuxt/node_modules/monaco-editor/esm/vs/platform/instantiation/common/instantiationService.js?v=2a224e56:68:27)
at Object.create (.../_nuxt/node_modules/monaco-editor/esm/vs/editor/standalone/browser/standaloneEditor.js?v=2a224e56:44:33)
at .../_nuxt/node_modules/nuxt-monaco-editor/dist/runtime/MonacoEditor.client.js:48:30
at .../_nuxt/node_modules/.cache/vite/client/deps/vue.js?v=475a85ca:4295:88
at callWithErrorHandling (.../_nuxt/node_modules/.cache/vite/client/deps/vue.js?v=475a85ca:1666:18)

Minimal Reproduction

https://stackblitz.com/edit/github-wsgmqi?file=nuxt.config.ts,package.json,app.vue

physics515 commented 10 months ago

I'm running into the same issue after upgrading.

yjl9903 commented 10 months ago

My workaround is to wrap the onMounted body in the setTimeout. Since I do not know why the editorElement ref is undefined while onMounted, maybe issues upstream?

https://github.com/e-chan1007/nuxt-monaco-editor/blob/9954c708debb5f57d53837caa2ca27c29c56ad1e/src/runtime/MonacoEditor.client.vue#L73-L83

onMounted(() => {
  setTimeout(() => {
    // original code here
  })
})
jontybrook commented 10 months ago

Ditto this. The above workaround worked for me too. Can this fix be merged to main?

jandobrx commented 10 months ago

Having the same issue is the setTimeout the only solution found sofar?

jandobrx commented 10 months ago

Also good to note you need to make the same change to the diff editor if using!!!

7836246 commented 10 months ago

有没有更好的解决方案 Is there a better solution?

johnkomarnicki commented 10 months ago

Having the same issue. Any additional recommendations?

jontybrook commented 9 months ago

I've just hacked together a fix for this on a fork. I updated deps from this module and wrapped the onMounted in nextTick. This has fixed the issue for me.

Anyone else wanting to use my patched version can do so by sourcing the module from my fork like this:

 "dependencies": {
    "monaco-editor": "^0.45.0",
    "nuxt-monaco-editor": "git+https://github.com/jontybrook/nuxt-monaco-editor.git#patch1",
  },
L422Y commented 9 months ago

I created my own CustomMonacoEditor.client.vue which uses a watch to make sure the element is ready, since there's no actual guarantee that elements are there on mount or with setTimeout/nextTick

<template>
    <div v-show="!isLoading" ref="editorElement" class="editor"/>
</template>
<script lang="ts" setup>
import type * as Monaco from "monaco-editor"
import { computed, ref, shallowRef, watch } from "vue"
import { defu } from "defu"

interface Props {
    /**
     * Programming Language (Not a locale for UI);
     * overrides `options.language`
     */
    lang?: string;
    /**
     * Options passed to the second argument of `monaco.editor.create`
     */
    options?: Monaco.editor.IStandaloneEditorConstructionOptions;
    modelValue?: string;
}

interface Emits {
    (event: "update:modelValue", value: string): void

    (event: "load", editor: Monaco.editor.IStandaloneCodeEditor): void
}

const props = withDefaults(defineProps<Props>(), {
    lang: () => "plaintext",
    options: () => ( {} ),
    modelValue: () => ""
})

const emit = defineEmits<Emits>()
const isLoading = ref(true)
const lang = computed(() => props.lang || props.options.language)
const editorRef = shallowRef<Monaco.editor.IStandaloneCodeEditor>()
const editorElement = ref<HTMLDivElement>()
const monaco = useMonaco()!
const defaultOptions: Monaco.editor.IStandaloneEditorConstructionOptions = {
    automaticLayout: true
}

let editor: Monaco.editor.IStandaloneCodeEditor
let model: Monaco.editor.ITextModel

watch(() => props.modelValue, () => {
    if (editor?.getValue() !== props.modelValue) {
        editor?.setValue(props.modelValue)
    }
})

watch(() => props.lang, () => {
    if (model) {
        model.dispose()
    }
    model = monaco.editor.createModel(props.modelValue, lang.value)
    editor?.setModel(model)
})

watch(() => props.options, () => {
    editor?.updateOptions(defu(props.options, defaultOptions))
})

watch(editorElement, (newValue, oldValue) => {
    if (!editorElement.value || oldValue) return
    editor = monaco.editor.create(editorElement.value!, defu(props.options, defaultOptions))
    model = monaco.editor.createModel(props.modelValue, lang.value)
    editorRef.value = editor
    editor.layout()
    editor.setModel(model)
    editor.onDidChangeModelContent(() => {
        emit("update:modelValue", editor.getValue())
    })
    isLoading.value = false
    emit("load", editor)
})

defineExpose({
    /**
     * Monaco editor instance
     */
    $editor: editorRef
})

onBeforeUnmount(() => {
    editor?.dispose()
    model?.dispose()
})
</script>
Sun-ZhenXing commented 9 months ago

@e-chan1007, please merge it to fix this issus. Thanks!