Interaktive Websites mit Nuxt.js – für Geschwindigkeit, SEO und Social Media

Nuxt.js fasst eine Vielzahl von JavaScript-Bibliotheken und Frameworks rund um Vue.js zusammen und ermöglicht so eine produktive Umgebung für Entwickler.

Lesezeit: 15 Min.
In Pocket speichern
vorlesen Druckansicht Kommentare lesen 32 Beiträge
Interaktive Websites mit Nuxt.js – Für Geschwindigkeit, SEO und Social Media

(Bild: Blackboard/Shutterstock.com)

Von
  • Alexander Schwartz
Inhaltsverzeichnis

Bei der Reise durch das Web sind manche Websites schnell, manche erschreckend langsam. Je nachdem, wie geschickt die Autoren der Website vorgehen, ruckelt sich die Darstellung nach und nach zurecht, bis alle Informationen den Browser erreichen und verarbeitet wurden. In den letzten Jahren kamen immer mehr Single Page Applications (SPA) hinzu. Nutzer erkennen sie meist an dem sich drehenden Ajax-Kringel, der sie zur Geduld auffordert. Verwenden können sie die Seite erst, wenn der Browser alle JavaScript-Bibliotheken und die eigentlichen Daten nachgeladen hat.

Die Nutzer hätten sich schon längst an die Wartezeit gewöhnt, wenn es nicht immer wieder Websites gäbe, die schnell sind, nicht ruckeln und trotzdem Interaktivität durch JavaScript bieten. Doch was macht eine Website schnell? Und wie kann man die Geschwindigkeit mit einem JavaScript-Framework wie Nuxt.js umsetzen?

Eine schnelle Website muss bereits nach der ersten HTTP-Antwort für den Nutzer dargestellt sein. Allerdings ermöglicht erst JavaScript eine voll interaktive Website, die nicht bei jeder Nutzerinteraktion mit dem Server Kontakt aufnehmen muss.

Universal Web Apps vereinen die schnelle Anzeige einer statischen HTML-Seite und die Interaktivität der Single-Page-App. Frameworks ermöglichen das, indem sie die HTML-Seite serverseitig vorberechnen. Sie packen alles für die erste Darstellung Notwendige in die eine entscheidende Antwort: zu Beginn das CSS, dann das vorberechnete HTML. Erst danach, während die Seite schon angezeigt wird, lädt und startet JavaScript. Während die Nutzer schon lesen und scrollen können, wird die Seite durch das nachgeladene JavaScript nahtlos zur interaktiven Single-Page-App. Da das CSS eingebettet vor dem HTML steht, entfällt ein häufiger Grund für einen ruckelnden Seitenaufbau. Verwenden die Entwickler responsives CSS, so werden Platzhalter für Grafiken beim ersten Rendern in der passenden Größe vorgehalten und der zweite Grund für einen ruckelnden Seitenaufbau entfällt.

Für alle drei populären JavaScript-Frameworks stehen Erweiterungen für Universal Web Apps zur Verfügung: Für Angular ist es Angular Universal, für Vue.js ist es Nuxt.js und für React NEXT.js oder auch Gatsby. Die Entscheidung zwischen diesen Erweiterungen fällt nicht leicht: Mit welchem Framework sind die Entwickler eher vertraut? Wie groß ist die Community und wie groß sind die Zukunftsaussichten des Frameworks? Bietet es genügend Funktionen und ist es bei Bedarf erweiterbar? Sind die APIs stabil?

Der Autor des Artikels entschied sich für Nuxt.js, da er mit Vue.js bereits gute Erfahrungen gesammelt hat. Vue.js bietet in der Kombination mit Nuxt.js alle benötigten Funktionen für schnelle und interaktive Websites. Über Vue.js konnte der Autor auch schwierige Integrationen mit Drittherstellern umsetzen. Nuxt.js erwies sich als gut konfigurier- und erweiterbar.

Darüber hinaus ist Vue.js aus Sicht des Autors das Framework mit der größten API-Stabilität, da die 2.x-API bereits seit September 2016 besteht. Auch die geplante 3.x-API soll weitestgehend abwärtskompatibel bleiben. Vue.js und Nuxt.js liefern in regelmäßigen Minor-Releases Erweiterungen ohne die API-Kompatibilität zu brechen. Die folgenden Beispiele nutzen daher Nuxt.js. Die aufgeführten Anwendungsfälle können Leser verwenden, um andere Frameworks für ihren Bedarf zu evaluieren.

Nuxt.js kann in verschiedenen Modi arbeiten.

Das serverseitige Erstellen der Seite bleibt zunächst deaktiviert, dafür kann die Anwendung überall dort eingesetzt werden, wo heute Single-Page-Apps Verwendung finden. Dazu generiert Nuxt.js im Build-Prozess die notwendigen minifizierten JavaScript- und HTML-Dateien. Damit sehen Nutzer der Website erst dann Daten, wenn die komplette SPA geladen und gestartet ist.

In diesem Modus berechnet Nuxt.js die Seiten serverseitig, wenn Nutzer sie aufrufen. Dafür läuft auf dem Server eine Node-Instanz. Entwickler können Daten dynamisch zum Beispiel via REST aus Backend-Systemen laden. Website-Besucher erhalten eine individuell für sie vorberechnete HTML-Seite, auf der sie bereits lesen und scrollen können, während der Browser den JavaScript-Teil der Anwendung nachlädt.

Statt die Seite bei jedem Aufruf neu zu berechnen, tut Nuxt.js dies im Pre-Rendered-Modus nur einmal zum Build-Zeitpunkt. Ergebnis ist eine statische HTML-Seite nebst dazugehörigen JavaScript-Dateien, die anschließend über ein Content Delivery Network (CDN) zu den Nutzern gelangen. Das CDN sorgt dafür, dass die Daten auf mehreren weltweit verteilten Servern vorliegen und immer der Server sie ausliefert, der dem Nutzer am nächsten ist. Das beschleunigt den Seitenaufbau noch einmal deutlich. Ändern sich wesentliche Inhalte der Website, muss Nuxt.js die Seiten jedoch neu generieren und an das CDN verteilen.

Nuxt.js basiert im Kern auf dem JavaScript-Framework Vue.js. Es konfiguriert rund um Vue.js und dessen serverseitige Render-Fähigkeiten einen kompletten Build-Prozess basierend auf Node und webpack. Damit finden sich JavaScript-Entwickler in einer zeitgemäßen und ihnen wahrscheinlich schon bekannten Entwicklungsumgebung wieder: Das Dependency-Management funktioniert über package.jsonund wahlweise yarn oder npm. Während der Entwicklung landen Änderungen an den Quelldateien via Hot-Reload direkt im Browser des Entwicklers. Unit- und Integrationstests stellen sicher, dass einmal entwickelte Funktionen nach Änderungen weiterhin funktionieren.

Ist Node.js installiert, erstellt der folgende Befehl ein Basisprojekt:

$ yarn create nuxt-app <project-name>

Ein Kommandozeilen-Interface führt durch Fragen zu REST-, CSS- und Test-Frameworks. Entwickler können sich zwischen TypeScript und JavaScript als Programmiersprache entscheiden.

In der zentralen Konfigurationsdatei nuxt.config.js finden sich alle projektspezifischen Konfigurationen. Anhand der ausführlichen API-Dokumentation auf der Nuxt.js-Homepage können Entwickler Standardwerte überschreiben.

Die "Getting Started"-Anleitung auf der Nuxt.js-Seite führt neue Entwickler Schritt für Schritt durch die Teile der Anwendung. Die wichtigsten Verzeichnisse sind layouts für Seitendesignvorlagen und pages für die einzelnen Seiten selbst. Aus den Dateien und Verzeichnissen unter pages konfiguriert Nuxt.js ein standardmäßiges Routing, sodass einzelne Seiten über URLs entsprechend der Verzeichnisstruktur erreichbar sind. Bei Bedarf können Entwickler dies in der Konfigurationsdatei nuxt.config.js anpassen und überschreiben.

Die neue Nuxt.js-Website soll nun Schritt für Schritt publiziert und optimiert werden. Als ersten Schritt (und beispielhaft für die Konfigurationsmöglichkeiten) wird sie in ein Content Delivery Network publiziert, hier am Beispiel von Netlify. Netlify integriert einen Continuous-Integration- und -Delivery-Mechanismus, der den Build-Prozess manuell oder bei einer Änderung an einer Quelldatei automatisch startet.

Die Schritte dafür sind wie folgt:

1. Ergänzen der Konfiguration um eine Netlify-konforme Generierung. Die folgende Konfiguration erzeugt für jede Seite im page-Quellverzeichnis eine HTML-Seite mit gleichem Namen. Zusätzlich erzeugt es eine Fallback-Seite 404.html, die das Content Delivery Network als Antwort auf eine nicht gefundene Datei zurückliefert.

generate: {
// subfolders would create redirects on netlify, therefore disable
subFolders: false,
fallback: true
}

2. Hinterlegen der URL zum Quellcode-Repository bei Netlify.

3. Konfiguration des Build-Befehls yarn generateund des Output-Verzeichnisses mit statisch generierten Dateien dist, wahlweise über die Netlify-Weboberfläche oder über eine Konfigurationsdatei netlify.toml.

Nach wenigen Minuten ist der erste Build live verfügbar. Bei allen weiteren Änderungen im Git-Repository wird die Anwendung automatisch neu gebaut und ausgerollt.

Teilt ein Nutzer einen Link auf einem sozialen Netzwerk, so analysiert dieses den HTML-Code der Seite: Twitter, Facebook und Co. erzeugen aus den Metadaten der Seite wie dem Titel und der Beschreibung eine Vorschau. Das in die Seite eingebettete JavaScript bleibt dabei unberücksichtigt. Suchmaschinen nutzen für die Indexierung von Webseiten den HTML-Code. Nur wenige Suchmaschinen wie Google starten auch den JavaScript-Code und können so Single-Page-Apps indexieren.

Da im vorherigen Abschnitt die Seiten generiert wurden, stehen den sozialen Netzwerken und Suchmaschinen alle Inhalte der Seite als HTML zur Verfügung. Auch in der Variante Universal App, bei der der Node-Server das HTML im Moment des Aufrufs generiert, funktioniert das. Noch enthalten aber alle Seiten die gleichen Metainformationen im Kopf der Seite. Jedoch soll jede Seite ihren eigenen Titel, Beschreibung und Vorschaubild bekommen, mit denen sie in sozialen Netzwerken und Suchergebnissen angezeigt wird.

Zunächst können Entwickler die globalen Standardwerte für Metainformationen in der nuxt-config.js-Datei hinterlegen. Werte, die später die einzelnen Seiten individuell überschreiben sollen, bekommen eine Header-ID hid, mit der man sie später referenzieren kann.

head: {
/* ... */
meta: [
/* ... */
{charset: 'utf-8'},
{name: 'viewport', content: 'width=device-width, initial-scale=1'},
{hid: 'ttitle', name: 'twitter:title', content: 'My Homepage'},
{hid: 'desc', name: 'description', content: 'I am a developer'},
{hid: 'tcard', name: 'twitter:card', content: 'summary'},
]
}

Jetzt können Entwickler die Werte auf einer Seite überschreiben. Das folgende Beispiel zeigt eine Seite für einen Blogbeitrag, dessen Daten in post hinterlegt sind. Während Titel und Beschreibung immer gesetzt sein müssen, werden das Vorschaubild und der Vorschautyp summary_large_image nur dann gesetzt, wenn der Blogbeitrag auch ein Vorschaubild enthält.

export default {
head() {
const self = this;
const head = {
title: self.post.title,
meta: [
{hid: 'ttitle', name: "twitter:title", content: self.post.title},
{hid: 'desc', name: 'description', content: self.post.description},
{hid: 'tdescription', name: 'twitter:description', content: self.post.description},
{
hid: 'tcard',
name: 'twitter:card',
content: self.post.preview !== undefined ? 'summary_large_image' : 'summary'
},
]
};
if (self.post.preview !== undefined) {
head.meta.push(
{hid: 'timage', name: 'twitter:image', content: 'https://www.example.com' + self.post.preview}
)
}
return head
}
}

Anschließend können Entwickler die korrekte Verwendung der allgemeinen und Twitter-spezifischen Meta-Tags über die Twitter-Developer-Tools verifizieren. Da verschiedene soziale Netzwerke verschiedene Meta-Tags verwenden, müssen die Entwickler für weitere soziale Netzwerke meist zusätzliche Meta-Tags aufnehmen und diese mit den jeweiligen Developer-Tools prüfen.

Für Nuxt.js gibt es ein Ökosystem mit Plug-ins. Eines dieser Plug-ins erzeugt eine Sitemap. Eine erste minimale Konfiguration, die für alle statischen Routen der Anwendung eine Sitemap erstellt, sieht wie folgt aus:

$ yarn add --dev @nuxtjs/sitemap

{
modules: [
'@nuxtjs/sitemap'
],
sitemap: {
hostname: 'https://example.com'
}
}

Mehr ist nicht notwendig, um ein Plug-in in Nuxt.js einzubinden. Die Awesome Nuxt.js List bietet einen Überblick über die verschiedenen Erweiterungen, die das Core-Team und die Community bereitstellen.

Beim Pre-Rendering sendet der Server zu Beginn der Seite das CSS. Standardmäßig schickt Nuxt.js das komplette referenzierte CSS der Seite mit. Wenn die Seite ein CSS-Framework verwendet, so nutzen die Seiten meist nur einen Teil des CSS. Damit Nuxt.js nur das notwendige CSS mitschickt, existieren verschiedene Bibliotheken, die die Anwendung nach verwendeten CSS-Klassen analysieren. Eine davon ist Purgecss, für das es ein fertiges Nuxt.js-Modul gibt. Entwickler können es wie folgt installieren:

$ yarn add --dev nuxt-purgecss

Danach können sie das PurgeCSS-Plug-in im postcss-Modus aktivieren:

{
modules: [
'nuxt-purgecss',
],
purgeCSS: {
mode: 'postcss',
whitelist: ['html', 'body', 'has-navbar-fixed-top', 'nuxt-link-exact-active', 'nuxt-progress'],
enabled: true // for fast enabling also in dev mode to check whitelist
}
}<

Wie im Listing dargestellt, akzeptiert die Erweiterung als Parameter eine Whitelist für Klassen, die nicht explizit in den Quelldateien vorkommen. Beispiele für solche Klassen sind Parameter in der Konfiguration in nuxt-config.js oder Klassen wie nuxt-link-exact-active und nuxt-progress, die eingebundene Frameworks setzen.

Entwickler können über die Konfigurationsdatei auch den webpack-Build-Prozess erweitern. Die folgenden Schritte binden das Webpack Plug-in responsive-loader ein, das Grafiken skalieren und minifizieren kann. Das Beispiel zeigt, wie flexibel der Nuxt.js-Build-Prozess erweiterbar ist, auch wenn kein fertiges Plug-in im Nuxt.js-Ökosystem existiert.

build: {
extend(config, {isDev, isClient}) {
// adding the new loader as the first in the list
config.module.rules.unshift({
test: /\.(png|jpe?g|gif)$/,
use: {
loader: 'responsive-loader',
options: {
// disable: isDev,
placeholder: true,
quality: 85,
placeholderSize: 30,
name: 'img/[name].[hash:hex:7].[width].[ext]',
adapter: require('responsive-loader/sharp')
}
}
})
// remove old pattern from the older loader
config.module.rules.forEach(value => {
if (String(value.test) === String(/\.(png|jpe?g|gif|svg|webp)$/)) {
// reduce to svg and webp, as other images are handled above
value.test = /\.(svg|webp)$/
// keep the configuration from image-webpack-loader here unchanged
}
})
}
}

Universal Web Apps bieten Nutzern angenehm schnelle Renderzeiten. Damit lassen sich auch auf mobilen Endgeräten Seitenladezeiten von weniger als einer Sekunde erreichen.

Unter der Haube bringt Nuxt.js eine Vielzahl von JavaScript-Bibliotheken und -Frameworks zusammen und ermöglicht so eine produktive Umgebung für Entwickler und ein angenehmes Erlebnis für Nutzer. Nuxt.js unterstützt drei Modi: Single Page App (SPA), Universal Application und Pre-Rendered. Dies erlaubt es den Entwicklern, zunächst mit einer SPA zu beginnen und später die erweiterten Funktionen zu aktivieren.

Nuxt.js baut auf Vue.js auf und bietet zuverlässige Releases und stabile APIs. Entwickler können dabei auf ihre bestehenden JavaScript-Kenntnisse und webpack-Erfahrungen zurückgreifen. Das Framework Nuxt.js lässt sich bei Bedarf um Plug-ins des eigenen Nuxt.js-Ökosystems oder um andere webpack-Plug-ins erweitern. Erfahrene JavaScript-Entwickler können so ihr bestehendes Wissen nutzen, um Universal Web Apps zu erstellen Damit ist Nuxt.js ein guter Kandidat für Websites, die auch auf mobilen Endgeräten begeistern.

Alexander Schwartz
arbeitet als Principal IT Consultant bei der msg. Im Laufe der Zeit arbeitete er mit verschiedensten Server- und Webtechnologien. Auf Konferenzen und bei User Groups spricht er über seine Erfahrungen, in seinem persönlichen Blog schreibt er zu Themen rund um die IT.
(bbo)