Eine Headless Vue.js Anwendung entwickeln mit Magnolia
Sep. 1, 2021
--
Vue

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.

Java
  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.

Java
  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:

Java
  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:

Java
  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:

Java
  "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:

Java
  mgnl create-light-module vue-gallery  

Erstellen einer Inhalts-App

Als Nächstes erstellen Sie einen Inhaltstyp "Foto" und die Inhalts-App:

Java
  cd vue-gallery mgnl create-app photo  

Bearbeiten Sie die Definition des Inhaltstyps in /contentTypes/photo.yaml

Java
  # 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

Java
  !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

Java
  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

Java
  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:

Definitions_gallery

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

Java
  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:

Java
  npm install bootstrap  

Fügen Sie in der Datei App.vue die folgenden Zeilen hinzu:

Java
  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.

Java
  <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

Java
  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:

Java
  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

Java
  <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:

Java
  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.

Editor_album

Erstellen der Kartenkomponente

Erstellen Sie eine Kartenkomponente in src/components/Card.vue mit einer Fotoeigenschaft, an die Sie ein Fotoobjekt übergeben können:

Java
  <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:

Java
  <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:

Java
  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

Gallery_page_in_edit_mode

Die Galerie-Seite, die in Magnolia gehostet wird

Gallery_page

Die Galerie-Seite auf dem Dev-Server (npm run serve)

Gallery_page_on_dev

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:

Über den autor

Dominic Nguyen

Senior Software Developer, Magnolia

Dominic is a senior software developer at Magnolia.