From ff04353b3ee0e6fc63733a673e2b27d2272a3355 Mon Sep 17 00:00:00 2001 From: Nick the Sick Date: Mon, 15 Jul 2024 12:32:42 +0200 Subject: [PATCH] revert: "fix(vue-3): faster component rendering (#5206)" This reverts commit 31f37464912b7b21f3a565ca63222b9f5b6cce00. --- packages/vue-3/src/Editor.ts | 8 ++-- packages/vue-3/src/EditorContent.ts | 38 ++++++++++++------ packages/vue-3/src/VueNodeViewRenderer.ts | 10 ++--- packages/vue-3/src/VueRenderer.ts | 49 ++++++++--------------- 4 files changed, 51 insertions(+), 54 deletions(-) diff --git a/packages/vue-3/src/Editor.ts b/packages/vue-3/src/Editor.ts index 691eec2ffa9..0933a79924c 100644 --- a/packages/vue-3/src/Editor.ts +++ b/packages/vue-3/src/Editor.ts @@ -1,14 +1,16 @@ import { Editor as CoreEditor, EditorOptions } from '@tiptap/core' import { EditorState, Plugin, PluginKey } from '@tiptap/pm/state' import { - AppContext, ComponentInternalInstance, ComponentPublicInstance, customRef, markRaw, + reactive, Ref, } from 'vue' +import { VueRenderer } from './VueRenderer.js' + function useDebouncedRef(value: T) { return customRef((track, trigger) => { return { @@ -40,9 +42,9 @@ export class Editor extends CoreEditor { private reactiveExtensionStorage: Ref> - public contentComponent: ContentComponent | null = null + public vueRenderers = reactive>(new Map()) - public appContext: AppContext | null = null + public contentComponent: ContentComponent | null = null constructor(options: Partial = {}) { super(options) diff --git a/packages/vue-3/src/EditorContent.ts b/packages/vue-3/src/EditorContent.ts index 7c215c3c95f..09f1b51c426 100644 --- a/packages/vue-3/src/EditorContent.ts +++ b/packages/vue-3/src/EditorContent.ts @@ -1,4 +1,5 @@ import { + DefineComponent, defineComponent, getCurrentInstance, h, @@ -7,6 +8,7 @@ import { PropType, Ref, ref, + Teleport, unref, watchEffect, } from 'vue' @@ -43,17 +45,6 @@ export const EditorContent = defineComponent({ // @ts-ignore editor.contentComponent = instance.ctx._ - if (instance) { - editor.appContext = { - ...instance.appContext, - provides: { - // @ts-ignore - ...instance.provides, - ...instance.appContext.provides, - }, - } - } - editor.setOptions({ element, }) @@ -78,7 +69,6 @@ export const EditorContent = defineComponent({ } editor.contentComponent = null - editor.appContext = null if (!editor.options.element.firstChild) { return @@ -97,11 +87,35 @@ export const EditorContent = defineComponent({ }, render() { + const vueRenderers: any[] = [] + + if (this.editor) { + this.editor.vueRenderers.forEach(vueRenderer => { + const node = h( + Teleport, + { + to: vueRenderer.teleportElement, + key: vueRenderer.id, + }, + h( + vueRenderer.component as DefineComponent, + { + ref: vueRenderer.id, + ...vueRenderer.props, + }, + ), + ) + + vueRenderers.push(node) + }) + } + return h( 'div', { ref: (el: any) => { this.rootEl = el }, }, + ...vueRenderers, ) }, }) diff --git a/packages/vue-3/src/VueNodeViewRenderer.ts b/packages/vue-3/src/VueNodeViewRenderer.ts index 201e051e039..a9f9c448df9 100644 --- a/packages/vue-3/src/VueNodeViewRenderer.ts +++ b/packages/vue-3/src/VueNodeViewRenderer.ts @@ -124,7 +124,7 @@ class VueNodeView extends NodeView, } -type ExtendedVNode = ReturnType | null - -interface RenderedComponent { - vNode: ExtendedVNode - destroy: () => void - el: Element | null -} - /** * This class is used to render Vue components inside the editor. */ export class VueRenderer { id: string - renderedComponent!: RenderedComponent - editor: ExtendedEditor component: Component - el: Element | null + teleportElement: Element + + element: Element props: Record @@ -38,40 +28,35 @@ export class VueRenderer { this.id = Math.floor(Math.random() * 0xFFFFFFFF).toString() this.editor = editor as ExtendedEditor this.component = markRaw(component) - this.el = document.createElement('div') + this.teleportElement = document.createElement('div') + this.element = this.teleportElement this.props = reactive(props) - this.renderedComponent = this.renderComponent() - } - - get element(): Element | null { - return this.renderedComponent.el - } + this.editor.vueRenderers.set(this.id, this) - renderComponent() { - let vNode: ExtendedVNode = h(this.component as DefineComponent, this.props) + if (this.editor.contentComponent) { + this.editor.contentComponent.update() - if (typeof document !== 'undefined' && this.el) { render(vNode, this.el) } + if (this.teleportElement.children.length !== 1) { + throw Error('VueRenderer doesn’t support multiple child elements.') + } - const destroy = () => { - if (this.el) { render(null, this.el) } - this.el = null - vNode = null + this.element = this.teleportElement.firstElementChild as Element } + } - return { vNode, destroy, el: this.el ? this.el.firstElementChild : null } + get ref(): any { + return this.editor.contentComponent?.refs[this.id] } updateProps(props: Record = {}): void { - Object .entries(props) .forEach(([key, value]) => { this.props[key] = value }) - this.renderComponent() } destroy(): void { - this.renderedComponent.destroy() + this.editor.vueRenderers.delete(this.id) } }