Skip to content

3. Eine erste [nuxt.js]-Anwendung

3.1. Erstellung der Anwendung

Für unsere [nuxt.js]-Entwicklungen verwenden wir weiterhin den VS-Code. Wir haben einen leeren Ordner [dvp] angelegt, in dem wir unsere Beispiele ablegen werden. Anschließend öffnen wir diesen Ordner:

Image

Wir speichern den Arbeitsbereich unter dem Namen [intro-nuxtjs] [3-5]:

Image

Wir öffnen ein Terminal [6-7]:

Image

Bisher haben wir den JavaScript-Paketmanager [npm] verwendet. Zur Abwechslung verwenden wir hier nun den Manager [yarn]. Dieser wird, wie [npm], mit den aktuellen Versionen von [node.js] installiert. Um eine erste [nuxt]-Anwendung zu erstellen, verwenden wir den Befehl [yarn create nuxt-app <dossier>] [1]. Der Befehl fordert eine Reihe von Informationen zum zu generierenden Projekt an und generiert dieses anschließend, sobald diese Informationen vorliegen: [2]:

Image

In [2] wurde eine ganze Dateistruktur erstellt. Die Datei [package.json] enthält die Liste der JavaScript-Bibliotheken, die in den Ordner [node-modules] [4] heruntergeladen wurden:


{
  "name": "nuxt-intro",
  "version": "1.0.0",
  "description": "nuxt-intro",
  "author": "serge-tahe",
  "private": true,
  "scripts": {
    "dev": "nuxt",
    "build": "nuxt build",
    "start": "nuxt start",
    "generate": "nuxt generate",
    "lint": "eslint --ext .js,.vue --ignore-path .gitignore ."
  },
  "dependencies": {
    "nuxt": "^2.0.0",
    "bootstrap-vue": "^2.0.0",
    "bootstrap": "^4.1.3",
    "@nuxtjs/axios": "^5.3.6"
  },
  "devDependencies": {
    "@nuxtjs/eslint-config": "^1.0.1",
    "@nuxtjs/eslint-module": "^1.0.0",
    "babel-eslint": "^10.0.1",
    "eslint": "^6.1.0",
    "eslint-plugin-nuxt": ">=0.4.2",
    "eslint-config-prettier": "^4.1.0",
    "eslint-plugin-prettier": "^3.0.1",
    "prettier": "^1.16.4"
  }
}

Diese Datei spiegelt die Antworten wider, die auf den Befehl [create nuxt-app] zur Definition des erstellten Projekts (November 2019) gegeben wurden. Der Leser verfügt möglicherweise über eine andere Datei [package.json]:

  • Er hat möglicherweise andere Antworten auf die Fragen gegeben;
  • der Befehl [create nuxt-app] hat sich seit der Erstellung dieses Dokuments weiterentwickelt: Abhängigkeiten und Versionen haben sich geändert;

Zeile 8 des Skripts enthält den Befehl, der die Anwendung startet:

Image

  • Bei [4] sieht man, dass die Anwendung unter URL und [localhost:3000] verfügbar ist;
  • Bei [5-6] sieht man, dass die Anwendung einen Server ([6]) und einen Client (dieses Servers, [5]) erstellt;

Rufen wir URL [http://localhost:3000/] in einem Browser auf:

Image

3.2. Beschreibung der Verzeichnisstruktur einer Anwendung [nuxt]

Sehen wir uns noch einmal die Struktur der erstellten Anwendung an:

Image

Die Ordner haben folgende Funktion:

assets
nicht kompilierte Ressourcen der Anwendung (Bilder, …);
static
Die Dateien in diesem Ordner sind im Stammverzeichnis der Anwendung verfügbar. In diesen Ordner werden Dateien abgelegt, die im Stammverzeichnis der Anwendung zu finden sein müssen, wie beispielsweise die Datei „[robots.txt]“ für Suchmaschinen;
components
die [vue]-Komponenten der Anwendung, die in den [layouts]- und [pages]-Dateien verwendet werden;
layouts
die Komponenten [vue] der Anwendung, die als Layout für die [pages] dienen;
Seiten
die Komponenten [vue], die von den verschiedenen Routen der Anwendung angezeigt werden. Man könnte sie als Ansichten der Anwendung bezeichnen. Die Seiten spielen in [nuxt] eine besondere Rolle: Die Routen werden dynamisch anhand der im Ordner [pages] gefundenen Verzeichnisstruktur erstellt;
Middleware
die Skripte, die bei jedem Routenwechsel ausgeführt werden. Sie ermöglichen die Steuerung der Routen;
Plugins
hat einen irreführenden Namen. Kann Plugins, aber auch klassische Skripte enthalten. Die in diesem Ordner befindlichen Skripte werden beim Start der Anwendung ausgeführt;
Store
Wenn er ein Skript namens [index.js] enthält, definiert dieses eine Instanz des Stores von [Vuex];

Ist ein Ordner leer, kann er aus der Verzeichnisstruktur gelöscht werden. Im obigen Beispiel können die Ordner „[assets, static, middleware, plugins, store]“ und „[2]“ gelöscht werden.

3.3. Die Konfigurationsdatei [nuxt.config]

Die Ausführung der Anwendung wird durch die folgende Datei „[nuxt.config.js]“ gesteuert:


export default {
  mode: 'universal',
  /*
   ** Headers of the page
   */
  head: {
    title: process.env.npm_package_name || '',
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      {
        hid: 'description',
        name: 'description',
        content: process.env.npm_package_description || ''
      }
    ],
    link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }]
  },
  /*
   ** Customize the progress-bar color
   */
  loading: { color: '#fff' },
  /*
   ** Global CSS
   */
  css: [],
  /*
   ** Plugins to load before mounting the App
   */
  plugins: [],
  /*
   ** Nuxt.js dev-modules
   */
  buildModules: [
    // Dok.: https://github.com/nuxt-community/eslint-module
    '@nuxtjs/eslint-module'
  ],
  /*
   ** Nuxt.js modules
   */
  modules: [
    // Dok.: https://bootstrap-vue.js.org
    'bootstrap-vue/nuxt',
    // Dok.: https://axios.nuxtjs.org/usage
    '@nuxtjs/axios'
  ],
  /*
   ** Axios module configuration
   ** See https://axios.nuxtjs.org/options
   */
  axios: {},
  /*
   ** Build configuration
   */
  build: {
    /*
     ** You can extend webpack config here
     */
    extend(config, ctx) {}
  }
}
  • Zeile 2: Der Typ der generierten Anwendung:
    • [universal]: Client-Server-Anwendung. Beim ersten Laden der Anwendung sowie bei jeder Seitenaktualisierung im Browser wird der Server aufgefordert, die Seite bereitzustellen;
    • [sap]: Anwendung vom Typ [Single Page Application]: Ein Server liefert zunächst die gesamte Anwendung aus. Anschließend arbeitet der Client eigenständig, auch bei einer Seitenaktualisierung im Browser;
  • Zeilen 6–18: Definieren den Header HTML <head> der verschiedenen Seiten der Anwendung:
    • Zeile 7: das Tag <title> für den Seitentitel;
    • Zeilen 8–16: die Tags <meta>;
    • Zeile 17: die Tags <link>

In der generierten Anwendung lautet das Tag <head> wie folgt (Quellcode der im Browser angezeigten Seite):


<title>nuxt-intro</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="nuxt-intro">
<link data-n-head="ssr" rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="preload" href="/_nuxt/runtime.js" as="script">
<link rel="preload" href="/_nuxt/commons.app.js" as="script">
<link rel="preload" href="/_nuxt/vendors.app.js" as="script">
<link rel="preload" href="/_nuxt/app.js" as="script">

Nun ändern wir die Datei [nuxt.config] wie folgt:


head: {
    title: 'Introduction à [nuxt.js]',
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      {
        hid: 'description',
        name: 'description',
        content: 'ssr routing loading asyncdata middleware plugins store'
      }
    ],
    link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }]
},

Wenn wir die Anwendung erneut ausführen, sieht das <head>-Tag nun wie folgt aus (Quellcode der im Browser angezeigten Seite):


  <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">
    <link rel="preload" href="/_nuxt/runtime.js" as="script">
    <link rel="preload" href="/_nuxt/commons.app.js" as="script">
    <link rel="preload" href="/_nuxt/vendors.app.js" as="script">
<link rel="preload" href="/_nuxt/app.js" as="script">

Kehren wir zur Datei [nuxt.config] zurück:


export default {
  mode: 'universal',
  /*
   ** Headers of the page
   */
  head: {
    ...
  },
  /*
   ** Customize the progress-bar color
   */
  loading: { color: '#fff' },
  /*
   ** Global CSS
   */
  css: [],
  /*
   ** Plugins to load before mounting the App
   */
  plugins: [],
  /*
   ** Nuxt.js dev-modules
   */
  buildModules: [
    // Dok.: https://github.com/nuxt-community/eslint-module
    '@nuxtjs/eslint-module'
  ],
  /*
   ** Nuxt.js modules
   */
  modules: [
    // Dok.: https://bootstrap-vue.js.org
    'bootstrap-vue/nuxt',
    // Dok.: https://axios.nuxtjs.org/usage
    '@nuxtjs/axios'
  ],
  /*
   ** Axios module configuration
   ** See https://axios.nuxtjs.org/options
   */
  axios: {},
  /*
   ** Build configuration
   */
  build: {
    /*
     ** You can extend webpack config here
     */
    extend(config, ctx) {}
  }
}
  • Zeile 12: Zwischen jeder Route des Clients [nuxt] erscheint ein Ladebalken (Loading), wenn der Routenwechsel etwas Zeit in Anspruch nimmt. Mit der Eigenschaft [loading] lässt sich dieser Ladebalken konfigurieren, hier die Farbe des Balkens;
  • Zeile 16: die globalen Dateien [css]. Sie werden automatisch in alle Seiten der Anwendung eingebunden;
  • Zeilen 24–27: die für die Kompilierung (Build) der Anwendung erforderlichen JavaScript-Module;
  • Zeilen 31–36: die von der Anwendung verwendeten JavaScript-Module;
  • Zeile 41: Konfiguration der Bibliothek „[axios]“, wenn diese vom Benutzer für die Dialoge „HTTP“ mit Drittanbieterservern ausgewählt wurde;
  • Zeilen 45–50: Konfiguration der Kompilierung (Build) des Projekts;

Der Konfigurationsdatei können weitere Schlüssel hinzugefügt werden. Insbesondere lassen sich der Dienstport (standardmäßig 3000) und das Projektstammverzeichnis (standardmäßig das Stammverzeichnis des Projekts) konfigurieren. Dies tun wir nun, indem wir die folgenden Schlüssel hinzufügen:


// Verzeichnis des Quellcodes
  srcDir: '.',
  router: {
    // URL Stammverzeichnis der Anwendungsseiten
    base: '/nuxt-intro/'
  },
  // Server
  server: {
    // Dienstport – standardmäßig 3000
    port: 81,
    // Abgehörte Netzwerkadressen – standardmäßig localhost=127.0.0.1
    host: '0.0.0.0'
  }
  • Zeile 2: Angabe, wo sich der Quellcode des Projekts befindet. Er befindet sich hier im aktuellen Verzeichnis, d. h. auf derselben Ebene wie die Datei „[nuxt.config.js]“. Dies ist der Standardwert;
  • Zeilen 8–13: Konfigurieren den Server (man darf nicht vergessen, dass eine Anwendung vom Typ [nuxt] sowohl auf einem Server als auch in einem Client-Browser dieses Servers installiert ist);
  • Zeile 10: Die Seiten der Anwendung werden über Port 81 des Servers bereitgestellt;
  • Zeile 12: Standardmäßig [localhost] (Netzwerkadresse 127.0.0.1). Ein Rechner kann mehrere Netzwerkadressen haben, wenn er zu mehreren Netzwerken gehört. Die Adresse 0.0.0.0 bedeutet, dass der Webserver alle Netzwerkadressen des Rechners abhört;
  • Zeilen 3–6: Konfigurieren den Router der Anwendung [nuxt];
  • Zeile 5: Die Seiten der Anwendung sind unter den Adressen URL und [http://localhost:81/nuxt-intro/] verfügbar;

Fügen wir diese Zeilen zur Datei [nuxt.config.js] hinzu und führen wir anschließend das Projekt aus (npm dev-Skript). Das Ergebnis sieht wie folgt aus:

Image

  • in [1] die Adresse des Rechners in einem öffentlichen Netzwerk;
  • in [2] der Dienstport;
  • in [3] die Stammverzeichnis der Anwendung;

3.4. Der Ordner [layouts]

Image

Der Ordner „[layouts]“ ist für Layout-Komponenten vorgesehen. Standardmäßig wird die Komponente mit dem Namen „[default.vue]“ verwendet. In diesem Projekt lautet diese wie folgt:


<template>
  <div>
    <nuxt />
  </div>
</template>

<style>
html {
  font-family: 'Source Sans Pro', -apple-system, BlinkMacSystemFont, 'Segoe UI',
    Roboto, 'Helvetica Neue', Arial, sans-serif;
  font-size: 16px;
  word-spacing: 1px;
  -ms-text-size-adjust: 100%;
  -webkit-text-size-adjust: 100%;
  -moz-osx-font-smoothing: grayscale;
  -webkit-font-smoothing: antialiased;
  box-sizing: border-box;
}

*,
*:before,
*:after {
  box-sizing: border-box;
  margin: 0;
}

.button--green {
  display: inline-block;
  border-radius: 4px;
  border: 1px solid #3b8070;
  color: #3b8070;
  text-decoration: none;
  padding: 10px 30px;
}

.button--green:hover {
  color: #fff;
  background-color: #3b8070;
}

.button--grey {
  display: inline-block;
  border-radius: 4px;
  border: 1px solid #35495e;
  color: #35495e;
  text-decoration: none;
  padding: 10px 30px;
  margin-left: 15px;
}

.button--grey:hover {
  color: #fff;
  background-color: #35495e;
}
</style>

Anmerkungen

  • Zeilen 1–5: die [template] der Komponente;
  • Zeile 3: Das Tag <nuxt /> bezeichnet die aktuelle Seite des Routings;
  • Zeilen 7–55: das von der Layout-Komponente eingebettete Styling. Da dieses die aktuelle Seite des Routings enthält, wird dieses Styling auf alle gerouteten Seiten der Anwendung angewendet;

Man sieht, dass der Hauptzweck der Seite [default.vue] darin besteht, den gerouteten Seiten ein Styling zuzuweisen.

3.5. Der Ordner [pages]

Image

Der Ordner „[pages]“ enthält die gerouteten Ansichten, die der Benutzer sieht. Die Seite „[index.vue]“ ist die Startseite der Anwendung. Bei „[nuxt.js]“ gibt es keine Routing-Datei. Die Routen werden anhand der Struktur des Ordners [pages] festgelegt. Ist hier eine Datei namens [index.vue] vorhanden, wird automatisch eine Route namens [index] erstellt, deren Pfad von [/index] auf [/] verkürzt wird, da es sich um die Startseite handelt. Somit wird folgende Route erstellt:

        { name : ‘index’, path : ‘/’}

Die Datei [index.vue] lautet wie folgt:


<template>
  <div class="container">
    <div>
      <logo />
      <h1 class="title">
        nuxt-intro
      </h1>
      <h2 class="subtitle">
        nuxt-intro
      </h2>
      <div class="links">
        <a href="https://nuxtjs.org/" target="_blank" class="button--green">
          Documentation
        </a>
        <a
          href="https://github.com/nuxt/nuxt.js"
          target="_blank"
          class="button--grey"
        >
          GitHub
        </a>
      </div>
    </div>
  </div>
</template>

<script>
import Logo from '~/components/Logo.vue'

export default {
  components: {
    Logo
  }
}
</script>

<style>
.container {
  margin: 0 auto;
  min-height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  text-align: center;
}

.title {
  font-family: 'Quicksand', 'Source Sans Pro', -apple-system, BlinkMacSystemFont,
    'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  display: block;
  font-weight: 300;
  font-size: 100px;
  color: #35495e;
  letter-spacing: 1px;
}

.subtitle {
  font-weight: 300;
  font-size: 42px;
  color: #526488;
  word-spacing: 5px;
  padding-bottom: 15px;
}

.links {
  padding-top: 15px;
}
</style>

Die Zeilen 1–25 der Datei [template] zeigen folgende Ansicht:

Image

Das Bild [1] wird durch Zeile 4 der Datei [template] generiert. Man sieht also, dass die Seite eine Komponente namens [logo] verwendet. Diese ist in den Zeilen 27–35 des Skripts der Seite definiert. In Zeile 28 bezeichnet die Bezeichnung [~] den Stammordner des Projekts.

Image

Die Komponente [Logo.vue] lautet wie folgt:


<template>
  <div class="VueToNuxtLogo">
    <div class="Triangle Triangle--two" />
    <div class="Triangle Triangle--one" />
    <div class="Triangle Triangle--three" />
    <div class="Triangle Triangle--four" />
  </div>
</template>

<style>
.VueToNuxtLogo {
  display: inline-block;
  animation: turn 2s linear forwards 1s;
  transform: rotateX(180deg);
  position: relative;
  overflow: hidden;
  height: 180px;
  width: 245px;
}

.Triangle {
  position: absolute;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
}

.Triangle--one {
  border-left: 105px solid transparent;
  border-right: 105px solid transparent;
  border-bottom: 180px solid #41b883;
}

.Triangle--two {
  top: 30px;
  left: 35px;
  animation: goright 0.5s linear forwards 3.5s;
  border-left: 87.5px solid transparent;
  border-right: 87.5px solid transparent;
  border-bottom: 150px solid #3b8070;
}

.Triangle--three {
  top: 60px;
  left: 35px;
  animation: goright 0.5s linear forwards 3.5s;
  border-left: 70px solid transparent;
  border-right: 70px solid transparent;
  border-bottom: 120px solid #35495e;
}

.Triangle--four {
  top: 120px;
  left: 70px;
  animation: godown 0.5s linear forwards 3s;
  border-left: 35px solid transparent;
  border-right: 35px solid transparent;
  border-bottom: 60px solid #fff;
}

@keyframes turn {
  100% {
    transform: rotateX(0deg);
  }
}

@keyframes godown {
  100% {
    top: 180px;
  }
}

@keyframes goright {
  100% {
    left: 70px;
  }
}
</style>

Diese Komponente besteht im Wesentlichen aus Stilen und Animationen zur Erstellung eines animierten Bildes.

3.7. Ansicht DevTools

[Vue DevTools] ist die Browsererweiterung, mit der die Objekte [nuxt.js] und [vue.js] im Browser untersucht werden können. Wir haben sie bereits im Kapitel über [vue.js] verwendet. Schauen wir uns an, was dieses Tool findet, wenn die Startseite unserer Anwendung angezeigt wird:

Image

  • In [1] verweist die Komponente [PagesIndex] auf die Seite [pages/index.vue];
  • in [2] sehen wir, dass diese Komponente eine Eigenschaft [$route] besitzt, die den Pfad angibt, über den die Seite [index] aufgerufen wurde;

Als einfache Übung geben wir diesen Pfad in der Konsole aus.

3.8. Änderung der Startseite

Wir werden die Datei [index.vue] bearbeiten. In unserer Projektinstallation haben wir zwei Abhängigkeiten installiert:

  • [eslint]: Diese überprüft die Syntax von JavaScript-Dateien und Vue-Komponenten. Wenn die Erweiterung [ESLint] von VSCode installiert wurde, wird diese Syntax bereits während der Texteingabe überprüft und Fehler werden sofort gemeldet;
  • [prettier]: formatiert den JavaScript-Code nach einem Standard;

Diese Abhängigkeiten sind in der Datei [package.json] verzeichnet:


"devDependencies": {
    "@nuxtjs/eslint-config": "^1.0.1",
    "@nuxtjs/eslint-module": "^1.0.0",
    "babel-eslint": "^10.0.1",
    "eslint": "^6.1.0",
    "eslint-config-prettier": "^4.1.0",
    "eslint-plugin-nuxt": ">=0.4.2",
    "eslint-plugin-prettier": "^3.0.1",
    "prettier": "^1.16.4"
}

Ich habe festgestellt (Nov. 2019), dass bei einer Installation über den Befehl [yarn create nuxt-app] die Tools [eslint, prettier] während der Texteingabe nicht funktionieren. Fehler werden erst bei der Kompilierung gemeldet. Nach einigen Recherchen habe ich eine Konfiguration gefunden, die funktioniert:

Image

Man legt im Stammverzeichnis des Projekts einen Ordner „[.vscode]“ an, der die folgende Datei „[settings.json]“ enthält:


{
  "eslint.validate": [
    {
      "language": "vue",
      "autoFix": true
    },
    {
      "language": "javascript",
      "autoFix": true
    }
  ],
  "eslint.autoFixOnSave": true,
  "editor.formatOnSave": false
}
  • Zeilen 2–11: Geben an, dass [eslint] beim Überprüfen der .vue- und .js-Dateien die Fehler beheben soll, die es beheben kann;
  • Zeile 12: Wenn eine Datei gespeichert wird, muss [eslint] die Fehler korrigieren, die es korrigieren kann;
  • Zeile 13: Deaktiviert die standardmäßige Formatierung durch VSCode beim Speichern. Diese wird stattdessen von [prettier] übernommen;

Mit dieser Konfiguration:

  • werden Syntax- oder Formatierungsfehler bereits während der Texteingabe gemeldet;
  • Formatierungsfehler werden beim Speichern der Datei automatisch korrigiert;

Die Bibliothek [prettier] wird über die Datei [.prettierrc] konfiguriert:

Image

Diese Datei lautet standardmäßig wie folgt:


{
  "semi": false,
  "arrowParens": "always",
  "singleQuote": true
}
  • Zeile 1: kein „;“ am Ende der Anweisungen;
  • Zeile 2: Wenn eine „Pfeil“-Funktion (arrow) einen einzigen Parameter hat, wird dieser in Klammern gesetzt;
  • Zeile 3: Zeichenfolgen werden in Apostrophe gesetzt (keine Anführungszeichen);

Wir fügen die folgenden beiden Regeln hinzu:


{
  "semi": false,
  "arrowParens": "always",
  "singleQuote": true,
  "printWidth": 120,
  "endOfLine": "auto"
}
  • Zeile 5: Die Codezeile darf bis zu 120 Zeichen lang sein;
  • Zeile 6: Das Zeilenendezeichen kann wahlweise CRLF (Windows) oder LF (Unix) sein;

Schließlich wird die Datei „[package.json]“ wie folgt geändert:


"scripts": {
    "dev": "nuxt",
    "build": "nuxt build",
    "start": "nuxt start",
    "generate": "nuxt generate",
    "lint": "eslint --ext .js,.vue --ignore-path .gitignore .",
    "lintfix": "eslint --fix --ext .js,.vue --ignore-path .gitignore ."
},
  • Zeile 7: Wir fügen den Befehl [lintfix] hinzu, der mit dem Befehl [lint] aus Zeile 6 identisch ist, außer dass er zusätzlich den Parameter [--fix] enthält. Der Befehl [lint] überprüft die Syntax und das Format aller Dateien des Projekts und meldet etwaige Fehler. [lintfix] führt denselben Vorgang durch, mit dem Unterschied, dass Formatierungsprobleme, die behoben werden können, automatisch korrigiert werden. [lintfix] ist der Befehl, der verwendet werden muss, wenn die Kompilierung aufgrund von Formatierungsproblemen in den Dateien fehlschlägt;

Anschließend ändern wir die Datei [index.vue] wie folgt:

Image


<script>
/* eslint-disable no-console */
import Logo from '~/components/Logo.vue'

export default {
  components: {
    Logo
  },
  // Lebenszyklus
  created() {
    console.log('created, route=', this.$route)
  }
}
</script>
  • Zeilen 10–12: Wir fügen die Funktion [created] hinzu, die automatisch ausgeführt wird, sobald die Komponente erstellt wurde;
  • Zeile 11: Die aktuelle Route wird angezeigt;
  • Zeile 2: Ein Kommentar für [eslint]. Ohne diesen Kommentar meldet [eslint] einen Fehler. Zeile 11: [console] darf nicht in den Lebenszyklusfunktionen enthalten sein. [eslint] ist konfigurierbar. Wir behalten die Standardkonfiguration bei und verwenden Kommentare wie den in Zeile 2, um eine bestimmte Regel von [eslint] zu deaktivieren. Wir verwenden zwei Arten von Kommentaren:
    • /* Deaktivierung der Regel [eslint] */: Deaktivierung einer Regel für die gesamte Datei;
    • // Deaktivierung der Regel [eslint]: Deaktivierung einer Regel für die folgende Zeile;

Während der Eingabe werden Fehler gemeldet und es steht die Funktion [Quick Fix] zur Verfügung:

Image

Das Projekt wird ausgeführt:

Image

  • in [1], die Registerkarte [Vue] der Entwicklertools des Browsers (F12);
  • in [2] und [3], die Routenanzeige;

Warum zwei Ansichten und nicht nur eine?

Eine [nuxt]-Anwendung besteht aus zwei Komponenten, einem Server und einem Client:

  1. Der Server stellt die Seiten der Anwendung beim Start bereit und anschließend jedes Mal, wenn eine Seite im Browser aktualisiert wird (F5) oder wenn der Benutzer eine URL der Anwendung manuell eingibt;
  2. jede vom Browser bereitgestellte Seite enthält die angeforderte Seite sowie den JavaScript-Code der gesamten Anwendung, der anschließend im Browser ausgeführt wird. Dies ist der Client. Solange keine Seitenaktualisierung im Browser erfolgt, funktioniert die Anwendung wie eine klassische Vue-Anwendung im [sap]-Modus (Single Page Application). Sobald der Benutzer manuell eine Seitenaktualisierung auslöst, wird die Seite vom Server angefordert und es kehrt man zur vorherigen Phase 1 zurück.

Man muss verstehen, dass es sich um dieselben Seiten des Ordners „[pages]“ handelt, die sowohl vom Server als auch vom Client bereitgestellt werden. Aus diesem Grund bezeichnen die Entwickler von „[nuxt]“ diese Art von Seiten als isomorphe Seiten. Die gleichen [.vue]-Seiten können sowohl vom Client als auch vom Server interpretiert werden. Nehmen wir das Beispiel der Seite [index]:


<template>
  <div class="container">
    <div>
      <logo />
      <h1 class="title">
        nuxt-intro
      </h1>
      <h2 class="subtitle">
        nuxt-intro
      </h2>
      <div class="links">
        <a href="https://nuxtjs.org/" target="_blank" class="button--green">
          Documentation
        </a>
        <a
          href="https://github.com/nuxt/nuxt.js"
          target="_blank"
          class="button--grey"
        >
          GitHub
        </a>
      </div>
    </div>
  </div>
</template>

<script>
/* eslint-disable no-console */
import Logo from '~/components/Logo.vue'

export default {
  components: {
    Logo
  },
  // Lebenszyklus
  created() {
    console.log('created, route=', this.$route)
  }
}
</script>

Da es sich um die Startseite handelt, wird sie beim Start der Anwendung vom Server bereitgestellt. Die Seite auf dem Server hat ebenfalls einen Lebenszyklus, der dem einer klassischen [Vue]-Seite entspricht, mit Ausnahme der Funktionen [beforeMount, monted], die serverseitig nicht vorhanden sind. Die Funktion [created] wird ausgeführt, was den ersten Log-Eintrag erklärt. Das bedeutet übrigens, dass der Server in der Lage ist, JavaScript-Skripte auszuführen. In diesem Fall und generell handelt es sich bei diesem Server um einen [node.js]-Server. Sobald die Seite auf dem Server erstellt wurde, gelangt sie zum Browser, wo sie erneut den Lebenszyklus durchläuft. Die Funktion [created] wird ein zweites Mal ausgeführt, was den zweiten Log-Eintrag ergibt.

Die Architektur einer [nuxt]-Anwendung könnte wie folgt aussehen:

Image

  • [1]: der Browser, der die Anwendung [nuxt] hostet, sobald diese im Browser geladen wurde. Dies wird als Client [nuxt] bezeichnet;
  • [3]: Der Server, auf dem die Anwendung [nuxt] ursprünglich gehostet wird. Diese wird beim Start der Anwendung sowie jedes Mal, wenn der Benutzer die aktuelle Browserseite aktualisiert oder manuell eine URL der Anwendung eingibt, in den Browser [1] geladen. Hier liegt der Unterschied in der Funktionsweise gegenüber einer klassischen Vue-Anwendung. Bei dieser wurde der Server, sobald die Seite im Browser geladen war, danach nie wieder angefragt. Ein weiterer wichtiger Unterschied, der bisher noch nicht deutlich wurde, besteht darin, dass der Server einer Vue-Anwendung ein statischer Server ist, der die Seiten [.vue] nicht interpretieren kann, während der Server einer Nuxt-Anwendung vom Typ [universal] ein JavaScript-Server ist. Bevor eine Seite an den Browser gesendet wird, kann der Server Skripte ausführen und beispielsweise Daten vom Server [2] abrufen;
  • [2]: ist der Server, der Daten entweder an die Clients [nuxt] und [1] oder an die Server [nuxt] und [3] liefert;

In dem obigen Schema lassen sich drei Client-Server-Subsysteme unterscheiden:

  • [1, 3]: hostet die Anwendung [nuxt]. [3] stellt diese beim Start der Anwendung zusammen mit der Startseite bereit und jedes Mal, wenn der Benutzer eine Seite manuell anfordert. [1] hostet dieAnwendung [nuxt], die von [3] empfangen wurde, das wiederum im Modus [SAP] läuft, solange die Seiten nicht manuell bei [3] angefordert werden;
  • [1, 2]: Im Modus [SAP] ruft der Client [nuxt] externe Daten von einem oder mehreren Servern ab;
  • [3, 2]: Bei der Generierung der vom Benutzer angeforderten Seite kann auch der Server [3] externe Daten von einem oder mehreren Servern abrufen;

Es ist also der Server [3], der eine Anwendung [nuxt] von einer Anwendung [vue] unterscheidet. Dieser Server wird jedes Mal aufgerufen, wenn der Benutzer eine Seite manuell anfordert. Er verarbeitet dieselben [.vue]-Seiten wie die Clients [vue] und [1]. Es handelt sich um einen JavaScript-Server, der die auf der Seite vorhandenen Skripte ausführen kann. Dies kann beispielsweise die Art und Weise beeinflussen, wie die Startseite mit externen Daten generiert wird: Während eine Anwendung [vue] diese Daten zwangsläufig vom Client [1] bezieht, können sie hier vom Server [3] abgerufen werden, bevor die Seite an den Client gesendet wird. Die Startseite gewinnt dadurch an Bedeutung und kann dazu beitragen, den SEO der Anwendung zu verbessern.

Hinweis: Im Entwicklungsmodus befinden sich die drei Instanzen [1, 2, 3] häufig auf demselben Rechner. Dies ist hier bei allen unseren Beispielen der Fall.

3.9. Verschieben des Anwendungsquellcodes in einen separaten Ordner

Im weiteren Verlauf werden wir verschiedene [nuxt]-Anwendungen im selben Ordner [dvp] erstellen. Der für jedes Projekt [nuxt] generierte Ordner mit den Abhängigkeiten [node_modules] kann nämlich mehrere hundert Megabyte groß sein. Wir werden verschiedene Ordner [nuxt-00, nuxt-01, ...] im Ordner [dvp] anlegen, um den Quellcode der zu testenden Beispiele zu speichern. Anschließend verwenden wir die Konfigurationsdatei [nuxt-config.js], um anzugeben, wo sich der Quellcode des Projekts [dvp] befindet, das das einzige Projekt [nuxt] in diesem Tutorial bleiben wird.

Wir verschieben den Quellcode der ursprünglich mit dem Befehl [yarn create nuxt-app] generierten Anwendung in einen Ordner [nuxt-00]:

Image

  • In [2] haben wir die Ordner [components, layouts, pages] in einen Ordner [nuxt-00] verschoben;
  • In [3] müssen wir die Datei [nuxt.config.js] ändern;

Wir ändern die Datei [nuxt.config.js] wie folgt:


export default {
  mode: 'universal',
  /*
   ** Headers of the page
   */
  ...
  /*
   ** Build configuration
   */
  build: {
    /*
     ** You can extend webpack config here
     */
    extend(config, ctx) {}
  },
  // Quellcode-Verzeichnis
  srcDir: 'nuxt-00',
  // Router
  router: {
    // Stammverzeichnis der Anwendung URL
    base: '/nuxt-00/'
  },
  // 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: '0.0.0.0'
  }
}

Die Datei wird an zwei Stellen geändert:

  • Zeile 17: Hier wird angegeben, dass sich der Quellcode des Projekts [dvp] im Ordner [nuxt-00] befindet;
  • Zeile 21: Es wird angegeben, dass das Stammverzeichnis der Anwendung URL nun [/nuxt-00/] lautet. Diese Änderung war nicht zwingend erforderlich. Man könnte diese Eigenschaft weglassen, und das Stammverzeichnis von URL wäre dann [/]. So können wir uns merken, dass der ausgeführte Quellcode aus dem Ordner [nuxt-00] stammt;

Anschließend wird das Projekt [dvp] wie zuvor ausgeführt:

Image

3.10. Bereitstellung der Anwendung [nuxt-00]

Wir werden die Anwendung [nuxt-00] in einer anderen Umgebung als der integrierten Umgebung von VSCode ausführen.

Zunächst kompilieren wir die Anwendung:

Image

  • zu [3], dem Ergebnis der Kompilierung auf dem Client. Wird vom Browser ausgeführt;
  • in [4], das Ergebnis der Serverkompilierung. Wird vom Server [node.js] ausgeführt;

Das Kompilierungsergebnis wird im Ordner [.nuxt] abgelegt:

Image

Wir kopieren die Ordner [.nuxt, node_modules] und die Dateien [package.json, nuxt.config.js] in einen separaten Ordner:

Image

Die Datei [package.json] wird wie folgt vereinfacht:


{
  "scripts": {
    "start": "nuxt start"
  }
}
  • Es wird nur das Skript [start] beibehalten, mit dem die kompilierte Version des Projekts ausgeführt werden kann;

Die Datei [nuxt.config.js] wird wie folgt vereinfacht:


export default {
  // Router
  router: {
    // Stammverzeichnis der URL-Dateien der Anwendung
    base: '/nuxt-00/'
  },
  // 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: '0.0.0.0'
  }
}
  • Zeile 5: Man legt die Basis-URL der kompilierten Anwendung fest;
  • Zeilen 8–14: Der Dienstport und die überwachten Netzwerkadressen werden definiert;

Anschließend öffnet man ein Laragon-Terminal und wechselt in den Ordner, der die kompilierte Version des Projekts enthält. Man kann jede Art von Terminal öffnen, allerdings muss sich die ausführbare Datei [npm] im Verzeichnis des Terminals befinden. Dies ist beim Laragon-Terminal der Fall.

Anschließend gibt man den Befehl [npm run start] ein:

Image

In [3] sieht man, dass ein Server gestartet wurde und auf den Port URL [http://192.168.1.128:81/nuxt-00/] lauscht. Rufen wir nun diese Adresse mit einem Browser auf. Das Ergebnis ist dasselbe wie zuvor. Auf der Terminalseite wurden Protokolle geschrieben: [5]. Es handelt sich um das Protokoll, das in der Methode [created] der Seite [index.vue] abgelegt wurde, die vom Server [node.js] ausgeführt wurde.

Image

Auf der Browserseite [6] findet sich ebenfalls das Protokoll der Methode [created] der Seite [index.vue], das jedoch diesmal vom Client ausgeführt wurde.

3.11. Einrichtung eines sicheren Servers

Oben lautet die URL der Anwendung [http://192.168.1.128/nuxt-00/]. Wir möchten, dass sie [https://192.168.1.128/nuxt-00/] lautet. Daher müssen wir einen sicheren Server einrichten. Wir zeigen, wie das geht.

Hinweis: Die Methode stammt aus dem Artikel [https://stackoverflow.com/questions/56966137/how-to-run-nuxt-npm-run-dev-with-https-in-localhost].

Zunächst erstellen wir mit [openssl] einen privaten und einen öffentlichen Schlüssel. [openssl] wird normalerweise zusammen mit dem Laragon-Server installiert. Daher ist dieser Befehl in jedem Laragon-Terminal verfügbar. Öffnen wir also ein Laragon-Terminal und wechseln wir in den Ordner der bereitgestellten Anwendung:

Image

Image

  • In [2] geben wir den Befehl [openssl genrsa 2048 > server.key] ein;
  • in [3] wird eine Datei [server.key] erstellt;
  • in [4] gibt man den Befehl [openssl req -new -x509 -nodes -sha256 -days 365 -key server.key -out server.crt] ein;
  • In [5] wird eine Datei mit dem Namen [server.crt] erstellt;

Diese beiden Dateien bilden ein selbstsigniertes Zertifikat. Die meisten Browser akzeptieren sie erst nach Zustimmung des Nutzers, der die Seite aufgerufen hat.

Die Dateien „[server.key, server.crt]“ müssen nun von der Webanwendung verwendet werden. Dazu muss die Datei „[nuxt.config.js]“ wie folgt geändert werden:


import path from 'path'
import fs from 'fs'

export default {
  // Router
  router: {
    // Stammverzeichnis der URL-Dateien der Anwendung
    base: '/nuxt-00/'
  },
  // 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: '0.0.0.0',
    // selbstsigniertes Zertifikat
    https: {
      key: fs.readFileSync(path.resolve(__dirname, 'server.key')),
      cert: fs.readFileSync(path.resolve(__dirname, 'server.crt'))
    }
  }
}

Die Zeilen 18–21 implementieren das Protokoll [https].

Führen wir nun die Anwendung erneut aus:

Image

3.12. Ende des ersten Beispiels

Das erste Beispiel ist nun abgeschlossen. Es hat uns viele Konzepte von [nuxt] nähergebracht. Wir werden nun weitere Beispiele entwickeln, die wir in Ordnern mit dem Namen [nuxt-01, nuxt-02, ...] ablegen werden. Da diese Beispiele eine andere Datei [nuxt.config.js] verwenden werden, speichern wir in jedem dieser Ordner die Datei [nuxt.config.js], die zu ihrer Ausführung verwendet wurde:

Image