5. Beispiel [nuxt-02]: Server- und Client-Seiten
In diesem Projekt zeigen wir:
- dass die vom Client erstellte Seite optisch von der vom Server empfangenen Seite abweichen kann. Es kommt dann zu einem schnellen Seitenwechsel, der für den Nutzer wahrnehmbar ist und somit die Benutzerfreundlichkeit der Anwendung beeinträchtigt. Diese Vorgehensweise sollte daher vermieden werden;
- eine Lösung, bei der die Client-Seite dieselbe Seite nachbildet, die vom Server gesendet wurde;
Das Projekt [nuxt-02] wird zunächst durch Kopieren des Projekts [nuxt-01] erstellt.

Dem Projekt wird ein Ordner „[store]“ sowie zwei neue Seiten hinzugefügt. Wir werden darauf zurückkommen.
5.1. Die Seite [index]
5.1.1. Der Code der Seite
Der Code der Seite [index] lautet nun wie folgt:
<!-- Startseite -->
<template>
<Layout :left="true" :right="true">
<!-- Navigation -->
<Navigation slot="left" />
<!-- Meldung-->
<b-alert slot="right" show variant="warning"> Home - value= {{ value }} </b-alert>
</Layout>
</template>
<script>
/* eslint-disable no-undef */
/* eslint-disable no-console */
/* eslint-disable nuxt/no-env-in-hooks */
import Navigation from '@/components/navigation'
import Layout from '@/components/layout'
export default {
name: 'Home',
// verwendete Komponenten
components: {
Layout,
Navigation
},
data() {
return {
value: 0
}
},
// Lebenszyklus
beforeCreate() {
// Client und Server
console.log('[home beforeCreate]')
},
created() {
// Client und Server
console.log('[home created]')
// nur Server
if (process.server) {
this.value = 10
}
// Client und Server
console.log('value=', this.value)
},
beforeMount() {
// nur Client
console.log('[home beforeMount]')
},
mounted() {
// nur Client
console.log('[home mounted]')
}
}
</script>
Anmerkungen
- Zeile 7: Die Seite [index] zeigt den Wert ihrer Eigenschaft [value] (Zeile 28) an;
- Zeilen 36–45: Hier ist zu beachten, dass die Funktion [created] sowohl serverseitig als auch clientseitig ausgeführt wird. In den Zeilen 40–42 setzt der Server den Wert der Eigenschaft [value] auf 10. Der Client hingegen verändert diesen Wert nicht. Wir wollen lediglich wissen, ob dieser Wert vom Client beibehalten wird. Wir werden feststellen, dass dies nicht der Fall ist;
5.1.2. Ausführung
Wir ändern die Datei [/nuxt.config.js], um das Projekt [nuxt-02] auszuführen:
...
// Quellcode-Verzeichnis
srcDir: 'nuxt-02',
// Router
router: {
// Stammverzeichnis der Anwendung URL
base: '/nuxt-02/'
},
// Server
server: {
// Dienstport, standardmäßig 3000
port: 81,
// Abgehörte Netzwerkadressen, standardmäßig localhost: 127.0.0.1
// 0.0.0.0 = alle Netzwerkadressen des Rechners
host: 'localhost'
}
...
Wir führen das Projekt [1] aus:

Die Seite [index] wird nun als [2-3] angezeigt. Sie zeigt kurz den Wert [10] an und anschließend den Wert [0]. Was ist passiert?
Schritt 1
Der Server wird zuerst ausgeführt. Er führt den Code der Seite [index] aus:
export default {
name: 'Home',
// verwendete Komponenten
components: {
Layout,
Navigation
},
data() {
return {
value: 0
}
},
// Lebenszyklus
beforeCreate() {
// Client und Server
console.log('[home beforeCreate]')
},
created() {
// Client und Server
console.log('[home created]')
// nur Server
if (process.server) {
this.value = 10
}
// Client und Server
console.log('value=', this.value)
},
beforeMount() {
// nur Client
console.log('[home beforeMount]')
},
mounted() {
// nur Client
console.log('[home mounted]')
}
}
- Aufgrund von Zeile 23 erhält die Eigenschaft [value] aus Zeile 10 den Wert 10;
Dies lässt sich überprüfen, indem man den Quellcode der vom Browser empfangenen Seite betrachtet (Option [code source] im Browser):
<!doctype html>
<html data-n-head-ssr>
<head>
<title>Introduction à [nuxt.js]</title>
<meta data-n-head="ssr" charset="utf-8">
<meta data-n-head="ssr" name="viewport" content="width=device-width, initial-scale=1">
<meta data-n-head="ssr" data-hid="description" name="description" content="ssr routing loading asyncdata middleware plugins store">
<link data-n-head="ssr" rel="icon" type="image/x-icon" href="/favicon.ico">
<base href="/nuxt-02/">
<link rel="preload" href="/nuxt-02/_nuxt/runtime.js" as="script">
<link rel="preload" href="/nuxt-02/_nuxt/commons.app.js" as="script">
<link rel="preload" href="/nuxt-02/_nuxt/vendors.app.js" as="script">
<link rel="preload" href="/nuxt-02/_nuxt/app.js" as="script">
....
</head>
<body>
<div data-server-rendered="true" id="__nuxt">
<div id="__layout">
<div class="container">
<div class="card">
<div class="card-body">
<div role="alert" aria-live="polite" aria-atomic="true" align="center" class="alert alert-success">
<h4>[nuxt-02] : page serveur, page client</h4>
</div> <div>
<div class="row">
<div class="col-2">
<ul class="nav flex-column">
<li class="nav-item">
<a href="/nuxt-02/" target="_self" class="nav-link active nuxt-link-active">
Home
</a>
</li>
<li class="nav-item">
<a href="/nuxt-02/page1" target="_self" class="nav-link">
Page 1
</a>
</li>
<li class="nav-item">
<a href="/nuxt-02/page2" target="_self" class="nav-link">
Page 2
</a>
</li>
</ul>
</div> <div class="col-10">
<div role="alert" aria-live="polite" aria-atomic="true" class="alert alert-warning">
Home - value= 10
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>window.__NUXT__ = ....;</script>
<script src="/nuxt-02/_nuxt/runtime.js" defer></script>
<script src="/nuxt-02/_nuxt/commons.app.js" defer></script>
<script src="/nuxt-02/_nuxt/vendors.app.js" defer></script>
<script src="/nuxt-02/_nuxt/app.js" defer></script>
</body>
</html>
- Zeile 46: Auf der empfangenen Seite hatte [value] den Wert 10;
Schritt 2
Es ist bekannt, dass nach dem Empfang der Seite die Skripte in den Zeilen 57–60 die Kontrolle übernehmen und das Verhalten der empfangenen Seite sowie die angezeigten Informationen, wie hier zu sehen, verändern. Diese Skripte bilden den Client, der ebenfalls den Code der Seite [index] ausführt – denselben Code wie der Server:
export default {
name: 'Home',
// verwendete Komponenten
components: {
Layout,
Navigation
},
data() {
return {
value: 0
}
},
// Lebenszyklus
beforeCreate() {
// Client und Server
console.log('[home beforeCreate]')
},
created() {
// Client und Server
console.log('[home created]')
// nur Server
if (process.server) {
this.value = 10
}
// Client und Server
console.log('value=', this.value)
},
beforeMount() {
// nur Client
console.log('[home beforeMount]')
},
mounted() {
// nur Client
console.log('[home mounted]')
}
}
- Um zu verstehen, was hier geschieht, muss man wissen, dass der Client [nuxt] die Zeilen 22–24 nicht ausführt (process.server=false);
- In einer klassischen [vue]-Anwendung bleibt die Eigenschaft [value] in Zeile 10 auf 0 gesetzt. Deshalb wird der angezeigte Wert zu [0], sobald der Client die empfangene Seite aufgerufen hat;
Der vom Server generierte Wert [nuxt] für die Eigenschaft [value] war nutzlos.
5.2. Die Seite [page1]
5.2.1. Der Store [Vuex]
Wir haben dem Projekt [nuxt-02] einen Ordner [store] hinzugefügt:

Durch das Vorhandensein dieses Ordners wird automatisch von [nuxt] ein Store namens [Vuex] implementiert. Es ist die Datei [index.js], die diesen Speicher implementiert. Hier lautet die Datei [index.js] wie folgt:
export const state = () => ({
counter: 0
})
export const mutations = {
increment(state, inc) {
state.counter += inc
}
}
[nuxt] implementiert einen Store [Vuex] anhand des Inhalts von [index.js]:
- Zeilen 1–3: Definition des Status [state] des Stores. Dieser Status wird von einer Funktion zurückgegeben. Hier hat der Status nur eine Eigenschaft, den Zähler in Zeile 2. Die exportierte Funktion muss [state] heißen;
- Zeilen 5–9: Die möglichen Operationen auf den Status des Stores. Sie werden als [mutations] bezeichnet. Hier ermöglicht die Mutation [increment], die Eigenschaft [counter] um den Wert [inc] zu erhöhen. Das exportierte Objekt muss den Namen [mutations] tragen;
Die von [nuxt] implementierte Ansicht [store] ist an verschiedenen Stellen verfügbar. In den Ansichten ist sie in der Eigenschaft [this.$store] verfügbar.
5.2.2. Der Code der Seite
Genau wie die Seite [index] zeigt auch die Seite [page1] einen Wert an, nämlich den des Vuex-Store-Zählers:
<!-- Seite 1 -->
<template>
<Layout :left="true" :right="true">
<!-- Navigation -->
<Navigation slot="left" />
<!-- Meldung-->
<b-alert slot="right" show variant="primary"> Page 1 - value = {{ value }} </b-alert>
</Layout>
</template>
<script>
/* eslint-disable no-console */
import Navigation from '@/components/navigation'
import Layout from '@/components/layout'
export default {
name: 'Page1',
// verwendete Komponenten
components: {
Layout,
Navigation
},
data() {
return {
value: 0
}
},
// Lebenszyklus
beforeCreate() {
// Client und Server
console.log('[home beforeCreate]')
},
created() {
// Client und Server
console.log('[home created]')
// nur Server
if (process.server) {
this.$store.commit('increment', 25)
}
// Client und Server
this.value = this.$store.state.counter
console.log('value=', this.value)
},
beforeMount() {
// nur Client
console.log('[home beforeMount]')
},
mounted() {
// nur Client
console.log('[home mounted]')
}
}
</script>
Kommentare
- Zeilen 38–40: Der Server erhöht den Zähler um 25;
- Zeile 42: Sowohl der Server als auch der Client zeigen den Wert des Zählers an;
- Zeile 7: Der Zählerstand wird angezeigt;
Beim Lesen dieses Codes muss man zwei Dinge beachten:
- Der ausgeführte Code ist für den Server derselbe wie für den Client;
- das Objekt „[this]“ ist jedoch nicht dasselbe: Es gibt eine serverseitige Version „[this]“ und eine clientseitige Version „[client]“;
Wir wollen herausfinden, ob das [this.$store] auf dem Server mit dem [this.$store] auf dem Client identisch ist. Da der Server als Erstes ausgeführt wird (beim Start der Anwendung), läuft dies auf folgende Frage hinaus: Wird das vom Server initialisierte [store] an den Client übertragen?
5.2.3. Ausführung
Wir führen das Projekt [nuxt-02] aus und geben manuell [localhost:81/nuxt-02/page1] ein, damit der Server aufgerufen wird. Wie beim Start der Seite [index]:
- führt der Server die Seite [page1.vue] aus;
- sendet die generierte Seite an den Browser. Diese wird angezeigt;
- die in der gesendeten Seite eingebetteten Client-Skripte übernehmen die Kontrolle und führen erneut die Seite „[page1.vue]“ aus;
- die angezeigte Seite wird daraufhin geändert;
Das Endergebnis sieht wie folgt aus:

Diesmal entspricht der angezeigte Wert tatsächlich dem vom Server festgelegten, und optisch ist kein „Ruckeln“ der Seite zu erkennen, das durch eine vom Client vorgenommene Änderung des vom Server angezeigten Werts verursacht wird. Was ist diesmal passiert?
Der Server hat die folgende Seite „[page1]“ ausgeführt:
...
<script>
/* eslint-disable no-console */
import Navigation from '@/components/navigation'
import Layout from '@/components/layout'
export default {
name: 'Page1',
// verwendete Komponenten
components: {
Layout,
Navigation
},
data() {
return {
value: 0
}
},
// Lebenszyklus
beforeCreate() {
// Client und Server
console.log('[page1 beforeCreate]')
},
created() {
// Client und Server
console.log('[page1 created]')
// nur Server
if (process.server) {
this.$store.commit('increment', 25)
}
// Client und Server
this.value = this.$store.state.counter
console.log('value=', this.value)
},
beforeMount() {
// nur Client
console.log('[page1 beforeMount]')
},
mounted() {
// nur Client
console.log('[page1 mounted]')
}
}
</script>
- Die Zeilen 30–32 wurden fehlerfrei ausgeführt. Das bedeutet, dass auch serverseitig [this.$store] auf das Speicherelement [Vuex] verweist. In Zeile 31 wurde der Zähler des Speicherelements auf 25 gesetzt;
- anschließend wurde die Seite an den Client gesendet;
Betrachtet man die vom Client empfangene Seite, so findet man folgende Elemente:
<!doctype html>
<html data-n-head-ssr>
<head>
<title>Introduction à [nuxt.js]</title>
<meta data-n-head="ssr" charset="utf-8">
<meta data-n-head="ssr" name="viewport" content="width=device-width, initial-scale=1">
<meta data-n-head="ssr" data-hid="description" name="description" content="ssr routing loading asyncdata middleware plugins store">
<link data-n-head="ssr" rel="icon" type="image/x-icon" href="/favicon.ico">
<base href="/nuxt-02/">
<link rel="preload" href="/nuxt-02/_nuxt/runtime.js" as="script">
<link rel="preload" href="/nuxt-02/_nuxt/commons.app.js" as="script">
<link rel="preload" href="/nuxt-02/_nuxt/vendors.app.js" as="script">
<link rel="preload" href="/nuxt-02/_nuxt/app.js" as="script">
...
</head>
<body>
<div data-server-rendered="true" id="__nuxt">
<div id="__layout">
<div class="container">
<div class="card">
<div class="card-body">
<div role="alert" aria-live="polite" aria-atomic="true" align="center" class="alert alert-success">
<h4>[nuxt-02] : page serveur, page client</h4>
</div>
<div>
<div class="row">
<div class="col-2">
<ul class="nav flex-column">
<li class="nav-item">
<a href="/nuxt-02/" target="_self" class="nav-link">
Home
</a>
</li>
<li class="nav-item">
<a href="/nuxt-02/page1" target="_self" class="nav-link active nuxt-link-active">
Page 1
</a>
</li>
<li class="nav-item">
<a href="/nuxt-02/page2" target="_self" class="nav-link">
Page 2
</a>
</li>
</ul>
</div> <div class="col-10">
<div role="alert" aria-live="polite" aria-atomic="true" class="alert alert-primary">
Page 1 - value = 25
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
window.__NUXT__ = (function (a, b, c) {
return {
layout: "default", data: [{}], error: null, state: { counter: 25 }, serverRendered: true,
logs: [
{ date: new Date(1574085336802), args: ["[home beforeCreate]"], type: a, level: b, tag: c },
{ date: new Date(1574085336839), args: ["[home created]"], type: a, level: b, tag: c },
{ date: new Date(1574085336869), args: ["value=", "25"], type: a, level: b, tag: c }
]
}
}("log", 2, ""));</script>
<script src="/nuxt-02/_nuxt/runtime.js" defer></script>
<script src="/nuxt-02/_nuxt/commons.app.js" defer></script>
<script src="/nuxt-02/_nuxt/vendors.app.js" defer></script>
<script src="/nuxt-02/_nuxt/app.js" defer></script>
</body>
</html>
- Zeile 47: der vom Server gesendete Wert;
- Zeile 60: Man stellt fest, dass der Status des Speichers [Vuex] in die Seite eingebettet wurde. Dies ermöglicht es dem Client, der nach dem Empfang der Seite ausgeführt wird, einen neuen Speicher [Vuex] mit 25 als Anfangswert des Zählers zu rekonstruieren;
Nach dem Empfang und der Anzeige der vom Server empfangenen Seite übernimmt der Client die Kontrolle und führt seinerseits die Seite [page1] aus:
...
<script>
/* eslint-disable no-console */
import Navigation from '@/components/navigation'
import Layout from '@/components/layout'
export default {
name: 'Page1',
// verwendete Komponenten
components: {
Layout,
Navigation
},
data() {
return {
value: 0
}
},
// Lebenszyklus
beforeCreate() {
// Client und Server
console.log('[page1 beforeCreate]')
},
created() {
// Client und Server
console.log('[page1 created]')
// nur Server
if (process.server) {
this.$store.commit('increment', 25)
}
// Client und Server
this.value = this.$store.state.counter
console.log('value=', this.value)
},
beforeMount() {
// nur Client
console.log('[page1 beforeMount]')
},
mounted() {
// nur Client
console.log('[page1 mounted]')
}
}
</script>
- Zeile 34: Die Eigenschaft [value] aus Zeile 18 erhält nun ebenfalls den Wert 25 des Zählers;
Der Speicher von [nuxt] ermöglicht es dem Server somit, beim ersten Laden der Seite, wenn diese auf dem Server abgerufen wird, Informationen an den Client zu übermitteln. Es sei daran erinnert, dass der Server, sobald diese Seite abgerufen wurde, nicht mehr angefragt wird und die Anwendung wie eine klassische [vue]-Anwendung im SAP-Modus funktioniert.
5.3. Die Seite [page2]
Auf der Seite [page2] zeigen wir eine weitere Möglichkeit, wie
- der Server berechnete Informationen in die Seite einbindet;
- der Client diese nicht verändert;
5.3.1. Der Code der Seite
Der Code der Seite [page2] entwickelt sich wie folgt weiter:
<!-- Seite 2 -->
<template>
<Layout :left="true" :right="true">
<!-- Navigation -->
<Navigation slot="left" />
<!-- Meldung -->
<b-alert slot="right" show variant="secondary"> Page 2 - value = {{ value }} </b-alert>
</Layout>
</template>
<script>
/* eslint-disable no-console */
/* eslint-disable nuxt/no-timing-in-fetch-data */
import Navigation from '@/components/navigation'
import Layout from '@/components/layout'
export default {
name: 'Page2',
// verwendete Komponenten
components: {
Layout,
Navigation
},
asyncData(context) {
// Wer führt diesen Code aus?
console.log('asyncData, client=', process.client, 'serveur=', process.server)
// nur für den Server
if (process.server) {
// Es wird ein Promise zurückgegeben
return new Promise(function(resolve, reject) {
// Normalerweise gibt es hier eine asynchrone Funktion
// Wir simulieren sie mit einer Wartezeit von einer Sekunde
setTimeout(() => {
// Dieses Ergebnis wird in die Eigenschaften von [data] aufgenommen
resolve({ value: 87 })
// Protokoll
console.log('asynData terminée')
}, 1000)
})
}
},
// Lebenszyklus
beforeCreate() {
// Client und Server
console.log('[page2 beforeCreate]')
},
created() {
// Client und Server
console.log('[page2 created]')
},
beforeMount() {
// nur Client
console.log('[page2 beforeMount]')
},
mounted() {
// nur Client
console.log('[page2 mounted]')
}
}
</script>
- Zeile 7: Die Seite zeigt den Wert einer Eigenschaft namens [value] an;
- Die Eigenschaft [value] existiert nicht als Element eines Objekts, das von der Funktion [data] zurückgegeben wird. Diese Funktion existiert hier nicht. Die Eigenschaft [value] wird dynamisch in Zeile 36 erstellt;
- Zeile 25: Die Funktion [asyncData] ist eine Funktion [nuxt]. Wie der Name schon sagt, handelt es sich dabei normalerweise um eine asynchrone Funktion. Ihre übliche Aufgabe besteht darin, externe Daten abzurufen. [nuxt] stellt sicher, dass die Seite nicht an den Client-Browser gesendet wird, bevor die Funktion [asyncData] ihre asynchronen Daten zurückgegeben hat;
- Die Funktion [asyncData] erhält als Parameter den Kontext [nuxt]. Dieses Objekt ist sehr umfangreich und bietet Zugriff auf zahlreiche Informationen über die Nuxt-Anwendung. Wir werden dies in den folgenden Abschnitten näher betrachten;
- Zeile 31: Wir implementieren die Funktion [asyncData] mit einem [Promise] (siehe Dokument |Einführung in die Sprache ECMASCRIPT 6 anhand eines Beispiels|). Der Konstruktor dieser Klasse akzeptiert als Parameter eine asynchrone Funktion, die:
- einen Erfolg signalisiert, indem sie Daten mit der Funktion [resolve] zurückgibt. Das von dieser Funktion zurückgegebene Objekt wird automatisch in die Eigenschaften [data] der Seite aufgenommen;
- einen Fehler meldet, indem er mit der Funktion [reject] einen Fehler zurückgibt;
- Zeile 34: Mit der Funktion [setTimeout] wird eine asynchrone Funktion simuliert. Diese Funktion gibt das Objekt [{ value: 87 }] (Zeile 36) nach einer Sekunde (Zeile 31) zurück, und zwar mithilfe der Funktion [resolve], die den Erfolg der Funktion [Promise] signalisiert. Das von der asynchronen Funktion zurückgegebene Objekt wird automatisch in die Eigenschaften [data] der Seite aufgenommen. Und genau diese Eigenschaft wird in Zeile 7 angezeigt;
- Zeile 27: Wir werden sehen, dass die Funktion [asyncData] vom Server, nicht jedoch vom Client ausgeführt wird;
- Zeile 29: Die Initialisierung der Eigenschaft [value] erfolgt durch den Server;
Hinweis: Das Objekt [this] ist in der Funktion [asyncData] nicht bekannt, da das Objekt, das die Komponente [vue] kapselt, noch nicht erstellt wurde;
5.3.2. Ausführung
Das Projekt [nuxt-02] wird ausgeführt, und man gibt [localhost:81/nuxt-02/page2] manuell ein, damit der Server aufgerufen wird. Wie beim Start der Seite [index]:
- führt der Server die Seite [page2.vue] aus;
- sendet die generierte Seite an den Browser. Diese wird angezeigt;
- die in der gesendeten Seite eingebetteten Client-Skripte übernehmen die Kontrolle und führen erneut die Seite „[page2.vue]“ aus;
- die angezeigte Seite wird daraufhin geändert;
Das Endergebnis sieht wie folgt aus:

Diesmal entspricht der angezeigte Wert tatsächlich dem vom Server festgelegten, und optisch ist kein „Ruckeln“ der Seite zu erkennen, das durch eine vom Client vorgenommene Änderung des vom Server angezeigten Werts verursacht wird. Was ist diesmal passiert?
Der Server hat die folgende Seite „[page2]“ ausgeführt:
<!-- Seite 2 -->
<template>
<Layout :left="true" :right="true">
<!-- Navigation -->
<Navigation slot="left" />
<!-- Meldung -->
<b-alert slot="right" show variant="secondary"> Page 2 - value = {{ value }} </b-alert>
</Layout>
</template>
<script>
/* eslint-disable no-console */
/* eslint-disable nuxt/no-timing-in-fetch-data */
import Navigation from '@/components/navigation'
import Layout from '@/components/layout'
export default {
name: 'Page2',
// verwendete Komponenten
components: {
Layout,
Navigation
},
asyncData(context) {
// Wer führt diesen Code aus?
console.log('asyncData, client=', process.client, 'serveur=', process.server)
// nur für den Server
if (process.server) {
// Es wird ein Promise zurückgegeben
return new Promise(function(resolve, reject) {
// Normalerweise gibt es hier eine asynchrone Funktion
// Wir simulieren sie mit einer Wartezeit von einer Sekunde
setTimeout(() => {
// Dieses Ergebnis wird in die Eigenschaften von [data] aufgenommen
resolve({ value: 87 })
// Protokoll
console.log('asynData terminée')
}, 1000)
})
}
},
// Lebenszyklus
beforeCreate() {
// Client und Server
console.log('[page2 beforeCreate]')
},
created() {
// Client und Server
console.log('[page2 created]')
},
beforeMount() {
// nur Client
console.log('[page2 beforeMount]')
},
mounted() {
// nur Client
console.log('[page2 mounted]')
}
}
</script>
In Zeile 36 wurde der in Zeile 7 angezeigte Wert festgelegt. Genau das hat der Client-Browser also erhalten. Genauer gesagt erhält er die folgende Seite:
<!doctype html>
<html data-n-head-ssr>
<head>
<title>Introduction à [nuxt.js]</title>
<meta data-n-head="ssr" charset="utf-8">
<meta data-n-head="ssr" name="viewport" content="width=device-width, initial-scale=1">
<meta data-n-head="ssr" data-hid="description" name="description" content="ssr routing loading asyncdata middleware plugins store">
<link data-n-head="ssr" rel="icon" type="image/x-icon" href="/favicon.ico">
<base href="/nuxt-02/">
<link rel="preload" href="/nuxt-02/_nuxt/runtime.js" as="script">
<link rel="preload" href="/nuxt-02/_nuxt/commons.app.js" as="script">
<link rel="preload" href="/nuxt-02/_nuxt/vendors.app.js" as="script">
<link rel="preload" href="/nuxt-02/_nuxt/app.js" as="script">
...
</head>
<body>
<div data-server-rendered="true" id="__nuxt">
<div id="__layout">
<div class="container">
<div class="card">
<div class="card-body">
<div role="alert" aria-live="polite" aria-atomic="true" align="center" class="alert alert-success">
<h4>[nuxt-02] : page serveur, page client</h4>
</div>
<div>
<div class="row">
<div class="col-2">
<ul class="nav flex-column">
<li class="nav-item">
<a href="/nuxt-02/" target="_self" class="nav-link">
Home
</a>
</li>
<li class="nav-item">
<a href="/nuxt-02/page1" target="_self" class="nav-link">
Page 1
</a>
</li>
<li class="nav-item">
<a href="/nuxt-02/page2" target="_self" class="nav-link active nuxt-link-active">
Page 2
</a>
</li>
</ul>
</div>
<div class="col-10">
<div role="alert" aria-live="polite" aria-atomic="true" class="alert alert-secondary">
Page 2 - value = 87
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
window.__NUXT__ = (function (a, b, c) {
return {
layout: "default", data: [{ value: 87 }], error: null, state: { counter: 0 }, serverRendered: true,
logs: [
{ date: new Date(1574096608555), args: ["asyncData, client=", "false", "serveur=", "true"], type: a, level: b, tag: c },
{ date: new Date(1574096608575), args: ["[page2 beforeCreate]"], type: a, level: b, tag: c },
{ date: new Date(1574096608599), args: ["[page2 created]"], type: a, level: b, tag: c }
]
}
}("log", 2, ""));</script>
<script src="/nuxt-02/_nuxt/runtime.js" defer></script>
<script src="/nuxt-02/_nuxt/commons.app.js" defer></script>
<script src="/nuxt-02/_nuxt/vendors.app.js" defer></script>
<script src="/nuxt-02/_nuxt/app.js" defer></script>
</body>
</html>
- Zeile 48: Man sieht, dass der Wert auf der empfangenen Seite 87 ist;
- Zeile 61: In der Antwort des Servers sind zwei Objekte zu sehen: [data] und [state]:
- [state] ist der Status des Stores [Vuex]. Dieser wurde anhand des Inhalts des Ordners [store] der Anwendung [nuxt-02] instanziiert;
- [data] enthält die vom Server mithilfe der Funktion [asyncData] erstellten Eigenschaften. Hier finden wir die vom Server erstellte Eigenschaft [value : 87]. Die Client-Skripte werden diese Eigenschaft in die Eigenschaften der Seite [page2] integrieren;
Kehren wir zum Code der Seite [page2] zurück:
<!-- Seite 2 -->
<template>
<Layout :left="true" :right="true">
<!-- Navigation -->
<Navigation slot="left" />
<!-- Meldung -->
<b-alert slot="right" show variant="secondary"> Page 2 - value = {{ value }} </b-alert>
</Layout>
</template>
<script>
/* eslint-disable no-console */
/* eslint-disable nuxt/no-timing-in-fetch-data */
import Navigation from '@/components/navigation'
import Layout from '@/components/layout'
export default {
name: 'Page2',
// verwendete Komponenten
components: {
Layout,
Navigation
},
asyncData(context) {
// Wer führt diesen Code aus?
console.log('asyncData, client=', process.client, 'serveur=', process.server)
// nur für den Server
if (process.server) {
// Es wird ein Promise zurückgegeben
return new Promise(function(resolve, reject) {
// Normalerweise gibt es hier eine asynchrone Funktion
// man simuliert sie mit einer Wartezeit von einer Sekunde
setTimeout(() => {
// Dieses Ergebnis wird in die Eigenschaften von [data] aufgenommen
resolve({ value: 87 })
// Protokoll
console.log('asynData terminée')
}, 1000)
})
}
},
// Lebenszyklus
beforeCreate() {
// Client und Server
console.log('[page2 beforeCreate]')
},
created() {
// Client und Server
console.log('[page2 created]')
},
beforeMount() {
// nur Client
console.log('[page2 beforeMount]')
},
mounted() {
// nur Client
console.log('[page2 mounted]')
}
}
</script>
- In Zeile 7 wird die Eigenschaft [value] verwendet. Die Seite definiert jedoch keine Eigenschaft mit dem Namen [value]. Die Client-Skripte haben diese Eigenschaft jedoch automatisch anhand des vom Server empfangenen Objekts [data: [{ value: 87 }]] erstellt;
Die Protokolle zeigen außerdem, dass die Funktion [asyncData] vom Client nicht ausgeführt wurde:

Die Funktion [asyncData] wurde vom Server [1] ausgeführt, jedoch nicht vom Client [2]. Außerdem ist festzustellen, dass die Lebenszyklusfunktionen vom Server erst nach Beendigung der Funktion [asyncData] ausgeführt werden. Um dies zu überprüfen, kann die Wartezeit innerhalb der Funktion [asyncData] verlängert werden.
5.4. Die Seite [page3]
Wir fügen unserer Anwendung eine neue Seite [page3] hinzu:

5.4.1. Die Komponente [navigation]
Die Komponente [vavigation] wird geändert, um die Navigation zur neuen Seite zu ermöglichen:
<template>
<!-- Bootstrap-Menü mit drei Optionen -->
<b-nav vertical>
<b-nav-item to="/" exact exact-active-class="active">
Home
</b-nav-item>
<b-nav-item to="/page1" exact exact-active-class="active">
Page 1
</b-nav-item>
<b-nav-item to="/page2" exact exact-active-class="active">
Page 2
</b-nav-item>
<b-nav-item to="/page3" exact exact-active-class="active">
Page 3
</b-nav-item>
</b-nav>
</template>
5.4.2. Der Code von [page3]
Der Code der Seite [page3] lautet wie folgt:
<!-- Seite 3 -->
<template>
<Layout :left="true" :right="true">
<!-- Navigation -->
<Navigation slot="left" />
<!-- Meldung -->
<b-alert slot="right" show variant="secondary"> Page 3 - value = {{ value }} </b-alert>
</Layout>
</template>
<script>
/* eslint-disable no-console */
/* eslint-disable nuxt/no-timing-in-fetch-data */
import Navigation from '@/components/navigation'
import Layout from '@/components/layout'
export default {
name: 'Page3',
// verwendete Komponenten
components: {
Layout,
Navigation
},
data() {
return {
value: 0
}
},
fetch(context) {
// Wer führt diesen Code aus?
console.log('fetch, client=', process.client, 'serveur=', process.server)
// nur für den Server
if (process.server) {
// Es wird ein Promise zurückgegeben
return new Promise(function(resolve, reject) {
// Normalerweise handelt es sich hier um eine asynchrone Funktion
// man simuliert sie mit einer Wartezeit von einer Sekunde
setTimeout(() => {
// Erfolg
resolve()
}, 1000)
}).then(() => {
// Der Speicher wird geändert
context.store.commit('increment', 28)
})
}
},
// Lebenszyklus
beforeCreate() {
// Client und Server
console.log('[page3 beforeCreate]')
},
created() {
// Client und Server
this.value = this.$store.state.counter
console.log('[page3 created], value=', this.value)
},
beforeMount() {
// nur Client
console.log('[page3 beforeMount]')
},
mounted() {
// nur Client
console.log('[page3 mounted]')
}
}
</script>
- Zeile 30: Die Funktion [fetch] verhält sich analog zur Funktion [asyncData]:
- Sie wird vor den Funktionen des Lebenszyklus ausgeführt;
- das Objekt [this] ist in dieser Funktion nicht bekannt;
- sie arbeitet asynchron;
- der Lebenszyklus beginnt erst, wenn die asynchrone Funktion ihr Ergebnis zurückgegeben hat;
- das Ergebnis wird hier über die Methode [then] von [Promise], Zeile 43, zurückgegeben;
- Die Funktion [fetch] erhält den Parameter [context]. Dieser repräsentiert den aktuellen Kontext [nuxt];
- Zeile 30: Unter seinen zahlreichen Eigenschaften verfügt das Objekt [context] über eine Eigenschaft [store], die den Store [Vuex] der Anwendung darstellt;
- Zeile 41: Künstlich wird nach einer Sekunde der Erfolg von [Promise] gemeldet (siehe Dokument |Einführung in die Sprache ECMASCRIPT 6 anhand eines Beispiels|);
- Zeile 45: Die Methode [then] wird daraufhin ausgeführt. Dort wird der Zähler des [store] erhöht;
5.4.3. Ausführung
Das Projekt [nuxt-02] wird ausgeführt, und man gibt [localhost:81/nuxt-02/page3] manuell ein, um den Server anzufordern. Wie beim Start der Seite [index]:
- führt der Server die Seite [page3.vue] aus;
- sendet die generierte Seite an den Browser. Diese wird angezeigt;
- die in der gesendeten Seite eingebetteten Client-Skripte übernehmen die Kontrolle und führen erneut die Seite „[page3.vue]“ aus;
- die angezeigte Seite wird daraufhin geändert;
Das Endergebnis sieht wie folgt aus:

Der angezeigte Wert entspricht tatsächlich dem vom Server festgelegten Wert, und optisch ist kein „Ruckeln“ der Seite zu erkennen, das durch eine vom Client vorgenommene Änderung des vom Server angezeigten Werts verursacht würde. Was ist diesmal passiert?
Der Server hat die folgende Seite [page3] ausgeführt:
<!-- Seite 3 -->
<template>
<Layout :left="true" :right="true">
<!-- Navigation -->
<Navigation slot="left" />
<!-- Meldung -->
<b-alert slot="right" show variant="secondary"> Page 3 - value = {{ value }} </b-alert>
</Layout>
</template>
<script>
/* eslint-disable no-console */
/* eslint-disable nuxt/no-timing-in-fetch-data */
import Navigation from '@/components/navigation'
import Layout from '@/components/layout'
export default {
name: 'Page3',
// verwendete Komponenten
components: {
Layout,
Navigation
},
data() {
return {
value: 0
}
},
fetch(context) {
// Wer führt diesen Code aus?
console.log('fetch, client=', process.client, 'serveur=', process.server)
// nur für den Server
if (process.server) {
// Es wird ein Promise zurückgegeben
return new Promise(function(resolve, reject) {
// Normalerweise gibt es hier eine asynchrone Funktion
// Wir simulieren sie mit einer Wartezeit von einer Sekunde
setTimeout(() => {
// Erfolg
resolve()
}, 1000)
}).then(() => {
// Der Speicher wird geändert
context.store.commit('increment', 28)
// Protokoll
console.log('fetch commit terminé')
})
}
},
// Lebenszyklus
beforeCreate() {
// Client und Server
console.log('[page3 beforeCreate]')
},
created() {
// Client und Server
this.value = this.$store.state.counter
console.log('[page3 created], value=', this.value)
},
beforeMount() {
// nur Client
console.log('[page3 beforeMount]')
},
mounted() {
// nur Client
console.log('[page3 mounted]')
}
}
</script>
- Zeile 45: Die asynchrone Funktion [fetch] ist die erste der oben genannten Funktionen, die ausgeführt wird. Sie erhält als Parameter ein Objekt namens [context], bei dem es sich um den aktuellen Kontext [nuxt] handelt. Unter den zahlreichen Eigenschaften dieses Objekts stellt die Eigenschaft [context.store] den Speicher [Vuex] dar;
- Zeile 45: In der asynchronen Funktion [fetch] setzt der Server den Zähler des Speichers auf 28;
- Zeile 56: Wenn die Funktion [created] ausgeführt wird, stellt [nuxt] sicher, dass die asynchrone Funktion [fetch] ihre Arbeit beendet hat;
- Zeile 58: Der Wert des Zählers der Jalousie wird der Eigenschaft [value] aus Zeile 27 zugewiesen;
- Zeile 7: Anzeige des Werts von [value], also des Zählers des Stores;
Der Client-Browser erhält die folgende Seite:
<!doctype html>
<html data-n-head-ssr>
<head>
<title>Introduction à [nuxt.js]</title>
<meta data-n-head="ssr" charset="utf-8">
<meta data-n-head="ssr" name="viewport" content="width=device-width, initial-scale=1">
<meta data-n-head="ssr" data-hid="description" name="description" content="ssr routing loading asyncdata middleware plugins store">
<link data-n-head="ssr" rel="icon" type="image/x-icon" href="/favicon.ico">
<base href="/nuxt-02/">
<link rel="preload" href="/nuxt-02/_nuxt/runtime.js" as="script">
<link rel="preload" href="/nuxt-02/_nuxt/commons.app.js" as="script">
<link rel="preload" href="/nuxt-02/_nuxt/vendors.app.js" as="script">
<link rel="preload" href="/nuxt-02/_nuxt/app.js" as="script">
...
</head>
<body>
<div data-server-rendered="true" id="__nuxt">
<div id="__layout">
<div class="container">
<div class="card">
<div class="card-body">
<div role="alert" aria-live="polite" aria-atomic="true" align="center" class="alert alert-success">
<h4>[nuxt-02] : page serveur, page client</h4>
</div>
<div>
<div class="row">
<div class="col-2">
<ul class="nav flex-column">
<li class="nav-item">
<a href="/nuxt-02/" target="_self" class="nav-link">
Home
</a>
</li>
<li class="nav-item">
<a href="/nuxt-02/page1" target="_self" class="nav-link">
Page 1
</a>
</li>
<li class="nav-item">
<a href="/nuxt-02/page2" target="_self" class="nav-link">
Page 2
</a>
</li>
<li class="nav-item">
<a href="/nuxt-02/page3" target="_self" class="nav-link active nuxt-link-active">
Page 3
</a>
</li>
</ul>
</div> <div class="col-10">
<div role="alert" aria-live="polite" aria-atomic="true" class="alert alert-secondary">
Page 3 - value = 28
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
window.__NUXT__ = (function (a, b, c) {
return {
layout: "default", data: [{}], error: null, state: { counter: 28 }, serverRendered: true,
logs: [
{ date: new Date(1574169916025), args: ["fetch, client=", "false", "serveur=", "true"], type: a, level: b, tag: c },
{ date: new Date(1574169917038), args: ["fetch commit terminé"], type: a, level: b, tag: c },
{ date: new Date(1574169917137), args: ["[page3 beforeCreate]"], type: a, level: b, tag: c },
{ date: new Date(1574169917167), args: ["[page3 created], value=", "28"], type: a, level: b, tag: c }
]
}
}("log", 2, ""));</script>
<script src="/nuxt-02/_nuxt/runtime.js" defer></script>
<script src="/nuxt-02/_nuxt/commons.app.js" defer></script>
<script src="/nuxt-02/_nuxt/vendors.app.js" defer></script>
<script src="/nuxt-02/_nuxt/app.js" defer></script>
</body>
</html>
- Zeile 52: Man sieht, dass der Wert auf der empfangenen Seite 28 beträgt;
- Zeile 65: In der Antwort des Servers ist zu sehen, dass der Server dem Client den Status [state] des Speichers [Vuex] gesendet hat. Anhand dieser Information können die Client-Skripte einen Speicher [Vuex] rekonstruieren;
Die Client-Skripte führen ihrerseits den Code der Seite [page3] aus:
<!-- Seite 3 -->
<template>
<Layout :left="true" :right="true">
<!-- Navigation -->
<Navigation slot="left" />
<!-- Meldung -->
<b-alert slot="right" show variant="secondary"> Page 3 - value = {{ value }} </b-alert>
</Layout>
</template>
<script>
/* eslint-disable no-console */
/* eslint-disable nuxt/no-timing-in-fetch-data */
import Navigation from '@/components/navigation'
import Layout from '@/components/layout'
export default {
name: 'Page3',
// verwendete Komponenten
components: {
Layout,
Navigation
},
data() {
return {
value: 0
}
},
fetch(context) {
// Wer führt diesen Code aus?
console.log('fetch, client=', process.client, 'serveur=', process.server)
// nur für den Server
if (process.server) {
// Es wird ein Promise zurückgegeben
return new Promise(function(resolve, reject) {
// Normalerweise gibt es hier eine asynchrone Funktion
// man simuliert sie mit einer Wartezeit von einer Sekunde
setTimeout(() => {
// Erfolg
resolve()
}, 1000)
}).then(() => {
// Der Speicher wird geändert
context.store.commit('increment', 28)
// Protokoll
console.log('fetch commit terminé')
})
}
},
// Lebenszyklus
beforeCreate() {
// Client und Server
console.log('[page3 beforeCreate]')
},
created() {
// Client und Server
this.value = this.$store.state.counter
console.log('[page3 created], value=', this.value)
},
beforeMount() {
// nur Client
console.log('[page3 beforeMount]')
},
mounted() {
// nur Client
console.log('[page3 mounted]')
}
}
</script>
- Zeile 58: Die vom Client ausgeführte Funktion [created] weist der Eigenschaft [value] in Zeile 27 den Wert des Zählers zu;
- in Zeile 7 wird dieser Wert angezeigt. Da er mit dem vom Server gesendeten Wert übereinstimmt, ist kein „Ruckeln“ der Seite aufgrund einer Änderung zu beobachten;
Die Protokolle zeigen außerdem, dass die Funktion [fetch] vom Client nicht ausgeführt wurde:

Die Funktion [fetch] wurde vom Server [1] ausgeführt, jedoch nicht vom Client [2]. Außerdem ist festzustellen, dass die Lebenszyklusfunktionen vom Server erst nach Beendigung der Funktion [fetch] [3] ausgeführt werden. Um dies zu überprüfen, kann die Wartezeit innerhalb der Funktion [fetch] verlängert werden.
Die Seiten [page1] und [page3] haben zwei Methoden gezeigt, bei denen der Speicher [Vuex] verwendet wird, um Informationen vom Server an den Client zu übertragen. Man kann sich fragen, ob diese Methoden gleichwertig sind. Wir erstellen eine Seite [page4], um dies zu überprüfen.
5.5. Die Seite [page4]
Wir fügen unserer Anwendung eine neue Seite [page4] hinzu:

5.5.1. Die Komponente [navigation]
Die Komponente [navigation] wird geändert, um die Navigation zur neuen Seite zu ermöglichen:
<template>
<!-- Bootstrap-Menü mit fünf Optionen -->
<b-nav vertical>
<b-nav-item to="/" exact exact-active-class="active">
Home
</b-nav-item>
<b-nav-item to="/page1" exact exact-active-class="active">
Page 1
</b-nav-item>
<b-nav-item to="/page2" exact exact-active-class="active">
Page 2
</b-nav-item>
<b-nav-item to="/page3" exact exact-active-class="active">
Page 3
</b-nav-item>
<b-nav-item to="/page4" exact exact-active-class="active">
Page 4
</b-nav-item>
</b-nav>
</template>
5.5.2. Der Code von [page4]
Der Code der Seite [page4] lautet wie folgt:
<!-- Seite 4 -->
<template>
<Layout :left="true" :right="true">
<!-- Navigation -->
<Navigation slot="left" />
<!-- Meldung -->
<b-alert slot="right" show variant="secondary"> Page 4 - value = {{ value }} </b-alert>
</Layout>
</template>
<script>
/* eslint-disable no-console */
import Navigation from '@/components/navigation'
import Layout from '@/components/layout'
export default {
name: 'Page4',
// verwendete Komponenten
components: {
Layout,
Navigation
},
data() {
return {
value: 0
}
},
// Lebenszyklus
async beforeCreate() {
// Client und Server
console.log('[page4 beforeCreate]')
// nur für den Server
if (process.server) {
// Die asynchrone Funktion wird ausgeführt
const valeur = await new Promise(function(resolve, reject) {
// Normalerweise handelt es sich hier um eine asynchrone Funktion
// sie wird mit einer Wartezeit von 10 Sekunden simuliert
setTimeout(() => {
// Erfolg – der Wert des Zählers wird zurückgegeben
resolve(52)
}, 10000)
})
// Man ändert den Speicher
this.$store.commit('increment', valeur)
// Protokoll
console.log('[page4 beforeCreate], fonction asynchrone terminée, compteur=', this.$store.state.counter)
}
},
created() {
// Client und Server
this.value = this.$store.state.counter
console.log('[page4 created], value=', this.value)
},
beforeMount() {
// nur Client
console.log('[page4 beforeMount]')
},
mounted() {
// nur Client
console.log('[page4 mounted]')
}
}
</script>
- Zeile 30: Was zuvor in der Funktion [fetch] ausgeführt wurde, erfolgt nun in der Methode [beforeCreate]. Es wird das Paar „async“ (Zeile 30) und „await“ (Zeile 36) verwendet, um das Ende der asynchronen Funktion abzuwarten;
- Zeile 36: Das Ergebnis der asynchronen Funktion wird in Zeile 41 nach 10 Sekunden (Zeile 42) abgerufen;
- Zeilen 50–54: In der Methode [created], die sowohl serverseitig als auch clientseitig ausgeführt wird, wird der Zähler der Eigenschaft [value] der Seite zugewiesen;
5.5.3. Ausführung
Das Projekt [nuxt-02] wird ausgeführt, und [localhost:81/nuxt-02/page4] wird manuell eingegeben, um den Server anzufordern. Wie beim Start der Seite [index]:
- führt der Server die Seite [page4.vue] aus;
- sendet die generierte Seite an den Browser. Diese wird angezeigt;
- die in der gesendeten Seite eingebetteten Client-Skripte übernehmen die Kontrolle und führen erneut die Seite „[page4.vue]“ aus;
- die angezeigte Seite wird daraufhin geändert;
Das Endergebnis sieht wie folgt aus:

Entgegen den Erwartungen ist der in [2] angezeigte Wert nicht 52. Was ist passiert?
Die Logs lauten wie folgt:

Es fällt auf, dass in [1] das Protokoll zum Abschluss der asynchronen Aktion nicht angezeigt wurde. Die Funktion [created], die den Wert des Zählers anzeigt, gibt 0 aus. All dies lässt vermuten, dass [nuxt] nicht auf das Ende der asynchronen Aktion gewartet hat.
Kehrt man zum Terminal von VSCode zurück, das zum Starten der Anwendung verwendet wurde, findet man die Protokolle von [3-4]. Daraus geht hervor, dass die asynchrone Funktion serverseitig tatsächlich ausgeführt wurde.
Letztendlich wurde die Funktion [beforeCreate] zwar vollständig serverseitig ausgeführt, aber [nuxt] hat nicht auf das Ende ihrer Ausführung gewartet, um die Seite an den Client-Browser zu senden, während es sehr wohl auf das Ende der Funktion [fetch] wartet. Diese Methode muss daher verwendet werden, wenn der Server einen Store [Vuex] initialisieren soll.
5.6. Navigation in der Anwendung [vue]
Wir haben gezeigt, was passiert, wenn jede der Seiten [index, page1, page2, page3, page4] zunächst vom Server geladen wird. In der Praxis ist dies jedoch nicht der Fall: Im Normalbetrieb wird nur die Seite [index] auf dem Server abgerufen. Sehen wir uns die drei Seiten in diesem Fall an:
Seite [index]

Dieses Ergebnis haben wir bereits im Abschnitt „Link“ erläutert.
Klicken wir nun auf den Link [Page 1]:

Der angezeigte Wert ist 0. Er betrug 25, als die Seite zunächst durch manuelle Eingabe der Adresse URL vom Server angefordert wurde. Die Erklärung ist einfach. Der ausgeführte Code lautet wie folgt:
created() {
// Client und Server
console.log('[page1 created]')
// nur Server
if (process.server) {
this.$store.commit('increment', 25)
}
// Client und Server
this.value = this.$store.state.counter
console.log('value=', this.value)
},
In Zeile 6 wurde der Zähler auf 25 gesetzt. Da die Seite nicht vom Server angefordert wurde, wurden die Zeilen 5–7 nicht ausgeführt, und der Zähler im Speicher [Vuex] blieb bei 0.
Klicken wir nun auf den Link [Page 2]:

Diesmal wird kein Wert angezeigt, und außerdem erscheint eine Warnung in den Konsolenprotokollen:

- Bei [1] stellen wir fest, dass die Funktion [asyncData] vom Client ausgeführt wurde. Es ist immer so:
- Sie wird vom Server ausgeführt, wenn die Seite vom Server angefordert wird. In diesem Fall wird sie nicht vom Client ausgeführt;
- jedes Mal, wenn die Seite das Ziel der aktuellen Route des Clients ist;
- in [2]: [nuxt] gibt eine Warnung aus, da in der Vorlage der Seite ein reaktiver Ausdruck {{ value }} vorhanden ist, die Seite jedoch keine Eigenschaft [value] besitzt;
Zur Erinnerung: Der vom Client ausgeführte Code lautet:
asyncData() {
// Wer führt diesen Code aus?
console.log('asyncData, client=', process.client, 'serveur=', process.server)
// nur für den Server
if (process.server) {
// Es wird ein Promise zurückgegeben
return new Promise(function(resolve, reject) {
// Normalerweise gibt es hier eine asynchrone Funktion – hier jedoch nicht
// Dieses Ergebnis wird in die Eigenschaften von [data] aufgenommen
resolve({ value: 87 })
})
}
},
- In Zeile 3 war zu sehen, dass die Funktion [asyncData] vom Client noch vor den Lebenszyklusfunktionen ausgeführt wurde;
- Zeile 5 hat die Ausführung des restlichen Codes verhindert, der die Eigenschaft [value] erstellt hätte, da dieser Code vom Client ausgeführt wird;
Kommen wir nun zur Seite [page3]:

- In [2] war der Wert 28, als die Seite vom Server bereitgestellt wurde. Hier ist das nicht der Fall;
- In [4] sehen wir, dass die Funktion [fetch] clientseitig ausgeführt wurde;
Sehen wir uns den vom Client ausgeführten Code an:
...
fetch(context) {
// Wer führt diesen Code aus?
console.log('fetch, client=', process.client, 'serveur=', process.server)
// Nur für den Server
if (process.server) {
// Es wird ein Promise zurückgegeben
return new Promise(function(resolve, reject) {
// Normalerweise handelt es sich hier um eine asynchrone Funktion
// man simuliert sie mit einer Wartezeit von einer Sekunde
setTimeout(() => {
// Erfolg
resolve()
}, 1000)
}).then(() => {
// Der Speicher wird geändert
context.store.commit('increment', 28)
// Protokoll
console.log('fetch commit terminé')
})
}
},
...
- Der Client führt die Methode [fetch] aus, Zeile 2;
- Die Zeilen 6–21 werden nicht ausgeführt, da die Bedingung [process.server] falsch ist. Daher wird Zeile 17, die den Zähler auf 28 setzt, nicht ausgeführt. Er bleibt bei Null. Deshalb zeigt der Client 0 statt 28 an;
Kommen wir nun zur Seite [page4]. Wir erhalten folgendes Ergebnis:

- in [2] den Zählerstand;
- in [3] die Client-Protokolle;
Der vom Client ausgeführte Code lautet wie folgt:
...
data() {
return {
value: 0
}
},
// Lebenszyklus
async beforeCreate() {
// Client und Server
console.log('[page4 beforeCreate]')
// nur für den Server
if (process.server) {
// Die asynchrone Funktion wird ausgeführt
const valeur = await new Promise(function(resolve, reject) {
// Normalerweise handelt es sich hier um eine asynchrone Funktion
// sie wird mit einer Wartezeit von 10 Sekunden simuliert
setTimeout(() => {
// Erfolg – der Wert des Zählers wird zurückgegeben
resolve(52)
}, 10000)
})
// Man ändert den Speicher
this.$store.commit('increment', valeur)
// Protokoll
console.log('[page4 beforeCreate], fonction asynchrone terminée, compteur=', this.$store.state.counter)
}
},
created() {
// Client und Server
this.value = this.$store.state.counter
console.log('[page4 created], value=', this.value)
},
...
- Die Zeilen 12–26 werden vom Client nicht ausgeführt, da die Bedingung [process.server] in Zeile 12 falsch ist. Daher ist der Wert des Zählers im Speicher [Vuex] gleich 0 (sein Anfangswert im Speicher), und genau diesen Wert zeigt die Seite an;
Man könnte sich fragen, was passiert, wenn man die Bedingung [if] in den Zeilen 12 und 26 auskommentiert. Hier ist die Antwort:
- Der Client führt diesmal die Zeilen 14–25 aus, aber [nuxt] wartet nicht auf das Ende der asynchronen Funktion (wie beim Server) und belässt den Zähler daher auf 0;
- Nach 10 Sekunden endet die asynchrone Funktion und der Zähler wird in Zeile 23 auf 52 gesetzt;
- wenn man erneut zur Seite [page4] navigiert, wird nun der Wert 52 angezeigt;
5.7. Résumé
Aus unseren verschiedenen Tests lassen sich folgende Punkte festhalten:
- Wenn die Seite [index] externe Daten enthalten soll, können diese vom Server mit der Funktion [asyncData] abgerufen werden;
- Wenn der Server beim Laden der Seite [index] einen Speicher [Vuex] mit externen Daten initialisieren muss, erfolgt dies in der Funktion [fetch];
- Die vom Server generierte Seite und die vom Client generierte Seite müssen identisch sein, um den „Ruckeleffekt“ zu vermeiden, der dadurch entsteht, dass die vom Client generierte Seite die vom Server gesendete und ursprünglich angezeigte Seite optisch ersetzt;
Anhand eines neuen Beispiels werden wir weitere Aspekte von [nuxt] kennenlernen.