20.10.2020

Statische Blogartikel mit @nuxt/content erzeugen

Mit dem neuen nuxt-Modul @nuxt/content (https://content.nuxtjs.org/) ist es ein leichtes, einen statischen Blog zu erstellen. In diesem Artikel m├Âchte ich zeigen, wie dieser Blog mit Hilfe von @nuxt/content entstanden ist.

Erzeugen/Anlegen der Inhalte

Inhalte werden im Root-Ordner content abgelegt und k├Ânnen standardm├Ą├čig in unterschiedlichen Formaten angelegt werden, dazu z├Ąhlen:

  • Markdown
  • JSON
  • CSV
  • XML
  • YAML

Je nach Typ sorgen unterschiedliche Parser daf├╝r, dass die Inhalte in der Nuxt-App ├╝ber den Root-Kontext abrufbar sind (this.$content bzw. context.$content).

F├╝r den Blog ist sicherlich Markdown der passendste Typ. ├ťber einen vorangestellten Bereich (Front Matter) ist es m├Âglich Attribute des Inhalts zu setzen. Dazu z├Ąhlen z.B. Titel und Beschreibung, aber man ist nicht auf die Standard-Attribute beschr├Ąnkt, es ist auch m├Âglich eigene Attribute hinzuzuf├╝gen (im Beispiel: img und date)

---
title: '@nuxt/content + Blog = ­čśŹ'
description: 'Das ist ein Beispiel-Beschreibungstext'
img: blog-images/2020/nuxt-content.jpg
date: 2020-10-20
---
# ├ťberschrift 1

## ├ťberschrift 2

...

Wichtig zu wissen: aktuell ist es die empfohlene Variante, Bilder und andere statische Dateien, die innerhalb des Inhalts eingebunden werden, im static Ordner der Nuxt-App abzulegen. Hintergrund hierbei ist, dass bei einem Build der App der static-Ordner von Webpack ignoriert wird und so beim Hinzuf├╝gen von Inhalten kein neuer Webpack-Build erforderlich ist.
F├╝r andere Ablageordner gibt es auf GitHub bereits mehrere Vorschl├Ąge, wie das umsetzbar ist (siehe hier). Ebenfalls kann man dem GitHub Issue entnehmen, dass bereits an einer L├Âsung gearbeitet wird, sodass in Zukunft standardm├Ą├čig vermutlich auch andere Ordner verwendet werden k├Ânnen.

Abruf der Inhalte: Query-API ├Ąhnlich zu MongoDB

Nach dem Erstellen der Inhalte sollen diese nat├╝rlich auch in der Nuxt-App angezeigt werden. Dazu bietet das Modul eine API, die der von MongoDB ├Ąhnelt. Mit einfachen verkettbaren Methoden hat man die Kontrolle dar├╝ber, welche Inhalte gefunden und angezeigt werden sollen.

Beispiel: Folgende Abfrage liefert alle Blogartikel mit ihrem Titel, ihrer Beschreibung, URL-Slug, vollst├Ąndigem Pfad und Erstellungsdatum zur├╝ck.

const articles = await $content('blog', { deep: true })  .only(['title', 'description', 'slug', 'path', 'createdAt'])  .sortBy('createdAt', 'desc')  .fetch()

Anzeige der Inhalte

Innerhalb der Vue-Komponente k├Ânnen die Inhalte dann ganz einfach verwendet werden. F├╝r Markdown-Inhalte gibt es bereits die mitgelieferte Komponente nuxt-content, ├╝ber die das Markdown geparsed und gerendert wird. Die Styles der einzelnen Bereiche k├Ânnen dann einfach ├╝ber simple CSS-Selektoren angepasst werden, die ├╝ber die CSS-Klasse "nuxt-content" nur auf den Markdown Bereich gescoped werden.

<template>  <article class="article">    <div class="banner" :class="article.img ? 'with-bg' : ''">      <img v-if="article.img" :src="`/${article.img}`" />      <h1>{{ article.title }}</h1>    </div>    <div class="date">{{ date }}</div>    <nuxt-content :document="article" class="content" />  </article></template><script>import { toLocaleDate } from '@/helpers/date'export default {  props: {    article: {      type: Object,    },  },  computed: {    date() {      return toLocaleDate(this.article.date)    },  },}</script><style lang="scss">.nuxt-content {  h1 {    font-size: 2em;    margin: 0 0 0.3em;  }  h2 {    margin: 1.5em 0 0.5em;  }  ul {    margin: 0.5em 0;  }}</style>

Automatisches Routing ├╝ber Verzeichnisstruktur

Innerhalb der Nuxt-App integriert sich das Modul auch nahtlos in das Routing. Wie man es vom Routing in Nuxt gew├Âhnt ist, ergibt sich die URL aus einer Abbildung der Verzeichnisstruktur. Dabei werden vom Modul automatisch die entsprechenden Routen dem Router hinzugef├╝gt.

content
|-- home.md
|-- 2019
    |-- artikel1.md
|-- 2020
    |-- artikel2.md

F├╝r diese Verzeichnisstruktur werden also automatisch folgende Routen angelegt:

  • /home
  • /2019/artikel1
  • /2020/artikel2

Dieses Verhalten kann nat├╝rlich angepasst werden, so kann man z.B. einen eigenen URL-Slug als Attribut im Front Matter Bereich hinzuf├╝gen und diesen dann bei der Generierung der Routen abfragen und verwenden.

Static site generation Support

Nuxt bietet standardm├Ą├čig die M├Âglichkeit der Generierung von statischen Seiten. Auch hier f├╝gt sich das content-Modul nahtlos ein - die Generierung funktioniert weiterhin ohne Probleme.
Allerdings gibt es eine kleine Einschr├Ąnkung: sofern die Inhalte nicht nachgeladen werden d├╝rfen/k├Ânnen/sollen, muss die Abfrage der Inhalte innerhalb der jeweiligen Nuxt-Page gemacht werden, da nur dort das Laden der Inhalte ├╝ber asyncData verf├╝gbar ist.

export default {  async asyncData({ $content, app, params, error }) {    const path = `/blog/${params.pathMatch || 'index'}`    const [article] = await $content({ deep: true }).where({ path }).fetch()    if (!article) {      return error({ statusCode: 404, message: 'Article not found' })    }    return {      article,    }  },}

Die Generierung der Seiten selbst ist davon nicht eingeschr├Ąnkt, es geht also wirklich haupts├Ąchlich darum, ob die Inhalte im generierten HTML bereits vorhanden sein sollen.

Trennung von Code und Content

Durch die Trennung von Applikationscode und Content ist m├Âglich, die Code-Generierung (Webpack) beim Hinzuf├╝gen von neuen Inhalten zu ├╝berspringen, da einfach festgestellt werden kann, ob sich der Applikations-Code ge├Ąndert hat oder nicht. Das f├╝hrt zu einer deutlich schnelleren "Build"-Zeit, da nur noch die neuen Inhalte prozessiert werden m├╝ssen.