SPA mit Vue.js, vuetify, Laravel Lumen und Passport III

Teil 3: Erstellung der Webanwendung mit Vue.js und axios

Albrecht Mauersberger
6 min readApr 10, 2019

Nachdem wir uns in Teil 1 des Tutorials mit der Erstellung des Backends und der API mit Laravel Lumen beschäftigt haben, welches wir in Teil 2 mit einer Möglichkeit zur Authentifizierung versehen haben, werden wir uns in diesem Artikel mit der Erstellung der eigentlichen Vue.js Webanwendung bzw. des Clients beschäftigen.

Der etwas einfachere Weg wäre eine Initialisierung mittels vue-cli , aber da selbst der offizielle Getting Started Guide davon abrät, habe auch ich mich entschieden, die Anwendung händisch aufzusetzen, damit ein größerer Lerneffekt entsteht.

Die aktuelle Projektstruktur

Durch die beiden ersten Teile haben wir momentan folgende durch Lumen erstellte Projektstruktur:

- app
- bootstrap
- config
- database
- public
- resources
- routes
- src
- storage
- tests
- vendor
.env.example
artisan
composer.json
composer.lock
phpunit.xml

Die Vue-Anwendung wird später parallel im public Ordner liegen, vorher wird allerdings Node.js und npm benötigt, um die Abhängigkeiten des Clients aufzulösen.

Abhängigkeiten mit npm installieren

Im ersten Schritt initialisieren wir uns im root-Ordner unserer Anwendung npm.

npm init

Wir werden nun gebeten, ein paar Informationen zur Anwendung zu hinterlegen. Danach können wir die benötigten Pakete installieren.

  • vue als Core-Paket
  • vue-router für das Routing
  • axios für die Ajax-Requests an die API
npm install --save vue vue-router axios 

Außerdem benötigen wir noch webpack zur Entwicklung incl. aller benötigter Loader und Abhängigkeiten.

  • webpack-cli um webpack von der Kommandozeile aufzurufen
  • webpack-dev-server für die lokale Entwicklung
  • webpack-merge um eine Basiskonfiguration mit spziellen Konfigurationen der jeweiligen Umgebung (lokal, produktiv) zusammenzuführen
  • html-webpack-plugin um die von webpack erstellten Bundles in die Datei index.html zu integrieren
  • Der Loader vue-loaderals Präprozessor zur Kompilierung der verschiedenen Vue-Komponenten
npm install --save-dev webpack webpack-cli webpack-dev-server webpack-merge html-webpack-plugin vue-loader 

Anlegen der Anwendungsstruktur

Nachdem alle Abhängigkeiten installiert wurden, können wir uns um die eigentliche Anwendungsstruktur im Ordner public hinterlegen. Dabei wird folgendes benötigt:

  • eine index.html Datei mit einem div-Container, in den die Vue.js-App gemounted werden kann
  • einen src Ordner, in dem unsere JavaScript- und Vue-Dateien liegen
  • eine app.js Datei, in der Vue.js initialisiert wird
  • eine Vue-Komponente App.vue, die letztlich die Inhalte ausgibt

Folgende Struktur ist somit vorgesehen:

...
public
|_ src
|_ js
|_ app.js
|_ App.vue
|_ index.html
...
package-lock.json
package.json

Die index.html wird mit einem einfachen Grundgerüst befüllt. Wichtig dabei ist das app-div, in welche später die Vue-Anwendung geladen wird.

In der app.js initialisieren wir Vue, laden die App.vue-Komponente und rendern diese in den DOM.

Die App.vue Komponente belassen wir vorerst beim klassischen Hello, World!

Webpack einrichten und den webpack-dev-server starten

Nachdem wir nun die Anwendung aufgesetzt haben, müssen wir nur noch den webpack-dev-server für die lokale Entwicklung einrichten. Wir legen dafür im root-Verzeichnis zwei Dateien an:

  • webpack.config.js als zentrale webpack-Konfiguration
  • webpack.dev.js für die lokale Entwicklung

In der zentralen Konfiguration definieren wir den Einstiegspunkt, legen die Loader für die einzelnen Dateitypen fest und initialisieren die benötigten Plugins. Da wir in der app.js Templates kompilieren und nicht direkt rendern, benötigen wir das Vue-Paket mit integrierten Compiler, welches wir per alias auflösen.

In der webpack.dev.js mergen wir jetzt noch die entwicklungsspezifischen Anforderungen, insbesondere das Hot Module Replacement, wodurch geänderter Quellcode zu einem automatischen Nachladen des DOMs im Browser führt.

Zuguterletzt legen wir in der package.json noch einen Shortcut an, um den webpack-server zu starten.

{
"scripts": {
"dev": "webpack-dev-server --config webpack.dev.js --content-base public/ --history-api-fallback"
},
}

Der Befehl npm run dev startet also unseren lokalen webpack-dev-server mit der webpack.dev.js Konfiguration und zeigt auf den Order public , in welchem unsere Vue-Anwendung liegt. Der Parameter --history-api-fallback greift schon vor auf das Routing und die gewünschte URL-Struktur. Mehr dazu im nächsten Abschnitt, aber erstmal testen wir nun unsere App durch Aufruf von http://localhost:8080 im Browser, wo daraufhin eine große Überschrift Hello, World! erscheinen sollte.

Einrichtung des Routing und Anbindung dynamischer Inhalte via API

Nun wollen wir uns die Firmen und Produkte von der API abrufen und auf der Startseite ausgeben. Die Firmen und Produkte sollen dabei auf die dazugehörigen Detailseiten verweisen. Dafür ergänzen wir die aktuelle Anwendungsstruktur um folgende Elemente:

  • ein Ordner pages für alle Top Level Komponenten, die mit einer Route verknüpft sind
  • eine router.js Datei im src\js Ordner, in der wir die Routen und damit die URLs festlegen

Damit sieht die Ordnerstruktur wie folgt aus:

...
public
|_ src
|_ js
|_ app.js
|_ router.js
|_ pages
|_ Company.vue
|_ Home.vue
|_ Product.vue
|_ App.vue
|_ index.html
...
package-lock.json
package.json

Wir fangen damit an, die router.js mit den benötigten Routen zu belegen. Wir haben dabei, um es anfangs übersichtlich zu halten, eine Route für die Startseite, eine Route für die Firmendetailseite und eine für die Produktdetailseite. Wichtig ist hier noch der Modus des Routers history der URLs ohne Fragmente (#) erstellt, weswegen wir im vorherigen Schritt schon entsprechende Vorkehrungen beim webpack-dev-server getroffen hatten.

Den Router müssen wir nun bei der Initialisierung der Anwendung berücksichtigen, indem wir ihn der app.js importieren. In diesem Zusammenhang initialisieren wir auch axios, um die Requests an die API durchzuführen. Hierbei ist wichtig, dass wir die axios-Instanz global in den Vue-Komponenten verfügbar machen und die Basis-URL der API festlegen. Der Router wird dann der Vue-Anwendung mit übergeben.

Erstellung der Vue-Komponenten und Anbindung der API

Nun müssen wir noch die Vue-Komponenten erstellen, die im Router referenziert sind. Wir fangen an mit den beiden Komponenten für die Firmen- und die Produktseite. Die beiden Seiten sind relativ identisch aufgebaut. Im script Bereich der Seite wird, nach dem Mounting (siehe Dokumentation), mittels axios bzw. this.$http der Endpunkt der API aufgerufen, wobei die ID aus der URL bzw. der Route übergeben wird. Die erhaltene Antwort wird an das data-Objekt übergeben. Dieses wird dann im Template ausgegeben, sofern das Produkt/die Firma vorhanden ist.

Hinweis: Der Request an die API wird im ersten Versuch fehlschlagen, da die API einen CORS-Fehler zurückgeben wird. Grund ist, dass die Anfrage von einem anderen Port kommt. Man kann diese Problematik mittels .htaccess lösen, oder man integriert eine weitere CORS-Middleware in Lumen. Dafür erstellt man unter app\http\Middleware eine CorsMiddleware.php mit folgenden Inhalt (der Access-Control-Allow-Origin muss produktiv entsprechend angepasst werden):

Diese Middleware muss nun in der bootstrap\app.php noch registiert werden.

$app->middleware([
App\Http\Middleware\CorsMiddleware::class,
]);

Erstellung der Startseite

Nun da die Requests letztlich funktionieren sollten, erstellen wir uns eine Startseite, auf der alle Firmen und Produkte, jeweils verlinkt, ausgegeben werden. Wir nutzen hierfür mehrere parallele Anfragen an die API mittels sogenanntem spreading bei axios (siehe Dokumentation). Über diese Einträge wird dann mittels v-for geloopt und für jedes Element ein verlinktes Listenelement mittels router-link ausgegeben. Diese Links gehen alle auf die jeweiligen benamten Routen (mittels name ) und übergeben dort den Parameter id .

Als letztes müssen wir jetzt noch die App.vue anpassen, die nun nicht mehr Hello, World! ausgeben soll, sondern die Vue-Komponente, die durch das Routing angesprochen ist.

Wenn nun der webpack-dev-server läuft und man widerum http://localhost:8080 aufruft, sollten 2 Listen mit Firmen und Produkten kommen, die jeweils verlinkt sind. Die Produkte und Firmen kann man anklicken oder direkt mit z.B. http://localhost:8080/products/1 bzw. http://localhost:8080/companies/1 aufrufen.

Ausblick

Im nächsten Teil werden wir vuetify einbinden, um die ganze Seite etwas aufzuhübschen und eine angemessene Navigation zu integrieren. Außerdem werden wir ein Kontaktformular erstellen, welches verlinkt ist und an die API gesendet werden kann.

Vorherige Teile dieser Serie:

Weitere Teile dieser Serie:

--

--