
Share:
)
Freundlicher Tech-Pädagoge, Familienvater, Verfechter der Vielfalt, streitet wahrscheinlich ein bisschen zu viel. Ehemals Backend-Ingenieur. Sprich mit mir über JavaScript (Frontend oder Backend), das erstaunliche Vue.js, DevOps, DevSecOps, alles was mit JamStack zu tun hat. Autorin auf DEV.to
Aufbau eines Slack-Klons mit Vue Teil 1
Lesedauer: 68 Minuten
Aufbau einer Slack-ähnlichen Vue.js Chat-Anwendung
Wollten Sie schon einmal eine Chat-Anwendung erstellen, wissen aber nicht, welche Funktionen Sie hinzufügen sollen, oder wie Sie sie generell gestalten können? In diesem Beitrag können Sie einen Klon von Slack, der beliebtesten Chat-Software, erstellen. Mit Vue.js, jedermanns Lieblings-Framework. Und Vonage Conversation API, jedermanns Lieblings-Konversationsdienst.
Dieser Beitrag ist Teil 1 einer mehrteiligen Tutorialserie, die von einem leeren Verzeichnis zu einer realen Anwendung führt, die viele der genredefinierenden Funktionen von Slacks enthält.
Hier sind einige der Dinge, die Sie in diesem Beitrag erfahren werden:
Wenn Sie an der kompletten Demo-App interessiert sind und die Anleitung komplett überspringen möchten, schauen Sie sich bitte das GitHub Repo für meinen Vue.js Slack Klon bis jetzt.
Voraussetzungen
Vonage API-Konto
Um dieses Tutorial durchzuführen, benötigen Sie ein Vonage API-Konto. Wenn Sie noch keines haben, können Sie sich noch heute anmelden und mit einem kostenlosen Guthaben beginnen. Sobald Sie ein Konto haben, finden Sie Ihren API-Schlüssel und Ihr API-Geheimnis oben auf dem Vonage-API-Dashboard.
Knotenpunkt & NPM
Um loszulegen, müssen Sie Node und NPM installiert haben. Diese Anleitung verwendet Node 8 und NPM 6. Stellen Sie sicher, dass sie installiert und aktuell sind.
Sowohl Node als auch NPM müssen installiert sein und die richtige Version haben. Gehen Sie zu nodejs.orgund laden Sie die richtige Version herunter und installieren Sie sie, falls Sie sie noch nicht haben.
Unser CLI
Um Ihre Anwendung einzurichten, müssen Sie Folgendes installieren unser CLI. Installieren Sie es mit NPM im Terminal.
Mit diesem Befehl können Sie überprüfen, ob Sie die richtige Version haben. Zum Zeitpunkt des Schreibens verwendete ich die Version 0.4.9-beta-3
.
Um die Schritte in diesem Artikel zu befolgen, müssen Sie sich Melden Sie sich für ein kostenloses Vonage-Konto an und konfigurieren Sie die CLI mit dem API-Schlüssel und dem Geheimnis, die Sie auf Ihrem Dashboard finden.
Express.js CLI
installieren Express-Generator. Sie werden diese Bibliothek verwenden, um einen einfachen Express.js-Server zu erstellen.
Mit diesem Befehl können Sie überprüfen, ob Sie die richtige Version haben. Zum Zeitpunkt des Schreibens verwendete ich die Version 4.16.1
.
Vue.js CLI
Installieren Sie die Vue CLI. Sie werden diese Bibliothek verwenden, um eine einfache Vue.js-Client-Anwendung zu erstellen.
Mit diesem Befehl können Sie überprüfen, ob Sie die richtige Version haben. Zum Zeitpunkt des Schreibens verwendete ich die Version 4.1.2
von @vue/cli
.
Von Grund auf neu
Diese Serie wird Sie von einem leeren Verzeichnis bis hin zu einer realen Chat-Anwendung mit Express.js als Server führen.
Einen Projektordner erstellen
Legen Sie als erstes ein Verzeichnis für Ihre Arbeit an.
Wechseln Sie dann in das neue Verzeichnis.
Erzeugen eines Express.js-Servers
Als Nächstes erstellen Sie einen einfachen Server mit dem Express.js-Generator. Das Tolle an diesem CLI ist, dass es die ausführbare Serverdatei und die Anwendung unabhängig voneinander konfiguriert. Das heißt, es übernimmt die Philosophie des extrem leichtgewichtigen und coolen Express Hallo Welt. Es teilt es auf in die ebenso coole ausführbare Datei für die Konfiguration des Servers und der Umgebung bin/www
. und die Anwendung selbst app.js
.
Da es sich bei der Anwendung hauptsächlich um eine API handelt, ist es besser, die Installation von Elementen zur Handhabung von Vorlagendateien zu überspringen. Verwenden Sie dazu die --no-view
Option.
Wenn Sie die Verwendung von git
als Versionskontrollsystem zu verwenden, sollten Sie die Verwendung von --git
zur Erzeugung der richtigen .gitignore
Datei zu erzeugen.
Da Sie sich bereits im Projektverzeichnis befinden, geben Sie die Option --force
und verwenden Sie .
als Verzeichnis an. Dann wird das Tool die Anwendung im aktuellen Verzeichnis ohne Probleme generieren.
Installieren Sie dann die Abhängigkeiten.
Den Express.js-Server lokal ausführen
Sobald der Server erstellt und die Abhängigkeiten installiert sind, können Sie ihn starten, um sicherzustellen, dass alles wie erwartet funktioniert.
Sie können überprüfen, ob es unter der Standard-URL funktioniert, localhost:3000.
Screenshot of a basic Express.js server running
Routen und Kontrolleure
Die generierte Anwendung enthält das notwendige Routing. Routing bedeutet, dass festgelegt wird, wie eine Anwendung eine Anfrage an eine bestimmte URL und Methode (GET, POST usw.) behandelt. Controller hingegen sind für den Ablauf der Anwendungsausführung verantwortlich. Die generierte Anwendung erstellt keine Controller und verwendet die Router, um eine Antwort zurückzugeben.
Erstellen Sie ein neues Controller-Verzeichnis.
Erstellen Sie einen neuen Controller in diesem Verzeichnis mit dem Namen server.js
.
Öffnen Sie controllers/server.js
und erstellen Sie die erste Methode für den Server.
// controllers/server.js
exports.status = function(req, res, next) {
res.json({
status: 'ok'
});
};
Dieser Controller könnte später dafür verantwortlich sein, den Client mit einer Bedingung zu versorgen, die von verschiedenen Überprüfungen abhängt, z. B. ob der Chat-Dienst in Betrieb ist oder ob er eine Verbindung zu den Daten herstellen kann. Die Idee ist, dass bei Problemen auf dem Server der Client den Fehler empfängt, ihn anständig behandelt und den Benutzer darüber informiert, was passiert ist.
Um diese Controller-Methode anzufordern, erstellen Sie eine neue Route im bestehenden Routenverzeichnis mit dem Namen server.js
.
Öffnen Sie routes/server.js
und fügen Sie den unten gezeigten Code ein.
// routes/server.js
var express = require('express');
var router = express.Router();
var serverController = require('../controllers/server');
router.get('/status', serverController.status);
module.exports = router;
Dies leitet einen Pfad (/status
) an eine Controller-Methode (serverController.status
). Die Route liefert das Ergebnis der Controller-Methode als Antwort an den Client.
Um diese Route zur App hinzuzufügen, müssen Sie app.js
bearbeiten und diese Änderungen vornehmen.
// app.js
- var indexRouter = require('./routes/index');
- var usersRouter = require('./routes/users');
...
- app.use('/', indexRouter);
- app.use('/users', usersRouter);
+ app.use('/api/server', require('./routes/server'));
Dann können Sie fortfahren und die routes/index.js
und routes/users.js
Dateien.
Starten Sie die Anwendung erneut mit npm start
; dann können Sie auf die neue Route unter localhost:3000/api/server/status.
Screenshot of a basic server status API endpoint
Einen Client erstellen
Verwenden Sie die Vue CLI, um eine neue Client-Anwendung zu erstellen.
Einen Vue.js-Client generieren
Führen Sie den Befehl create mit der Vue CLI aus. Dieses Tool generiert eine einfache Vue-Anwendung, auf der unser Chat-Client basiert. Es fordert mit einigen Optionen, und Sie können die Standardeinstellungen auswählen.
Der Client wird im Verzeichnis client
Verzeichnis wie im Befehl angegeben. Er läuft auch npm install
automatisch.
Wechseln Sie nun in das client
Verzeichnis.
Um den Client zu starten, verwenden Sie diesen Befehl. Beachten Sie, dass er sich von der Art und Weise unterscheidet, wie Sie den Server ausführen.
Dann können Sie auf Ihren Client unter localhost:8080. Sie werden feststellen, dass er standardmäßig einen anderen Port hat. In der Entwicklungsumgebung hilft uns das, wie Sie gleich sehen werden, wenn wir den Server und den Client gleichzeitig laufen lassen.
Screenshot of a basic Vue.js client running
Hot Reloading der Express.js Server Dateien
In der Regel möchten die meisten Entwickler, dass die Anwendung die Dateien automatisch neu lädt, wenn sie sie bearbeiten. Um dies zu erreichen, werden wir den Server so einrichten, dass er nodemon um die Dateien bereitzustellen.
Nodemon installieren
Wenn Sie sich immer noch in dem client
Verzeichnis befinden, können Sie mit diesem Befehl eine Ebene höher in das Hauptverzeichnis des Projekts wechseln, ..
das ein übergeordnetes Verzeichnis bezeichnet.
Installieren Sie nun Nodemon als Entwicklungsabhängigkeit. Installieren Sie eine Entwicklungsabhängigkeit, indem Sie --save-dev
als Option des Befehls hinzufügen.
Einmal installiert, können Sie die package.json
Datei bearbeiten und das start
Skript wie hier gezeigt ändern.
+ "dev:server": "nodemon ./bin/www",
"start": "node ./bin/www"
Wenn Sie die Anwendung mit npm run dev:server
starten, verwendet sie Nodemon. Nodemon überwacht die Anwendungsdateien und startet den Dienst automatisch neu, wenn sich eine Datei ändert.
Anmerkung: Dazu gehören auch die Metadaten der Dateien, wie z. B. Berechtigungen und Änderungsdatum.
Server und Client gleichzeitig ausführen
Im weiteren Verlauf dieses Leitfadens werden Sie sowohl den Client als auch Express.js gleichzeitig ausführen müssen. Es gibt eine Gleichzeitige Paket, das es sehr einfach macht, getrennte Anwendungen aneinander anzulehnen.
Gleichzeitige Installation
Gleichzeitige Installation, auch als Entwicklungsabhängigkeit.
Beide Entwicklungsumgebungen starten
Ändern Sie die package.json
Datei für den Server, wie hier gezeigt. Im letzten Abschnitt haben wir ein dev:server
Skript hinzugefügt, das den Server mit Nodemon ausführt. Jetzt fügen wir ein dev:client
Skript auf der Stammebene des Projekts hinzu, um den Client auch von hier aus zu starten.
"dev:server": "nodemon ./bin/www",
+ "dev:client": "cd client && npm run serve",
"start": "node ./bin/www"
Fügen Sie nun diese Zeile hinzu, um die beiden mit Concurrently zu kombinieren. Sie werden die Option --kill-others-on-fail
was bedeutet, dass Concurrently alle Dienste anhält, wenn ein schwerer Fehler auftritt. Ohne diese Option müssten Sie, wenn Node oder Webpack (das den Client bedient) auf einen Fehler stößt, Concurrently neu starten, damit sowohl Client als auch Server wieder laufen.
"dev:server": "nodemon ./bin/www",
"dev:client": "cd client && npm run serve",
+ "dev": "concurrently --kill-others-on-fail 'npm run dev:server' 'npm run dev:client'",
"start": "node ./bin/www"
Wenn Sie die Anwendung mit npm run dev
starten, werden sowohl der Server als auch der Client gemeinsam unter localhost:3000 und localhost:8080 respektvoll.
Screenshot of a Express.js and Vue.js running concurrently
Proxy-API-Anfragen an den Express.js-Server
Um in der Entwicklungsumgebung vom Client aus Anfragen an den Server zu stellen, muss ein Proxy eingerichtet werden. Sie können Vue.js so konfigurieren, dass es alle Anfragen, die mit einer bestimmten Route beginnen, proxyisiert.
Konfigurieren Sie den Proxy
Erstellen Sie dazu eine neue Datei im Verzeichnis client
Verzeichnis eine neue Datei mit dem Namen vue.config.js
. Wechseln Sie dann in das Client-Verzeichnis.
Erstellen Sie eine leere Konfigurationsdatei.
Fügen Sie den folgenden Code ein.
// vue.config.js
module.exports = {
devServer: {
proxy: {
"/api": {
target: "http://localhost:3000",
secure: false
}
}
}
};
Dieser Code teilt Vue.js mit, dass bei der Ausführung von devServer
dass alle Routen, die mit /api
übereinstimmen, auf http://localhost:3000
. Dies ist die URL für den Server, wenn Sie das dev
Skript, oder das dev:server
Skript direkt ausführen.
Einen API-Verbraucherdienst erstellen
Um Anfragen von Vue.js an unseren Server vom Client aus zu stellen, installieren Sie Axios, welches ein Versprechen basierter HTTP-Client zur Verwendung im Browser-seitigen Code.
Jetzt, wo Sie Axios installiert haben und Anfragen zwischen dem Server und dem Client projizieren können, ist es an der Zeit, diese Anfragen zu stellen. Im Verzeichnis des Clients src/
Verzeichnis erstellen Sie ein neues Verzeichnis namens services
um alle API-Dienstdateien zu enthalten.
Erstellen Sie einen abstrakten API-Dienst, der den Pfad für nachfolgende API-Dienste vorgibt. Denken Sie daran, dass in der Entwicklungsumgebung, /api
als Proxy für den Server dient.
Verwenden Sie den folgenden Code, um einen abstrakten API-Dienst zu erstellen, der eine Axios-Instanz zurückgibt.
// src/services/Api.js
import axios from 'axios'
export default() => {
return axios.create({
baseURL: `/api`,
headers: {'Cache-Control': 'no-cache, no-store, no-transform'}
})
}
Sie haben bereits einen server/status
Endpunkt im Server erstellt, auf den Sie bei laufendem Server über localhost:3000/api/server/status.
Um diesen Endpunkt von der Client-Anwendung aus zu nutzen, erstellen Sie eine Datei für den Dienst.
Und fügen Sie diesen Code hinzu, um eine fetchStatus
Methode für den neuen Server
Dienst.
// src/services/Server.js
import Api from '@/services/Api'
export default {
fetchStatus () {
return Api().get('server/status')
}
}
Abfrage des Serverstatus im Client
Nachdem Sie nun einen Dienst erstellt haben, der Anfragen an den Server stellt, importieren Sie den Dienst in Ihre App.vue
Komponente.
Öffnen Sie App.vue
und fügen Sie die Zeilen wie hier gezeigt ein.
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
- <HelloWorld msg="Welcome to Your Vue.js App"/>
+ <HelloWorld v-if="!!server.status && server.status === 'ok'" msg="Welcome to Your Vue.js App"/>
+ <template v-else>
+ <HelloWorld msg="Connecting..."/>
+ </template>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
+ import ServerService from '@/services/Server'
export default {
name: 'App',
components: {
HelloWorld
+ },
+ data () {
+ return {
+ server: {},
+ }
+ },
+ mounted () {
+ this.getServerStatus()
+ },
+ methods: {
+ getServerStatus () {
+ ServerService.fetchStatus()
+ .then((response) => {
+ this.server = response.data
+ })
+ }
}
}
</script>
# ...
Hier verwendet es die HelloWorld Komponente, um dem Benutzer den Status der Anfrage anzuzeigen.
Hinweis: Denken Sie daran, dass Sie sich bei diesem Schritt wahrscheinlich noch im Client-Verzeichnis befinden. Das erneute Starten (oder Neustarten) der Entwicklungsumgebung mit
npm run dev
muss im Server-Verzeichnis ausgeführt werden (cd ..
um vom Client zum Server zu wechseln).
Sobald er läuft, können Sie auf den Client unter localhost:8080. Wenn Sie schnell genug sind, können Sie die Meldung "Connecting..." sehen.
Screenshot of the Vue.js client connecting to the Express.js server
Laden von Bildschirmen mit Tailwind und FontAwesome
Während Sie im letzten Abschnitt eine Verbindung zum Server hergestellt haben, haben Sie die HalloWelt Komponente wiederverwendet. Jetzt verwenden Sie die Tailwind CSS Low-Level-CSS-Framework und FontAwesome einen Ladebildschirm für den Client erstellen.
Wenn Sie dies unabhängig von dieser Anwendung üben möchten, habe ich über Verwendung von Tailwind CSS mit Vue.js in einem separaten Leitfaden für Sie beschrieben.
Tailwind CSS installieren
Um Tailwind CSS im Client zu verwenden, müssen wir es als Abhängigkeit installieren und den Client so konfigurieren, dass er es verwendet.
Anmerkung: Diese Installation ist für den Client, nicht für den Server. Stellen Sie also sicher, dass Sie sich im
client
Verzeichnis befinden.
Vue.js Client für Tailwind CSS konfigurieren
Wenn die Client-App gebaut wird, sucht sie nach einer postcss.config.js
Datei, die eine Konfigurationsdatei ist, die Vue.js verwendet, um zu wissen, wie CSS zu verarbeiten ist. Die Tailwind-CSS-Installation sagt, dass Sie es als Plugin in Ihrer Build-Kette hinzufügen möchten.
Die von Vue generierte Demo-App erstellt keine postcss.config.js
Datei. Tun Sie das jetzt.
Und konfigurieren Sie ihn mit diesem Code.
// postcss.config.js
const autoprefixer = require('autoprefixer');
const tailwindcss = require('tailwindcss');
module.exports = {
plugins: [
tailwindcss,
autoprefixer,
],
};
Tailwind als CSS-Asset hinzufügen
Die Demo-App erstellt auch keine CSS-Assets. Stattdessen verwendet sie CSS innerhalb von Vue.js-Komponenten, was viele Anleitungen zeigen. Um Tailwind einzubinden, erstellen Sie also eine einfache CSS-Datei im Assets-Verzeichnis mit diesen Befehlen oder Ihrem Editor.
Verwenden Sie diesen Code, um die Tailwind-CSS-Basis, -Komponenten und -Hilfsmittel in Ihren CSS-Aufbau einzubinden. Kopieren Sie ihn und fügen Sie ihn in Ihre neue index.css
Datei ein.
/* src/assets/styles/index.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
Tailwind-CSS einbinden
Bearbeiten Sie nun Ihre main.js
Datei zum Importieren index.css
in den Client.
// src/main.js
import Vue from 'vue';
import App from './App.vue';
+ import './assets/styles/index.css';
Vue.config.productionTip = false;
new Vue({
render: h => h(App),
}).$mount(`#app`);
Screenshot of the Vue.js client styles after Tailwind CSS preflight enabled
Anmerkung: Tailwind CSS verwendet Preflight (erstellt auf der Grundlage von normalize.css), um das gesamte Styling in verschiedenen Browsern an dieselbe Stelle zurückzusetzen. Sie werden feststellen, dass es einige Standard-Stylings zerstört hat. Machen Sie sich keine Sorgen, Sie werden dies bald vollständig ersetzen.
FontAwesome installieren
Die Erstellung eines Lade-Spinners erfolgt mit einer Schriftart, die einen gekerbten Kreis darstellt. Installieren Sie es auf dem Client mit diesem Befehl.
FontAwesome einbeziehen
Bearbeiten Sie main.js
erneut und fügen Sie diesen Code hinzu.
// src/main.js
import Vue from 'vue';
import App from './App.vue';
+ import { library } from '@fortawesome/fontawesome-svg-core'
+ import { fas } from '@fortawesome/free-solid-svg-icons'
+ import { far } from '@fortawesome/free-regular-svg-icons'
+ import { FontAwesomeIcon, FontAwesomeLayers } from '@fortawesome/vue-fontawesome'
import './assets/styles/index.css';
+ library.add(fas, far)
+ Vue.component('font-awesome-icon', FontAwesomeIcon)
+ Vue.component('font-awesome-layers', FontAwesomeLayers)
Vue.config.productionTip = false;
new Vue({
render: h => h(App),
}).$mount(`#app`);
Den Ladebildschirm erstellen
Um eine neue Vue.js-Komponente zu erstellen, die als Ladebildschirm verwendet werden soll, fügen Sie eine neue Komponentendatei mit diesem Befehl oder Ihrem Editor hinzu.
Fügen Sie nun mit diesem Code den Spinner zu einem durchsichtigen Overlay im Vollbildmodus hinzu.
<template>
<div class="w-screen h-screen fixed block top-0 left-0 bg-white opacity-75 z-50 flex">
<span class="text-green-500 opacity-75 top-1/2 m-auto text-center">
<font-awesome-icon icon="circle-notch" class="fa-spin fa-5x mb-2"/>
<p class="text-base">
{{ message }}
</p>
</span>
</div>
</template>
<script>
export default {
name: 'Loading',
props: {
message: String
}
}
</script>
Und fügen Sie den Ladebildschirm durch Bearbeiten von App.vue
und ersetzen Sie die Wiederverwendung von HelloWorld.vue
durch die neue Komponente.
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld v-if="!!server.status && server.status === 'ok'" msg="Welcome to Your Vue.js App"/>
<template v-else>
- <HelloWorld msg="Connecting..."/>
+ <Loading message="Connecting..." />
</template>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
+ import Loading from '@/components/Loading.vue'
import ServerService from '@/services/Server'
export default {
name: 'App',
components: {
- HelloWorld
+ HelloWorld,
+ Loading
},
data () {
return {
server: {},
}
},
mounted () {
this.getServerStatus()
},
methods: {
getServerStatus () {
ServerService.fetchStatus()
.then((response) => {
this.server = response.data
})
}
}
}
</script>
...
Screenshot of the Vue.js client loading screen with spinner
Anmerkung: Um dies zu testen, können Sie die Antwort
status
im Verzeichnis des Serverscontrollers/server.js
Verzeichnis so ändern, dass sie etwas anderes zurückgibt alsok
.
Behandlung von Serverfehlern im Client
Es ist an der Zeit, dem Client eine Fehlerbehandlung hinzuzufügen.
Abfangen von Anfragefehlern
Bearbeiten Sie App.vue
und fügen Sie den folgenden Code hinzu.
...
<script>
import HelloWorld from './components/HelloWorld.vue'
import Loading from '@/components/Loading.vue'
import ServerService from '@/services/Server'
export default {
name: 'App',
components: {
HelloWorld,
Loading
},
data () {
return {
server: {},
+ error: null
}
},
mounted () {
this.getServerStatus()
},
methods: {
getServerStatus () {
ServerService.fetchStatus()
.then((response) => {
this.server = response.data
})
+ .catch((err) => {
+ this.error = { title: 'Couldn\'t connect to Server', message: 'There may be a problem with your connection. Please check and try again.', reason: err.reason }
+ })
}
}
}
</script>
...
Wenn nun ein Fehler vom Server zurückkommt, wird dieser vom Client abgefangen und zu den Komponentendaten hinzugefügt.
Erstellen einer Fehlerkomponente
Um einen Fehler anzuzeigen, erstellen Sie eine leere Error.vue
Komponente mit diesem Befehl oder Ihrem Editor.
Fügen Sie diesen Code hinzu, der ebenfalls FontAwesome-Symbole (und -Ebenen) verwendet, um eine geeignete Grafik zu erstellen.
<template>
<div class="flex h-screen">
<div class="m-auto text-center w-2/3">
<font-awesome-layers class="fa-10x mb-10">
<font-awesome-icon icon="globe-americas" transform="grow-4" class="text-gray-500"/>
<font-awesome-icon :icon="['far', 'circle']" transform="grow-5" class="outline text-white"/>
<font-awesome-icon icon="times" class="cross text-red-500" transform="shrink-8 right-5 up-5"/>
</font-awesome-layers>
<h1 class="text-3xl mb-3 text-gray-800">{{ error.title }}</h1>
<p class="text-base text-gray-800">{{ error.message }}</p>
<p class="invisible">{{ error.reason }}</p>
</div>
</div>
</template>
<script>
export default {
name: 'Error',
props: {
error: Object
}
}
</script>
<style scoped>
.outline path {
stroke: white;
stroke-width: 20px;
}
.cross path {
stroke: white;
stroke-width: 20px;
}
</style>
Anzeige eines Serverfehlers auf dem Client
Noch einmal bearbeiten App.vue
fügen Sie den Code wie hier gezeigt ein. Entfernen Sie das Bild zur gleichen Zeit.
<template>
<div id="app">
- <img alt="Vue logo" src="./assets/logo.png">
<HelloWorld v-if="!!server.status && server.status === 'ok'" msg="Welcome to Your Vue.js App"/>
<template v-else>
- <Loading message="Connecting..." />
+ <Loading v-if="!error" message="Connecting..." />
+ <Error v-else :error="error" />
</template>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
+ import Error from '@/components/Error.vue'
import Loading from '@/components/Loading.vue'
import ServerService from '@/services/Server'
export default {
name: 'App',
components: {
HelloWorld,
+ Error,
Loading
},
data () {
return {
server: {},
error: null
}
},
mounted () {
this.getServerStatus()
},
methods: {
getServerStatus () {
ServerService.fetchStatus()
.then((response) => {
this.server = response.data
})
.catch((err) => {
this.error = { title: 'Couldn\'t connect to Server', message: 'There may be a problem with your connection. Please check and try again.', reason: err.reason }
})
}
}
}
</script>
...
Jetzt zeigt der Client die vom Server gesendeten Fehler an.
Screenshot of the Vue.js client catching a server error
Anmerkung: Um zu sehen, dass dies funktioniert, können Sie die Anwendung Ihres Servers ändern
controllers/server.js
und ersetzen Sieres.json
durchres.sendStatus(500)
ersetzen, um dem Client einen 500-Fehlercode zu liefern.
Dotenv-Umgebungsdateien verwenden
Sie sollten Schlüssel und Anmeldeinformationen nicht fest in Ihrem Server, aber vor allem nicht in Ihrem Client programmieren.
Dotenv installieren
Installieren Sie dotenv
damit Sie Umgebungsvariablen setzen und in Ihrer Anwendung lesen können.
Anmerkung: Möglicherweise befinden Sie sich bei diesem Schritt im Client-Verzeichnis. Verwenden Sie
cd ..
um vom Client zum Server zu wechseln.
Erstellen einer Umgebungsdatei
Erstellen Sie eine leere Umgebungsdatei für den Server mit diesem Befehl oder Ihrem Editor.
Konfigurieren Sie die Umgebung
Bearbeiten Sie nun .env
und fügen Sie diese Beispielkonfiguration in die Datei ein. Das Token und die ID sind nicht echt.
Anmerkung:
.env
Dateien werden von Git ignoriert, da die erzeugte.gitignore
Datei hinzufügen.env
standardmäßig hinzufügen. Das Übertragen Ihrer.env
Datei ist ungefähr so sicher wie das Hardcoding Ihrer Anmeldedaten. Es wird auch deutlich, dass diese Anmeldeinformationen für diese Umgebung gelten, die lokal ausgeführt wird. Wenn Sie dies einsetzen, müssen Sie die Umgebung auf dem Server auf andere Weise verwalten. Heroku zum Beispiel bietet Ihnen ein Bedienfeld für die Konfiguration der Umgebung.
Laden Sie die Umgebung
Bearbeiten Sie nun die Server-Top-Datei, um die Umgebung beim Start der Anwendung einzubeziehen. Bearbeiten Sie bin/www
(sie hat keine Dateierweiterung) wie hier gezeigt.
#!/usr/bin/env node
+ require('dotenv').config();
/**
* Module dependencies.
*/
...
Server-Umgebungswerte an den Client weitergeben
Die erste Umgebungsvariable, die dem Client mitgeteilt werden muss, ist VONAGE_DEFAULT_CONVERSATION_ID
die Standard-"Raum"-ID für den Chat! Sie werden später zurückkommen und den Wert der Umgebungsvariablen bearbeiten.
Bearbeiten Sie controllers/server.js
und fügen Sie den hier gezeigten Code ein.
// controllers/server.js
exports.status = function(req, res, next) {
res.json({
+ defaultConversationId: process.env.VONAGE_DEFAULT_CONVERSATION_ID,
status: 'ok'
});
};
Benutzerendpunkte für die Client-Authentifizierung
In späteren Teilen dieser Serie wird ein Identitätsanbieter die vom Server gesendeten Benutzerdaten verwalten. In der Zwischenzeit sollten Sie auch diese Informationen fälschen und sie bearbeiten, wenn Sie sie haben.
Erstellen eines Benutzerendpunkts
Erstellen Sie einen Benutzerendpunkt, indem Sie zunächst einen user.js
Controller mit Ihrem Editor oder diesem Befehl erstellen.
Geben Sie ihm diesen Code.
// controllers/user.js
exports.session = function(req, res, next) {
res.json({
user: process.env.VONAGE_USER,
token: process.env.VONAGE_USER_TOKEN
});
};
Erstellen Sie nun mit Ihrem Editor oder diesem Befehl eine Route für den Zugriff auf die Endpunkte der Benutzersteuerung.
Und geben Sie ihm diesen Code.
// routes/user.js
const express = require('express');
const router = express.Router();
const userController = require('../controllers/user');
router.get('/session', userController.session);
module.exports = router;
Zum Schluss bearbeiten Sie Ihre app.js
Datei und fügen Sie die neue Route wie hier gezeigt ein.
// app.js
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var app = express();
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
+ app.use('/api/user', require('./routes/user'));
app.use('/api/server', require('./routes/server'));
module.exports = app;
Starten Sie die Anwendung erneut mit npm start
; dann können Sie auf die neue Route unter localhost:3000/api/user/session.
Screenshot of a user session API endpoint
Verbindung zur Vonage Conversation API
In diesem Abschnitt folgen die üblichen Schritte, wenn Sie bereits eines meiner Tutorials für die Client-Seite gelesen haben. Falls nicht, sind dies einfache Befehle, um unsere Vonage-Konversation zu erstellen, der Benutzer beitreten können.
Einrichten mit unserer CLI
Um sich als Benutzer mit der Konversations-API zu verbinden, müssen Sie zunächst eine Anwendung, eine Konversation und einen Benutzer erstellen.
Eine Anwendung erstellen
Erstellen Sie eine Anwendung mit RTC-Funktionen (Echtzeitkommunikation). Die Ereignis-URL empfängt ein Live-Protokoll von Ereignissen, die im Dienst stattfinden, wie z. B. das Betreten/Austreten von Benutzern oder das Senden von Nachrichten. Dies ist vorerst eine Beispiel-URL, aber Sie werden in späteren Teilen unserer Serie in der Lage sein, Ereignisse zu erfassen und darauf zu reagieren.
Eine Konversation schaffen
Zweitens: Erstellen Sie eine Unterhaltung, die wie ein Chatroom funktioniert. Oder ein Container für Nachrichten und Ereignisse.
Erstellen Sie Ihren Benutzer
Legen Sie nun einen Benutzer für sich selbst an.
Anmerkung: In dieser Demo werden Sie nicht zwischen zwei Benutzern chatten. Andere Anleitungen zeigen Ihnen, wie Sie Unterhaltungen zwischen mehreren Benutzern erstellen können. Dieser Leitfaden konzentriert sich auf die einfache, aber ansprechende Gestaltung Ihrer Nachrichten-UI.
Hinzufügen des Benutzers zu einer Konversation
Als Nächstes fügen Sie den neuen Benutzer zur Konversation hinzu. Ein Benutzer kann Mitglied einer Anwendung sein, muss aber dennoch der Unterhaltung beitreten.
Ein Benutzer-Token generieren
Zum Schluss erzeugen Sie für Ihren neuen Benutzer ein Token. Dieses Token repräsentiert den Benutzer beim Zugriff auf die Anwendung. Dieses Zugriffstoken identifiziert den Benutzer, so dass jeder, der es benutzt, als der richtige Benutzer angesehen wird.
In der Praxis werden Sie die Anwendung mit diesem Token konfigurieren. In der Produktion sollten diese geschützt, geheim gehalten und der Client-Anwendung, wenn überhaupt, nur sehr vorsichtig zugänglich gemacht werden.
Der Token ist nur 24 Stunden lang verwendbar. Danach müssen Sie diesen Befehl erneut ausführen nexmo jwt:generate
Befehl erneut ausführen, um Ihrem Client-Benutzer erneut Zugriff zu gewähren.
Speichern Sie die Berechtigungsnachweise in der Umgebung
Bearbeiten Sie nun .env
und fügen Sie die von Ihnen erstellten Anmeldeinformationen hinzu.
Erstellen eines Dienstes für die Benutzersitzung
Erstellen Sie einen User.js
Dienst, um den Endpunkt der Benutzersitzung von der Client-Anwendung zu nutzen.
Erstellen Sie die Datei mit diesem Befehl oder Ihrem Editor.
Und fügen Sie diesen Code hinzu, um eine fetchSession
Methode für den neuen User
Dienst.
// src/services/User.js
import Api from '@/services/Api'
export default {
fetchSession () {
return Api().get('user/session')
}
}
Verbinden Sie den Client mit der Konversations-API
Um den Client mit der Konversations-API zu verbinden, müssen Sie die neueste Version der nexmo-client
.
Erstellen Sie eine neue Vonage.vue
Komponente mit Hilfe Ihres Editors oder des unten stehenden Befehls, die die Aufgabe hat, sich mit der Conversation-API unter Verwendung der nexmo-client
Bibliothek.
Ähnlich wie bei der App.vue
Komponente, fordert die Vonage.vue
Komponente Informationen zur Benutzersitzung vom Server ab, indem sie die Loading.vue
und Error.vue
Komponenten auf die gleiche Weise.
<template>
<div>
<HelloWorld v-if="!!app && !!conversation" msg="Welcome to Your Vue.js App"/>
<template v-else>
<Loading v-if="!error" message="Logging you in..." />
<Error v-else :error="error" />
</template>
</div>
</template>
<script>
import HelloWorld from '@/components/HelloWorld.vue'
import Loading from '@/components/Loading.vue'
import Error from '@/components/Error.vue'
import UserService from '@/services/User'
import Client from 'nexmo-client'
export default {
name: 'Vonage',
props: {
server: Object
},
components: {
ChatWindow,
Error,
Loading
},
data () {
return {
app: null,
conversation: null,
error: null
}
},
mounted () {
this.fetchSession()
},
methods: {
_errorHandler (err) {
this.error = { title: 'Chat Service Error', message: err.reason }
},
fetchSession () {
UserService.fetchSession()
.then((response) => {
const { token } = response.data
new Client()
.createSession(token)
.then(app => {
this.app = app
return app.getConversation(this.$props.server.defaultConversationId)
})
.then((conversation) => {
this.conversation = conversation
})
.catch(this._errorHandler)
})
.catch(this._errorHandler)
}
}
}
</script>
Ersetzen Sie nun die Verwendung des HelloWorld.vue
durch die neue Vonage.vue
Komponente innerhalb von App.vue
indem Sie diese Änderungen vornehmen.
<template>
<div id="app">
- <HelloWorld v-if="!!server.status && server.status === 'ok'" msg="Welcome to Your Vue.js App"/>
+ <Vonage v-if="!!server.status && server.status === 'ok'" :server="server" />
<template v-else>
<Loading v-if="!error" message="Connecting..." />
<Error v-else :error="error" />
</template>
</div>
</template>
<script>
- import HelloWorld from './components/HelloWorld.vue'
+ import Vonage from '@/components/Vonage.vue'
import Error from '@/components/Error.vue'
import Loading from '@/components/Loading.vue'
import ServerService from '@/services/Server'
export default {
name: 'App',
components: {
- HelloWorld,
+ Vonage,
Error,
Loading
},
data () {
return {
server: {},
error: null
}
},
mounted () {
this.getServerStatus()
},
methods: {
getServerStatus () {
ServerService.fetchStatus()
.then((response) => {
this.server = response.data
})
.catch((err) => {
this.error = { title: 'Couldn\'t connect to Server', message: 'There may be a problem with your connection. Please check and try again.', reason: err.reason }
})
}
}
}
</script>
Nach dem Ladebildschirm "Connecting..." sehen Sie nun einen Ladebildschirm "Logging you in...", bevor die HelloWorld.vue
Komponente lädt.
Screenshot of client logging into the Conversation API
Hinweis: Sie erreichen Hello World nur, wenn Ihre Anwendung erfolgreich eine Verbindung zum Server hergestellt hat, einen "OK"-Status erhalten hat, die Benutzersitzung angefordert und dann das Token des Benutzers verwendet hat, um sich mit der Conversation-API unter Verwendung der
nexmo-client
Bibliothek.
Erstellen Sie die Chat-Komponenten
Jetzt sind Sie mit der Konversations-API verbunden und können mit der Erstellung Ihrer Messaging-Oberfläche beginnen. Beginnen Sie zunächst mit der Grundstruktur Ihrer Anwendung, dem Chat-Fenster.
Chat-Fenster
Legen Sie dazu die Komponenten ChatWindow.vue
, ChatWindowHeader.vue
, ChatWindowEvents.vue
, und ChatWindowFooter.vue
mit dem Befehl oder Ihrem Editor.
Bearbeiten Sie ChatWindow.vue
und geben Sie den folgenden Code ein.
<template>
<div class="flex flex-col min-h-screen max-h-screen bg-white overflow-hidden">
<ChatWindowHeader :channelName="'#' + conversation.display_name"/>
<ChatWindowEvents :conversation="conversation" :user="user" :members="members" />
<ChatWindowFooter :conversation="conversation" />
</div>
</template>
<script>
import ChatWindowHeader from '@/components/ChatWindowHeader.vue'
import ChatWindowEvents from '@/components/ChatWindowEvents.vue'
import ChatWindowFooter from '@/components/ChatWindowFooter.vue'
export default {
name: 'ChatWindow',
props: {
app: Object,
conversation: Object
},
components: {
ChatWindowHeader,
ChatWindowEvents,
ChatWindowFooter
},
data () {
return {
user: {},
members: new Map(),
}
},
mounted () {
this.user = this.$props.app.me
this.fetchMembers()
},
methods: {
fetchMembers () {
this.members = this.$props.conversation.members
}
}
}
</script>
Die ChatWindow.vue
Komponente ist für die Strukturierung des Chat-Layouts verantwortlich. Kopfzeile oben, Nachrichten in der Mitte und die Fußzeile unten. Sie übergibt den Kanalnamen, mit einem vorangestellten Hash, als channelName
an die Kopfzeile. Außerdem werden die Konversation, der Benutzer und die Mitglieder an die Ereigniskomponente weitergegeben. Anschließend wird die Konversation an die Fußzeile weitergegeben.
Als nächstes bearbeiten Sie ChatWindowHeader.vue
und geben Sie diesen Code ein.
<template>
<div class="border-b flex px-6 py-2 items-center">
<div class="flex flex-col">
<h4 class="text-grey-darkest mb-1 font-extrabold">{{ channelName }}</h4>
</div>
</div>
</template>
<script>
export default {
name: 'ChatWindowHeader',
props: {
channelName: String,
members: Number
}
}
</script>
Die Komponente ChatWindowHeader.vue
Komponente zeigt zunächst nur den Kanalnamen an.
Bearbeiten Sie nun ChatWindowEvents.vue
und geben Sie ihr diesen Code.
<template>
<div class="py-4 flex-auto overflow-y-auto" ref="chatWindow">
<template v-if="!!events.length">
<div class="px-6 hover:bg-gray-100" v-for="event in events" v-bind:key="'event' + event.id">
<div v-if="event.type === 'text'">
<strong>{{ members.get(event.from).display_name }}</strong> on <strong>{{ event.timestamp.split("T")[0] }}</strong> at <strong>{{ event.timestamp.split("T")[1].split(".")[0] }}</strong> says {{ event.body.text }}
</div>
<div v-else-if="event.type === 'member:joined'">
<strong>{{ event.body.user.display_name }}</strong> has joined <strong>#{{ event.conversation.display_name }}</strong>.
</div>
</div>
</template>
<Loading v-else message="Loading messages..." />
<Error v-else :error="error" />
</div>
</template>
<script>
import Loading from '@/components/Loading.vue'
import Error from '@/components/Error.vue'
export default {
name: 'ChatWindowEvents',
components: {
Loading,
Error
},
props: {
user: Object,
conversation: Object,
members: Map,
},
data () {
return {
events: [],
error: null
}
},
mounted () {
this.getEventHistory()
this.registerListeners()
},
methods: {
registerListeners () {
const { conversation } = this.$props
conversation.on('text', (user, event) => {
this.events.push(event)
})
conversation.on("member:joined", (user, event) => {
this.events.push(event)
})
},
getEventHistory () {
this.$props.conversation
.getEvents({ page_size: 40, order: 'desc' })
.then(eventsPage => {
eventsPage.items.forEach(event => {
this.events.unshift(event)
})
})
.catch(err => {
this.error = { title: 'Chat Service Error', message: err.message }
})
},
},
}
</script>
Die Komponente ChatWindowEvents.vue
Komponente ist für die Auflistung aller Ereignisse in der Konversation zuständig. Sie tut dies von oben nach unten, wobei ältere Ereignisse oben im Fenster stehen. Blättern Sie nach unten, um die neuesten Nachrichten zu sehen. Es werden insgesamt 40 Nachrichten geladen. Später in dieser Serie werden Sie sehen, wie Sie ältere Nachrichten laden können.
Schließlich bearbeiten Sie ChatWindowFooter.vue
und geben Sie ihr diesen Code.
<template>
<div class="px-4">
<textarea
v-bind:class="{
'disabled:opacity-75': isSending,
'bg-gray-300': isSending,
'border-gray-400': isSending,
'border-gray-400': !isSending
}"
v-bind:disabled="isSending"
v-bind:value="inputMessage"
v-on:input="inputMessage = $event.target.value"
v-on:keydown.enter.exact.prevent
v-on:keyup.enter.exact="sendMessage"
v-on:keyup="typingEvents"
type="text"
:placeholder="'Message ' + conversation.display_name"
class="w-full rounded border text-sm border-gray-700 overflow-hidden py-2 px-4 resize-none"
rows="1"
ref="inputBox"
>
</textarea>
<div class="grid grid-cols-10 h-6 text-xs">
</div>
</div>
</template>
<script>
export default {
name: 'ChatWindowFooter',
props: {
conversation: Object,
},
data () {
return {
inputMessage: '',
isSending: false
}
},
methods: {
typingEvents () {
this.resizeInput()
},
resizeInput () {
const inputRows = this.inputMessage.split(/\r?\n/).length
this.$refs.inputBox.rows = inputRows
},
sendMessage () {
if (this.inputMessage.replace(/\s/g,'').length > 0) {
this.isSending = true
this.$props.conversation
.sendText(this.inputMessage.trim())
.then(() => {
this.isSending = false
this.$nextTick(() => {
this.$refs.inputBox.focus()
this.inputMessage = ''
this.resizeInput()
});
})
.catch(err => {
console.error(err) // eslint-disable-line no-console
})
}
}
}
}
</script>
<style scoped>
textarea:focus{
outline: none;
}
</style>
Wenn Sie Ihre Komponenten erstellt haben, bearbeiten Sie Vonage.vue
und ersetzen Sie HelloWorld.vue
durch Ihre neue ChatWindow.vue
Komponente.
<template>
<div>
- <HelloWorld v-if="!!app && !!conversation" msg="Welcome to Your Vue.js App" />
+ <ChatWindow v-if="!!app && !!conversation" :app="app" :conversation="conversation" />
<template v-else>
<Loading v-if="!error" message="Logging you in..." />
<Error v-else :error="error" />
</template>
</div>
</template>
<script>
- import HelloWorld from '@/components/HelloWorld.vue'
+ import ChatWindow from '@/components/ChatWindow.vue'
import Loading from '@/components/Loading.vue'
import Error from '@/components/Error.vue'
import UserService from '@/services/User'
import VonageClient from 'nexmo-client'
export default {
name: 'Vonage',
props: {
server: Object
},
components: {
- HelloWorld,
+ ChatWindow,
Error,
Loading
},
data () {
return {
app: null,
conversation: null,
error: null
}
},
mounted () {
this.fetchSession()
},
methods: {
...
}
}
</script>
Hier gibt es viel zu kopieren und einzufügen. Sobald es läuft, sehen Sie, wie es aussieht.
Screenshot of the chat client working
Beachten Sie den Rand, der von der Demo-Anwendung übrig geblieben ist! Zum Schluss entfernen Sie diese Formatierung durch Bearbeiten von src/App.vue
wie folgt.
<template>
<div id="app">
<Vonage v-if="!!server.status && server.status === 'ok'" :server="server" />
<template v-else>
<Loading v-if="!error" message="Connecting..." />
<Error v-else :error="error" />
</template>
</div>
</template>
<script>
...
</script>
-
- <style>
- #app {
- font-family: Avenir, Helvetica, Arial, sans-serif;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
- text-align: center;
- color: #2c3e50;
- margin-top: 60px;
- }
- </style>
Wenn Sie schon dabei sind, löschen Sie HelloWorld.vue
. Zum Schluss.
Screenshot of the chat client working beautifully
Arbeits-Chat erreicht!
Teil 1, abgeschlossen! Sie haben einen Chat-Client erstellt, der langsam Slack ähnelt. Hier ist eine Liste mit dem, was Sie bisher gemacht haben:
Erstellung einer Express.js-Anwendung zur Verwendung als API
Erstellung einer Vue.js-Anwendung zur Verwendung als Client
Erstellte API-Endpunkte in Express.js
Verwendete API-Endpunkte in Vue.js
Hot-Reloading von Express.js-Dateien hinzugefügt
Gleichzeitiges Hinzufügen zu Express.js und Vue.js mit einem Befehl
Proxied API-Anfragen von Vue.js zu Express.js
Gestyltes Vue.js mit Tailwind CSS
Animierte Icons mit FontAwesome
Erstellung einer Komponente zum Laden im Vollbildmodus
Verbunden mit der Vonage Conversation API
Erstellen einer Messaging UI
Wenn Sie an der kompletten Demo-App interessiert sind, schauen Sie sich bitte das GitHub Repo für meinen Vue.js Slack Klon bis jetzt.
Bleiben Sie dran für Teil 2, in dem wir uns mit den folgenden Must-haves der Benutzererfahrung beschäftigen.
Unendliches Scrollen der Geschichte
Festgehaltene Bildlaufpositionen beim Scrollen der Historie
Ping nach unten beim Senden von Nachrichten
Benachrichtigungen über ungelesene Nachrichten
Schaltfläche "Zum Lesen markieren
Anzahl der Kanalmitglieder
Löschung von Nachrichten
Benachrichtigung über Ereignisse bei der Benutzereingabe (mehrere Personen tippen)
Mehrzeilige Meldungen
Slack-Stil Markdown
Am Ende von Teil 2 werden Sie etwas haben, das ungefähr so aussieht!
Screenshot of the sneak peek of chat from Part 2
Weitere Lektüre
Hier finden Sie einige weitere Artikel, die Ihnen bei der Entwicklung einer webbasierten Chat-App helfen können.
Und vergessen Sie nicht: Wenn Sie Fragen, Ratschläge oder Ideen haben, die Sie mit der Community teilen möchten, dann können Sie sich gerne in unserem Slack-Arbeitsbereich der Gemeinschaft 👇
Share:
)
Freundlicher Tech-Pädagoge, Familienvater, Verfechter der Vielfalt, streitet wahrscheinlich ein bisschen zu viel. Ehemals Backend-Ingenieur. Sprich mit mir über JavaScript (Frontend oder Backend), das erstaunliche Vue.js, DevOps, DevSecOps, alles was mit JamStack zu tun hat. Autorin auf DEV.to