Vue.js Components im WordPress Block Editor / Gutenberg anzeigen

Gutenberg basiert ja (leider) auf React. Ich programmiere aber schon seit Jahren viel lieber mit Vue.js. Zwar habe ich mich damit abgefunden Blöcke für den Block Editor aka Gutenberg in React zu schreiben (wobei man nur sehr begrenzt eigentlich React verwendet, eher noch JSX), aber trotzdem verwende ich für einige Blöcke Vue.js. Im Fronend kein Problem, aber eine Vorschau im Block Editor angezeigt zu bekommen, inkl. Änderungen an den Attributen, war eine echte Herausforderung.

I.d.R. wird Vue.js für die Komponenten einmal beim Laden der Seite initialisiert:

new Vue({ el: document.querySelector('.vue'), })
Code-Sprache: CSS (css)

Wird aber, wie im Block Editor üblich, das HTML ständig ausgetauscht, muss auch ständig Vue neu initialisiert werden. Mein Problem: Ich weiß nicht genau wann! Jedes Mal, wenn die edit-Funktion des Blocks ausgeführt wird bedeutet dies massive Performanceprobleme.

Längere Zeit hatte ich deswegen Vuera im Einsatz um Vue in React zu nutzen. So richtig rund lief das aber bei mir nie. Vor allem nicht, wenn der Block serverseitig mit ServerSideRender im Editor gerendert wird. Hier gibt es keinen Hinweis, wann das Laden abgeschlossen worden ist und Vue neu initialisiert werden müsste.

Web Components to the rescue

Seit einigen Wochen habe ich Web Components für mich entdeckt. Dabei werden die Benutzerdefinierten Elemente = Custom Elements im window Interface registriert und immer, wenn der Browser ein definiertes Element erkennt, z.B. <vue-wrapper>, wird es initialisiert. Einmal registriert, muss ich mich also nicht darum kümmern, Vue.js zum richtigen Zeitpunkt erneut zu initialisieren.

Ich erstelle mir also ein einfaches Custom Element, das als einzige Aufgabe hat, beim Verbinden über den connectedCallback mit dem DOM, Vue für dieses Element el über this zu initialisieren.

import Vue from 'vue'; import MyComponent from './my-component'; Vue.component('my-component', MyComponent); // Component global registrieren class VueWrapper extends HTMLElement { connectedCallback() { new Vue({ el: this, }); } } window.customElements.define('vue-wrapper', VueWrapper );
Code-Sprache: JavaScript (javascript)

Im HTML muss ich dann nur noch meinen Vue Componen mit dem vue-wrapper umschließen:

<vue-wrapper> <my-component></my-component> </vue-wrapper>
Code-Sprache: HTML, XML (xml)

Immer wenn der Browser im DOM ein neues <vue-wrapper> Custom Element erkennt, wird er Vue für euch zuverlässig initialisieren.

Vue.js Component als Web Component

Ich bin sogar noch einen Schritt weiter gegangen und habe meinen Vue.js Component als Web Component bzw. Custom Element umgesetzt. Dafür gibt es aktuell zwei NPM Packages:

  • @vue/web-component-wrapper: Die offizielle Implementation von Vue.js, welche allerdings schon seit zwei Jahren (Stand Januar 2021) keine Liebe mehr abgekommen hat. Probleme gibt es hier bei Objekten und Arrays als Props.
  • vue-custom-element: Meine Empfehlung aktuell, vor allem wenn man Objekte oder Arrays als Props übergeben möchte. Bekommt mehr Liebe ab.

Sein Vue Component registriert man dann wie folgt:

import Vue from 'vue'; import vueCustomElement from 'vue-custom-element' import MyComponent from './my-component'; Vue.use(vueCustomElement); Vue.customElement('my-component', MyComponent);
Code-Sprache: JavaScript (javascript)

Jetzt benötigt man auch keinen Wrapper mehr, sondern kann das Custom Element direkt verwenden:

<my-component></my-component>
Code-Sprache: HTML, XML (xml)

Objekte & Arrays als Props

Möchte man Daten an seinen Component übergeben, ist das bei String, Number und Boolean kein Problem:

<my-component :status="true" :count="1" :text="My Component"></my-component>
Code-Sprache: HTML, XML (xml)

Nur Objekte und Parameter machen hier Probleme. Es wird empfohlen diese direkt über JavaScript zu übergeben:

document.querySelector('my-component').data = [ ... ];
Code-Sprache: JavaScript (javascript)

Schöner wäre aber wie bei Vue.js üblich:

<my-component :data="[ ... ]"></my-component>
Code-Sprache: HTML, XML (xml)

Damit es so funktioniert, muss man das Array/Objekt als JSON-String übergeben und im connectedCallback in ein echtes Array oder Objekt umwandeln:

import Vue from 'vue'; import vueCustomElement from 'vue-custom-element' import MyComponent from './my-component'; Vue.use(vueCustomElement); Vue.customElement('my-component', MyComponent, { connectedCallback() { this.data = this.hasAttribute(':data') ? JSON.parse(this.getAttribute(':data')) : undefined; } });
Code-Sprache: JavaScript (javascript)
Achtung

Ich konnte als Attribute nicht den selber Namen wie für den Prop verwenden. Deswegen habe ich als Attribute :data gewählt, als Prop data ohne : Das kommt der Vue-Syntax sehr nah.

In JSX wird aber kein : akzeptiert, hier könnte man stattdessen das Attribut mit data prefixen, z.B.

this.mydata = this.hasAttribute('data-mydata') ? JSON.parse(this.getAttribute('data-mydata') : undefined;
Code-Sprache: JavaScript (javascript)

Fazit

JavaScript über Custom Elements initialisieren funktioniert nicht nur für Vue.js, sondern grundsätzlich für viele JavaScript-Frameworks und andere Libraries überall wo man ein Element für die Initialisierung übergeben muss.

9 Reaktionen zu “Vue.js Components im WordPress Block Editor / Gutenberg anzeigen

Reposts

  • Torsten Landsiedel
  • The Developer Bot

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.