Wie man Contentblöcke aus einem CMS in eine Vue-Anwendung integiert – ohne Ajax!

Die gängigen Translation Systeme für Single Page Applications (SPAs) sind nicht geeignet größere Contentblöcke für Redakteure einfach pflegbar und übersetzbar zu machen. Ihr Schwerpunkt liegt eher auf kleinen Strings und Labels. Vor kurzem haben wir in einem Projekt eine Möglichkeit gesucht, wie man größere Contentblöcke in eine SPA mit vue-router einbringt, die in Pimcore integiert ist.

Aufgrund des Aufbaus der SPA müssen diese Contentblöcke in Subrouten des Routers eingebaut werden. Die Inhalte per Ajax nachzuladen ist dabei zwar möglich, aber keine angenehme Wahl. Hier ist relativ viel Aufwand (Platzhalter, Loading-Anzeige, Errorhandling) nötig und es ist schwerer mit dem CMS von Pimcore koppelbar.

Die Lösung ist dabei eigentlich relativ einfach: Wir nutzen die Möglichkeiten des Pimcore Experience Managers, um größere Content-Blöcke backend-Seitig zu übersetzen.

Das Setup

Dazu muss man folgendes sicherstellen: Der Template-Compiler von Vue muss mit in das Bundle. Das ist er normalerweise nicht. Wenn man die Anwendung mit der vue-cli erstellt, wird eine Runtime ohne Template Compiler verwendet. Das kann geändert werden, erhöht die Bundle-Größe aber um ca. 10kB. Im Falle einer Anwendung, die mit der Vue CLI ab Version 3.0 gebaut wird geht das folgendermaßen:

// vue.config.js
module.exports = {
  runtimeCompiler: true
}

Für andere Build-Systeme oder Konfigurationen hat die Vue-Doku da noch ein paar Hinweise. Laravel Mix liefert den Compiler immer in der Runtime mit. Mit den 10kB können wir an der Stelle gut leben, unsere SPA hat wenig perfomancerelevanz und misst aktuell mit Template-Compiler ca. 60kB.

Was können wir damit nun anfangen?

Nach dem Setup haben wir nun Zugriff auf den Template Compiler, auch wenn die Vue-Anwendung schon gebundled ist. Damit kann man auch nachträglich Vues x-templates in die Anwendung laden und nutzen.

Also bauen wir uns eine Component, die nur ein x-template lädt und einbindet:

<script>
    export default {
        name: "HtmlInclude",
        props: {
            templateId: {
                type: String,
                required: true
            }
        },
        created() {
            this.$options.template = this.templateId
        }
    }
</script>

Das ganze wird folgendermaßen aufgerufen:

<HtmlInclude :template-id="'#mein-template'"></HtmlInclude>

In das HTML der app-aufrufenden Seite muss dann nur noch ein Template eingebettet werden, welches den Richtlinien von Vue-Componenten entspricht:

<script type="text/x-template" id="mein-template">
...
</script>

Wie sieht das ganze auf Seite des CMS aus?

In unserem Fall in Pimcore bieten wir dem Bearbeiter eine komplette Editorenmöglichkeit mit includes, wie er es gewohnt ist. Der entsprechende Contentblock wird beim Rendering der Page lediglich mit dem eben beschriebenenen x-template umschlossen; damit ist er unsichtbar, wenn er nicht aus der Vue-Anwendung geladen wird.

Wochenbericht 2018.36

  1. Hygen: The simple, fast, and scalable code generator that lives in your project
  2. Mit Generatoren wie Gatsby und Nuxt sucht die Contentverwaltung neue Wege: 10 Headless CMS’s Overview
  3. ​Linus Torvalds talks frankly about Intel security bugs: „[.] it’s still not fair that Linux has to fix hardware problems.“
  4. Front-end Developer Handbook 2018 (free pdf)
  5. Intro to Go for JavaScript developers

Was zum Lachen: Never Satisfied