Eine Headless Vue.js Anwendung entwickeln mit Magnolia
Bei der Entwicklung digitaler Erlebnisse in einer Headless-Architektur bietet Magnolia eine einzigartige Möglichkeit für Marketer, Seiten visuell in einem WYSIWYG-Editor zu gestalten, während Templates und Anwendungslogik von einem entkoppelten Frontend, wie z.B. einer SPA oder PWA, verwaltet werden.
Während es bereits möglich war, unseren visuellen Editor mit jedem beliebigen Frontend-Framework zu verwenden, war es ein größerer Aufwand, ihn mit etwas anderem als React und Angular zum Laufen zu bringen. Da Vue.js zu einem der beliebtesten JavaScript-Frameworks für die Entwicklung von Frontend-Anwendungen geworden ist, haben wir beschlossen, dass es an der Zeit ist, eine noch einfachere Möglichkeit zur Integration von Vue.js anzubieten.
In diesem Blog werde ich die Vue-Editor-Bibliothek vorstellen und zeigen, wie man eine Vue.js-Anwendung erstellt, die Seiten von Magnolia über die REST-API abruft.
Wann immer Sie Hilfe benötigen, können Sie sich auf meinen Code im Beispielprojekt beziehen.
Einrichten eines Front-End-Projekts
Bitte stellen Sie sicher, dass Sie NodeJS von https://nodejs.org installiert haben, bevor Sie fortfahren.
Sie werden das Vue CLI verwenden, um ein Vue-Projekt namens magnolia-vue-site zu erstellen. Installieren Sie es und wenn es nach der Vue-Version fragt, wählen Sie Vue 3.
npm install -g @vue/cli vue create magnolia-vue-site cd magnolia-vue-site
Installieren Sie dann @magnolia/vue-editor sowie rimraf und copyfiles, um den kompilierten Code in ein Magnolia Light Module zu kopieren.
npm install @magnolia/vue-editor npm install -D rimraf copyfiles
Nachdem Sie das Projekt erstellt haben, können Sie npm run serve verwenden, um den vom Vue CLI generierten Entwicklungsserver zu starten.
Konfigurieren des Vue-Server-Ports und der REST-URLs
Die Standard-Ports für den Magnolia- und den Vue-Server sind beide 8080, Sie müssen also einen der beiden Ports ändern.
Für dieses Tutorial setzen Sie den Vue-Port auf 3000 und konfigurieren die Parameter publicPath und lintOnSave
Erstellen Sie die vue.config.js im Stammverzeichnis magnolia-vue-site:
module.exports = { devServer: { port: 3000 }, publicPath: `${process.env.VUE_APP_MGNL_BASE}${process.env.VUE_APP_MGNL_STATIC}`, lintOnSave: false };
publicPath weist Vue an, diesen Pfad an Links in index.html anzuhängen, wenn die Datei erzeugt wird. Das Setzen von lintOnSave auf false bedeutet, dass ich nicht möchte, dass die Vue IDE-Erweiterung ESLint-Regeln überprüft, wenn ich eine Datei speichere.
Das obige Beispiel verwendet auch die Parameter VUE_APP_MGNL_BASE und VUE_APP_MGNL_STATIC die aus der Datei .env stammen.
Erstellen wir also .env im Stammordner mit den folgenden Parametern, die für die Erstellung von index.html und für REST-Aufrufe in der Anwendung benötigt werden:
VUE_APP_MGNL_HOST=http://localhost:8080 VUE_APP_MGNL_BASE=/magnoliaAuthor VUE_APP_MGNL_API_TEMPLATES=/.rest/template-annotations/v1 VUE_APP_MGNL_API_PAGES=/.rest/delivery/pages/v1 VUE_APP_MGNL_STATIC=/.resources/vue-gallery/webresources/dist VUE_APP_MGNL_GALLERY=/.rest/delivery/gallery/v1
Aufbau des Projekts
Fügen Sie zwei Skripte in der Datei package.json hinzu und ändern Sie das Build-Skript:
"clean": "rimraf dist && rimraf light-modules/vue-gallery/webresources/dist", "deploy": "npm run build && copyfiles -u 1 \"dist/**/*\" light-modules/vue-gallery/webresources/dist" "build": "npm run clean && vue-cli-service build",
Das Skript clean löscht kompilierten Code aus den Ordnern dist und webresources und das Skript deploy erstellt und kopiert dann den Ordner dist in den Ordner webresources.
Installation von Magnolia
Bitte folgen Sie der Dokumentation, um Magnolia zu installieren. Wenn Sie mit der Light-Entwicklung in Magnolia nicht vertraut sind, empfehle ich Ihnen, sich darüber zu informieren, bevor Sie mit dem nächsten Abschnitt fortfahren.
Ein Magnolia Light Modul erstellen
Magnolia kann über YAML-Dateien in sogenannten "Light Modules" konfiguriert werden. Erstellen Sie einen Ordner light-modules im Root-Ordner und ein vue-gallery3 Light Module über die Magnolia CLI:
mgnl create-light-module vue-gallery
Erstellen einer Inhalts-App
Als Nächstes erstellen Sie einen Inhaltstyp "Foto" und die Inhalts-App:
cd vue-gallery mgnl create-app photo
Bearbeiten Sie die Definition des Inhaltstyps in /contentTypes/photo.yaml
# Der automatisch generierte contentType demonstriert die Verwendung der allgemeinen Eigenschaften. # Passen Sie diese an Ihre Anforderungen an. datasource: workspace: gallery # Konfigurieren Sie optional einen benutzerdefinierten Namespace. (Ersetzen Sie [myNamespace] überall.) # Dieser Namespace kann dann weiter unten für den Nodetype verwendet werden. namespaces: mt: https://www.magnolia-cms.com/jcr/1.0/mt autoCreate: true model: # Geben Sie optional einen bestimmten Nodetype an, andernfalls wird 'mgnl:content' verwendet. nodeType: mt:gallery properties: - name: title label: Titel type: String required: true i18n: true - name: description label: Beschreibung type: String - name: image label: Bild Typ: Asset
Bearbeiten Sie die Definition der Content App in /contentApps/photo.yaml
!content-type:photo Name: Fotos
Wenn Sie sich jetzt bei Magnolia anmelden, sollten Sie die Fotos-App sehen und können der Fotos-App und der Assets-App Daten hinzufügen, um die REST-Endpunkte im nächsten Schritt zu testen.
Wenn Sie möchten, können Sie Daten aus dem Ordner content-import aus meinem Quellcode für den Galerie-Endpunkt importieren.
Registrierung der REST-Endpunkte
Registrieren Sie zwei REST-Endpunkte, einen für Seiten und einen für Fotos:
/restEnpoints/auslieferung/seiten_v1.yaml
class: info.magnolia.rest.delivery.jcr.v2.JcrDeliveryEndpointDefinition workspace: website nodeTypes: - mgnl:page includeSystemProperties: true bypassWorkspaceAcls: true limit: 50 depth: 10 references: - name: image propertyName: image referenceResolver: class: info.magnolia.rest.reference.dam.AssetReferenceResolverDefinition assetRenditions: - '480' - 1600x1200
/restEnpoints/Lieferung/Galerie_v1.yaml
class: info.magnolia.rest.delivery.jcr.v2.JcrDeliveryEndpointDefinition workspace: gallery nodeTypes: - mt:gallery includeSystemProperties: true bypassWorkspaceAcls: true limit: 50 depth: 10 references: - name: image propertyName: image referenceResolver: class: info.magnolia.rest.reference.dam.AssetReferenceResolverDefinition assetRenditions: - '480' - 1600x1200
Verwenden Sie die Definitions-App, um zu überprüfen, ob die neuen Endpunkte in Magnolia registriert wurden:
Sie können auch überprüfen, ob die folgenden URLs korrekt funktionieren:
Vorlagen erstellen
Erstellen Sie eine Seitenvorlage und drei Komponentenvorlagen. In unserem Beispielprojekt finden Sie Vorlagen, die Sie verwenden können.
Erstellen Sie eine Seitenvorlage in /templates/pages/standard.yaml
Klasse: info.magnolia.rendering.spa.renderer.SpaRenderableDefinition renderType: spa visible: true dialog: mte:pages/pageProperties templateScript: /vue-gallery/webresources/dist/index.html areas: header: title: Header type: single availableComponents: header: id: vue-gallery:components/page-header main: renderType: spa title: Haupt verfügbarKomponenten: gallery: id: vue-gallery:components/gallery footer: renderType: spa title: Fußzeile type: single availableComponents: footer: id: vue-gallery:components/page-footer
Die drei Komponentendefinitionen haben keinen Inhalt. Erstellen Sie drei leere Dateien, damit Magnolia diese Komponenten registrieren kann.
Der Einfachheit halber werden wir keine Dialoge erstellen.
Erstellen der Vue-Komponenten
Das Vue CLI hat bereits main.js, App.vue, und components/HelloWorld.vue für Sie erstellt.
Konfigurieren der App.vue
In diesem Tutorial werden Sie eine Bootstrap-Vorlage von https://getbootstrap.com/docs/5.0/examples/album/ verwenden . Installieren Sie Bootstrap und importieren Sie das Bootstrap-CSS:
npm install bootstrap
Fügen Sie in der Datei App.vue die folgenden Zeilen hinzu:
import "../node_modules/bootstrap/dist/css/bootstrap.css"; import "../node_modules/bootstrap/dist/js/bootstrap.js";
Als nächstes importieren Sie EditablePage aus @magnolia/vue-editor und bearbeiten die Vorlage.
<template>
<editable-page
v-if="content && templateAnnotations"
:content="content"
:templateAnnotations="templateAnnotations"
:config="config"
/>
</template>
EditablePage benötigt drei Parameter: content, templateAnnotations und config.
content ist ein Seitenobjekt
- das wir vom Seitenendpunkt abrufen müssen.
templateAnnotations ist ein Objekt des Endpunkts template annotation.
config ist ein Objekt
- das ein Attribut componentMappings hat
- das ich später erstellen werde.
Nachfolgend finden Sie den Code zur Initialisierung der Parameter für die EditablePage
import "../node_modules/bootstrap/dist/css/bootstrap.css"; import "../node_modules/bootstrap/dist/js/bootstrap.js"; import { EditablePage } from '@magnolia/vue-editor'; import componentMappings from './mappings'; import config from './config'; function removeExtension(path) { let newPath = path; if (path.indexOf('.') > -1) { newPath = path.substr(0, path.lastIndexOf('.')); } return newPath; } export default { name: "App", components: { EditablePage }, data() { return { content: null, templateAnnotations: null, config: { componentMappings } }; }, methods: { async loadPage() { const { pathname } = window.location; const path = config.BASE ? pathname.substr(config.BASE.length) : pathname; const url = `${config.HOST}${config.BASE}${config.PAGES}${removeExtension(path)}`; const pageRes = await fetch(url); const data = await pageRes.json(); this.content = data; const annotationUrl = `${config.HOST}${config.BASE}${config.ANNOTATIONS}${removeExtension(path)}`; const annotationRes = await fetch(annotationUrl); const annotationData = await annotationRes.json(); this.templateAnnotations = annotationData; } }, mounted() { this.loadPage(); } };
loadPage muss nach mounted aufgerufen werden, da vue-editor erst funktioniert, nachdem Vue das HTML im Dokument gerendert hat.
Sie müssen auch die Berechtigungen für den Aufruf des Endpunkts für Vorlagenanmerkungen konfigurieren. In der Dokumentation finden Sie die Standardkonfiguration.
Erstellen des Konfigurationsobjekts
Verwenden Sie in der App.vue-Komponente ein Config-Objekt, das Parameter speichert, um URLs zum Abrufen von Daten von REST-Endpunkten zu generieren.
Erstellen Sie /config.js:
const HOST = process.env.VUE_APP_MGNL_HOST || 'http://localhost:8080'; const BASE = process.env.VUE_APP_MGNL_BASE || '/magnoliaAuthor'; const ANNOTATIONS = process.env.VUE_APP_MGNL_API_TEMPLATES || '/.rest/template-annotations/v1'; const PAGES = process.env.VUE_APP_MGNL_API_PAGES || '/.rest/delivery/pages/v1'; const GALLERY = process.env.VUE_APP_MGNL_GALLERY || '/.rest/gallery/gallery/v1'; export default { HOST, BASE, ANNOTATIONS, PAGES, GALLERY };
Erstellen einer Seitenkomponente zur Anzeige der Standardseitenvorlage
Die App.vue ist nun fertig, also erstellen Sie eine Seitenkomponente mit den Parametern header, main und footer von EditablePage.
Die EditablePage rendert eine Seitenkomponente dynamisch und übergibt alle Bereiche aus der Template-Definition an die dynamische Seitenkomponente.
Erstellen Sie StandardPage.vue im Ordner src/components
<template>
<header>
<editable-area :content="header"></editable-area>
</header>
<main>
<section class="py-5 text-center container">
<div class="row py-lg-5">
<div class="col-lg-6 col-md-8 mx-auto">
<h1 class="fw-light">Beispiel für ein Album</h1>
<p class="lead text-muted">
Eine kurze und prägnante Beschreibung der unten stehenden Sammlung, ihres Inhalts, ihres Schöpfers usw. Machen Sie es kurz und bündig, aber nicht zu kurz, damit die Leute es nicht einfach übergehen. </p>
<p>
<a
href="https://getbootstrap.com/docs/5.0/examples/album/#"
class="btn btn-primary my-2"
>Hauptaufforderung zum Handeln</a
>
<a
href="https://getbootstrap.com/docs/5.0/examples/album/#"
class="btn btn-secondary my-2"
>Nebenaufforderung</a
></p>
</div>
</div>
</section>
<div class="album py-5 bg-light">
<editable-area :content="main"></editable-area>
</div>
</main>
<editable-area :content="footer"></editable-area>
</template>
<script>
import { EditableArea } from '@magnolia/vue-editor';
export default {
name: 'StandardPage',
components: { EditableArea },
props: ['header', 'main', 'footer']
};
</script>
Die StandardPage importiert EditableArea von @magnolia/vue-editor und hat drei Eigenschaften: header, main und footer. Die Vorlage spezifiziert jeden Bereich im Seitenlayout.
Erstellen von Komponenten-Zuordnungen
Erstellen Sie nun die Komponentenzuordnungen, die die Komponente StandardPage der ID der Seitenvorlage in src/mappings.js zuordnen:
import StandardPage from './components/StandardPage.vue'; export default { 'vue-gallery:pages/standard': StandardPage };
Führen Sie npm run deploy aus und überprüfen Sie das Ergebnis in Magnolia.
Erstellen der Kartenkomponente
Erstellen Sie eine Kartenkomponente in src/components/Card.vue mit einer Fotoeigenschaft, an die Sie ein Fotoobjekt übergeben können:
<template>
<div class="card shadow-sm">
<svg
class="bd-placeholder-img card-img-top"
width="100%"
height="280"
xmlns="http://www.w3.org/2000/svg"
role="img"
aria-label="Placeholder: Thumbnail"
preserveAspectRatio="xMidYMid slice"
focusable="false"
>
<title>Platzhalter</title>
<rect width="100%" height="100%" fill="#55595c"></rect>
<text x="50%" y="50%" fill="#eceeef" dy=".3em">Vorschaubild</text>
<image :href="hostname + photo.image.renditions['480'].link" width="100%" height="100%" ></image>
</svg>
<div class="card-body">
<p class="card-text">
Dies ist eine breitere Karte mit darunter liegendem Text als natürliche Einleitung zu weiteren Inhalten. Dieser Inhalt ist ein wenig länger. </p>
</div>
</div>
</template>
<script>
import config from '../config';
export default {
name: 'Card',
props: ['photo'],
setup() {
return {
hostname: config.HOST
}
}
};
</script>
Erstellen der Galeriekomponente
Als Nächstes erstellen Sie eine Galeriekomponente in src/components/Gallery.vue, um Fotos vom Galerie-Endpunkt abzurufen:
<template>
<div class="container">
<div class="row row-cols-1 row-cols-sm-2 row-cols-md-3 g-3">
<div class="col" v-for="photo in photos" :key="photo['@id']">
<card :photo="photo"></card>
</div>
</div>
</div>
</template>
<script>
import Card from './Card.vue'
import config from '../config';
export default {
name: 'Gallery',
data() {
return {
photos: []
}
},
components: { Card },
methods: {
async loadData() {
const url = `${config.HOST}${config.BASE}${config.GALLERY}`;
const res = await fetch(url);
const data = await res.json();
this.photos = data.results;
}
},
beforeMount() {
this.loadData();
}
}
</script>
Sie müssen auch die HTML-Tags PageHeader und PageFooter erstellen. Sie finden den Code in den Quellen meines Projekts. Beachten Sie, dass ich ein Seitenpräfix hinzugefügt habe, um einen Konflikt zu vermeiden.
Dann ordnen Sie Gallery, PageHeader und PageFooter der Datei mappings.js zu:
import StandardPage from './components/StandardPage.vue'; import Gallery from './components/Gallery.vue'; import PageHeader from './components/PageHeader.vue'; import PageFooter from './components/PageFooter.vue'; export default { 'vue-gallery:pages/standard': StandardPage, 'vue-gallery:components/gallery': Gallery, 'vue-gallery:components/page-header': PageHeader, 'vue-gallery:components/page-footer': PageFooter };
Sie haben nun dieses Tutorial abgeschlossen und können Ihre Vue-Vorlagen an Ihre Bedürfnisse anpassen.
Screenshots aus dem Projekt
Die Galerieseite im Bearbeitungsmodus
Die Galerie-Seite, die in Magnolia gehostet wird
Die Galerie-Seite auf dem Dev-Server (npm run serve)
Ressourcen
Den Quellcode des Projekts finden Sie unten:
Wir haben auch ein weiteres Beispielprojekt, das Sie interessieren könnte:
Wenn Sie mit Magnolia Light Modules oder dem Seiteneditor noch nicht vertraut sind, können Sie sich diese Ressourcen ansehen: