
Partager:
Éducateur technique sympathique, père de famille, défenseur de la diversité, il discute probablement un peu trop. Anciennement ingénieur backend. Parlez-moi de JavaScript (frontend ou backend), de l'incroyable Vue.js, de DevOps, de DevSecOps, de tout ce qui concerne JamStack. Rédacteur sur DEV.to
Construire un clone de Slack en utilisant Vue Partie 1
Temps de lecture : 70 minutes
Construire une application de chat Vue.js semblable à Slack
Avez-vous déjà voulu créer une application de chat, mais vous êtes bloqué sur les fonctionnalités à ajouter, ou juste comment le rendre généralement ? Dans cet article, vous allez construire un clone du logiciel de chat préféré de tous, Slack. En utilisant Vue.js, le framework préféré de tous. Et Vonage Conversation API, le service de conversation préféré de tous.
Ce billet est la première partie d'une série de tutoriels en plusieurs parties qui va nous permettre de passer d'un répertoire vide à une application réelle présentant plusieurs des fonctionnalités de Slacks qui définissent le genre.
Voici quelques-unes des choses que vous apprendrez dans ce billet :
Si vous êtes intéressé par l'application de démonstration complète, sans passer par le guide, veuillez consulter le repo GitHub de mon clone Vue js Slack. GitHub pour mon clone Vue.js Slack jusqu'à présent.
Conditions préalables
Vonage API Account
To complete this tutorial, you will need a Vonage API account. If you don’t have one already, you can sign up today and start building with free credit. Once you have an account, you can find your API Key and API Secret at the top of the Vonage API Dashboard.
Node et NPM
Pour commencer, vous aurez besoin d'installer Node et NPM. Ce guide utilise Node 8 et NPM 6. Vérifiez qu'ils sont installés et à jour.
Node et NPM doivent être installés et à la bonne version. Allez sur nodejs.orgtéléchargez et installez la bonne version si vous ne l'avez pas.
Notre CLI
Pour mettre en place votre application, vous devez installer notre CLI. Installez-le en utilisant NPM dans le terminal.
Vous pouvez vérifier que vous avez la bonne version avec cette commande. Au moment où j'écris ces lignes, j'utilise la version 0.4.9-beta-3.
Pour suivre les étapes de cet article, n'oubliez pas de de vous inscrire à un compte Vonage gratuit et de configurer le CLI avec la clé API et le secret qui se trouvent sur votre tableau de bord.
CLI Express.js
Installer Générateur Express. Vous utiliserez cette bibliothèque pour générer un serveur Express.js de base.
Vous pouvez vérifier que vous avez la bonne version avec cette commande. Au moment où j'écris ces lignes, j'utilise la version 4.16.1.
CLI Vue.js
Installer le CLI de Vue. Vous utiliserez cette bibliothèque pour générer une application client Vue.js de base.
Vous pouvez vérifier que vous avez la bonne version avec cette commande. Au moment de la rédaction de ce document, j'utilisais la version 4.1.2 de @vue/cli.
Partir de zéro
Cette série va vous emmener d'un répertoire vierge jusqu'à une application de chat du monde réel en utilisant Express.js comme serveur.
Créer un dossier de projet
Tout d'abord, créez un répertoire pour votre travail.
Ensuite, il faut changer de répertoire.
Générer un serveur Express.js
Ensuite, créez un serveur de base en utilisant le générateur Express.js. Ce que j'aime dans cette CLI, c'est qu'elle configure l'exécutable du serveur et l'application indépendamment l'un de l'autre. En d'autres termes, il reprend la philosophie de l'application extrêmement légère et cool Express Hello World. Il le divise en un fichier exécutable tout aussi cool pour configurer le serveur et l'environnement bin/wwwet l'application elle-même app.js.
L'application étant principalement une API, il est préférable de ne pas installer ce qui sert à gérer les fichiers de modèles. Pour cela, utilisez l'option --no-view option.
Si vous envisagez d'utiliser git comme système de contrôle de version, vous devriez envisager d'utiliser --git pour générer le fichier .gitignore correct.
Comme vous êtes déjà dans le répertoire du projet, spécifiez l'option --force et utilisez . comme répertoire. L'outil générera alors l'application dans le répertoire actuel sans problème.
Ensuite, installez les dépendances.
Exécuter le serveur Express.js localement
Une fois que le serveur a été créé et que les dépendances ont été installées, vous pouvez le démarrer pour vous assurer que tout fonctionne comme prévu.
Vous pouvez vérifier qu'il fonctionne à l'URL par défaut, localhost:3000.

Routes et contrôleurs
L'application générée comprend le routage nécessaire. Le routage consiste à déterminer comment une application traite une demande adressée à une URL et à une méthode particulières (GET, POST, etc.). Les contrôleurs, quant à eux, sont responsables du flux d'exécution de l'application. L'application générée ne crée pas de contrôleurs et utilise les routeurs pour renvoyer une réponse.
Créez un nouveau répertoire de contrôleur.
Créer un nouveau contrôleur dans ce répertoire nommé server.js.
Ouvrir controllers/server.js et créez la première méthode pour le serveur.
// controllers/server.js
exports.status = function(req, res, next) {
res.json({
status: 'ok'
});
};Ce contrôleur pourrait ensuite être chargé de fournir au client une condition, en fonction de diverses vérifications, par exemple si le service de chat est opérationnel ou s'il peut se connecter aux données. L'idée est que si un problème survient sur le serveur, le client recevra l'erreur, la traitera avec élégance et informera l'utilisateur de ce qui s'est passé.
Pour demander cette méthode du contrôleur, créez une nouvelle route dans le répertoire routes existant, nommée server.js.
Ouvrez routes/server.js et ajoutez le code ci-dessous.
// routes/server.js
var express = require('express');
var router = express.Router();
var serverController = require('../controllers/server');
router.get('/status', serverController.status);
module.exports = router;Cela permet d'acheminer un chemin (/status) vers une méthode du contrôleur (serverController.status). La route fournit le résultat de la méthode du contrôleur au client en tant que réponse.
Pour ajouter cet itinéraire à l'application, vous devez éditer app.js et effectuer ces changements.
// 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'));Vous pouvez ensuite supprimer les éléments routes/index.js et routes/users.js et
Relancez l'application avec npm start; vous pouvez alors accéder à la nouvelle route à l'adresse suivante localhost:3000/api/server/status.

Création d'un client
Utilisez l'interface de programmation Vue pour créer une nouvelle application client.
Générer un client Vue.js
Exécutez la commande create avec l'interface de commande Vue. Cet outil génère une application Vue simple sur laquelle nous baserons notre client de chat. Il propose quelques options et vous pouvez sélectionner les valeurs par défaut.
Le client est généré dans le répertoire client comme spécifié dans la commande. Il s'exécute également npm install automatiquement.
Maintenant, allez dans le répertoire client répertoire.
Pour exécuter le client, utilisez cette commande. Notez qu'elle est différente de celle utilisée pour lancer le serveur.
Vous pouvez ensuite accéder à votre client à l'adresse suivante localhost:8080. Vous remarquerez qu'il a un port différent par défaut et dans l'environnement de développement, cela nous aide, comme vous le découvrirez plus loin, à faire fonctionner le serveur et le client simultanément.

Rechargement à chaud des fichiers du serveur Express.js
En général, au cours du processus de développement, la plupart des gens souhaitent que l'application recharge automatiquement les fichiers au fur et à mesure qu'ils les modifient. Pour ce faire, nous allons configurer le serveur pour qu'il utilise nodemon pour servir les fichiers.
Installer Nodemon
Si vous êtes toujours dans le répertoire client de tout à l'heure, vous pouvez revenir au répertoire principal du projet en remontant d'un niveau avec cette commande, .. qui indique un répertoire parent.
Maintenant, installez Nodemon en tant que dépendance de développement. Installez une dépendance de développement en ajoutant --save-dev comme option de la commande.
Une fois installé, vous pouvez éditer le fichier package.json et modifier le script start comme indiqué ici.
+ "dev:server": "nodemon ./bin/www",
"start": "node ./bin/www"Lorsque vous exécutez l'application avec npm run dev:serverelle utilisera Nodemon. Nodemon surveille les fichiers de l'application et redémarre automatiquement le service lorsque des fichiers sont modifiés.
Remarque : Les métadonnées des fichiers, telles que les autorisations et la date de modification, sont également prises en compte.
Exécution simultanée du serveur et du client
Au fur et à mesure que nous avançons dans ce guide, vous aurez besoin d'exécuter le client et Express.js simultanément. Il existe une option Concurrently pour cela, qui rend très facile l'apprentissage d'applications séparées l'une sur l'autre.
Installation simultanée
Installation simultanée, également en tant que dépendance de développement.
Démarrer les deux environnements de développement
Modifiez le fichier package.json pour le serveur, comme indiqué ici. Dans la dernière section, nous avons ajouté un script dev:server qui exécutait le serveur à l'aide de Nodemon. Maintenant, nous ajoutons un script dev:client au niveau racine du projet pour exécuter le client à partir d'ici également.
"dev:server": "nodemon ./bin/www",
+ "dev:client": "cd client && npm run serve",
"start": "node ./bin/www"
Maintenant, ajoutez cette ligne pour combiner les deux en utilisant Concurrently. Vous remarquerez l'option --kill-others-on-fail qui signifie que Concurrently arrêtera tous les services si une erreur est détectée. Sans cela, si Node ou Webpack (qui sert le client) rencontrait une erreur, vous devriez redémarrer Concurrently pour que le client et le serveur fonctionnent à nouveau.
"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"
Lorsque vous exécutez l'application avec npm run develle démarrera le serveur et le client ensemble à l'adresse suivante localhost:3000 et localhost:8080 respectueusement.

Proxy des requêtes API vers le serveur Express.js
Pour effectuer des requêtes dans l'environnement de développement vers le serveur à partir du client, vous devez mettre en place un proxy. Vous pouvez configurer Vue.js de manière à ce que toutes les requêtes commençant par une route particulière soient envoyées par proxy.
Configurer le Proxy
Pour ce faire, créez un nouveau fichier dans le répertoire client nommé vue.config.js. Allez ensuite dans le répertoire du client.
Créer un fichier de configuration vide.
Collez le code suivant.
// vue.config.js
module.exports = {
devServer: {
proxy: {
"/api": {
target: "http://localhost:3000",
secure: false
}
}
}
};Ce code indique à Vue.js que lors de l'exécution de devServer que toutes les routes correspondant à /api doivent être redirigées vers http://localhost:3000. Il s'agit de l'URL du serveur lorsque vous exécutez le script dev ou le script dev:server directement.
Créer un service consommateur d'API
Pour effectuer des requêtes de Vue.js vers notre serveur à partir du client, installez Axiosqui est une Promise à utiliser dans le code côté navigateur.
Maintenant qu'Axios est installé et que vous pouvez transmettre des requêtes par proxy entre le serveur et le client, il est temps de faire ces requêtes. Dans le répertoire src/ du client, créez un nouveau répertoire nommé services pour contenir tous les fichiers du service API.
Créez un service API abstrait, qui définira le chemin pour les services API suivants. N'oubliez pas que dans l'environnement de développement, /api va servir de proxy vers le serveur.
Utilisez le code suivant pour créer un service API abstrait qui renvoie une instance d'Axios.
// src/services/Api.js
import axios from 'axios'
export default() => {
return axios.create({
baseURL: `/api`,
headers: {'Cache-Control': 'no-cache, no-store, no-transform'}
})
}
Vous avez déjà créé un server/status dans le serveur, auquel vous pouvez accéder lorsque le serveur est en cours d'exécution à partir de localhost:3000/api/server/status.
Pour consommer ce point d'accès à partir de l'application cliente, créez un fichier pour le service.
Et ajoutez ce code pour créer une méthode fetchStatus sur le nouveau Server service.
// src/services/Server.js
import Api from '@/services/Api'
export default {
fetchStatus () {
return Api().get('server/status')
}
} Demander l'état du serveur au client
Maintenant que vous avez créé un service pour effectuer des requêtes au serveur, importez le service dans votre composant App.vue composant.
Ouvrez App.vue et ajoutez les lignes comme indiqué ici.
<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>
# ...
Ici, il réutilise le fichier HelloWorld pour afficher l'état de la demande à l'utilisateur.
Remarque : N'oubliez pas que vous êtes probablement encore dans le répertoire client à ce stade. Si vous démarrez (ou redémarrez) à nouveau l'environnement de développement en utilisant
npm run devdoit être exécuté dans le répertoire du serveur (cd ..pour passer du client au serveur).
Une fois qu'il est lancé, vous pouvez accéder au client à l'adresse suivante localhost:8080. Si vous êtes assez rapide, vous pouvez voir le message "Connecting...".

Chargement des écrans avec Tailwind et FontAwesome
Lors de la connexion au serveur dans la dernière section, vous aurez réutilisé le fichier HelloWorld . Maintenant, en utilisant le composant Tailwind CSS et FontAwesome, créez un écran de chargement pour le client.
Si vous souhaitez pratiquer cette méthode en dehors de cette application, j'ai écrit sur le sujet suivant Utiliser Tailwind CSS avec Vue.js dans un guide séparé juste pour vous.
Installer Tailwind CSS
Pour utiliser Tailwind CSS dans le client, nous devons l'installer en tant que dépendance et configurer le client pour qu'il l'utilise.
Note : Cette installation est pour le client et non pour le serveur : Cette installation est pour le client, pas pour le serveur. Assurez-vous donc d'être dans le répertoire
clientdans le répertoire
Configurer le client Vue.js pour Tailwind CSS
Lorsque l'application cliente se construit, elle recherche un fichier postcss.config.js qui est un fichier de configuration que Vue.js utilise pour savoir comment traiter le CSS. L'installation de Tailwind CSS indique que vous devez l'ajouter en tant que plugin dans votre chaîne de construction.
L'application de démonstration générée par Vue ne crée pas de fichier postcss.config.js fichier. Faites-le maintenant.
Et configurez-le à l'aide de ce code.
// postcss.config.js
const autoprefixer = require('autoprefixer');
const tailwindcss = require('tailwindcss');
module.exports = {
plugins: [
tailwindcss,
autoprefixer,
],
}; Ajouter Tailwind en tant que ressource CSS
L'application de démonstration ne crée pas non plus d'actifs CSS. Au lieu de cela, elle utilise le CSS à l'intérieur des composants Vue.js, comme le montrent de nombreux guides. Ainsi, pour inclure tailwind, créez un fichier CSS de base dans le répertoire assets à l'aide de ces commandes ou de votre éditeur.
Utilisez ce code pour inclure la base CSS Tailwind, les composants et les utilitaires dans votre construction CSS. Copiez-le et collez-le dans votre nouveau fichier index.css dans votre nouveau fichier
/* src/assets/styles/index.css */
@tailwind base;
@tailwind components;
@tailwind utilities; Inclure le CSS Tailwind
Modifiez maintenant votre fichier main.js pour importer index.css vers le 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`);

Remarque : Tailwind CSS utilise preflight (construit au-dessus de normalize.css) pour réinitialiser tous les styles des différents navigateurs au même endroit. Vous remarquerez que certains styles par défaut ont été supprimés. Ne vous inquiétez pas, vous remplacerez cela bientôt.
Installer FontAwesome
La création d'un spinner de chargement se fera avec une font awesome notched circle. Installez-le sur le client avec cette commande.
Inclure FontAwesome
Modifier main.js et ajoutez ce code.
// 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`);
Créer l'écran de chargement
Pour créer un nouveau composant Vue.js à utiliser comme écran de chargement, ajoutez un nouveau fichier de composant à l'aide de cette commande ou de votre éditeur.
Maintenant, à l'aide de ce code, ajoutez le spinner à une superposition translucide en plein écran.
<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>
Et, ajoutez l'écran de chargement en éditant App.vue et en remplaçant la réutilisation de HelloWorld.vue par le nouveau composant.
<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>
...

Remarque : Pour tester ceci, vous pouvez modifier la réponse
statusdans le répertoirecontrollers/server.jspour qu'elle renvoie autre chose queok.
Gérer les erreurs du serveur dans le client
Il est temps d'ajouter la gestion des erreurs au client.
Attraper les erreurs de requête
Modifier App.vue et ajoutez le code suivant.
...
<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>
...Désormais, si une erreur est renvoyée par le serveur, elle sera détectée par le client et ajoutée aux données du composant.
Créer un composant d'erreur
Pour afficher une erreur, créez un composant Error.vue à l'aide de cette commande ou de votre éditeur.
Ajoutez ce code, qui utilise également les icônes FontAwesome (et les calques) pour produire un graphique approprié.
<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>
Afficher une erreur du serveur dans le client
Une fois de plus, l'édition App.vueajoutez le code comme indiqué ici. Supprimez l'image en même temps.
<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>
...
Maintenant, le client affiche les erreurs envoyées par le serveur.

Note : Pour voir si cela fonctionne, vous pouvez modifier l'application de votre serveur : Pour que cela fonctionne, vous pouvez modifier l'application de votre serveur
controllers/server.jsen remplaçantres.jsonparres.sendStatus(500)pour fournir au client un code d'erreur 500.
Utiliser les fichiers d'environnement Dotenv
Il n'est pas souhaitable de coder en dur les clés et les informations d'identification dans votre serveur, et encore moins dans votre client.
Installer Dotenv
Installer dotenv afin que vous puissiez définir des variables d'environnement et les lire dans votre application.
Remarque : Il se peut que vous vous trouviez dans le répertoire du client à ce stade. Utilisez
cd ..pour passer du client au serveur.
Créer un fichier d'environnement
Créez un fichier d'environnement vide pour le serveur à l'aide de cette commande ou de votre éditeur.
Configurer l'environnement
Maintenant, éditez .env et ajoutez cet exemple de configuration au fichier. Le jeton et l'identifiant ne sont pas réels.
Note : Les fichiers sont ignorés par git en raison des fichiers générés :
.envLes fichiers de la catégorie " Autres " sont ignorés par git en raison du fait que le fichier de la catégorie " Autres " généré.gitignoregénéré ajoute.envpar défaut. Transmettre votre fichier.envest à peu près aussi sûr que de coder en dur vos informations d'identification. Cela souligne également que ces informations d'identification sont pour cet environnement, l'exécutant localement. Si vous deviez déployer ceci, attendez-vous à gérer l'environnement sur le serveur d'une manière différente. Heroku, par exemple, vous fournit un panneau de contrôle pour configurer l'environnement.
Charger l'environnement
Modifiez maintenant le fichier top du serveur pour inclure l'environnement au démarrage de l'application. Modifiez bin/www (il n'y a pas d'extension de fichier) comme indiqué ici.
#!/usr/bin/env node
+ require('dotenv').config();
/**
* Module dependencies.
*/
... Transmettre les valeurs de l'environnement du serveur au client
La première variable d'environnement à partager avec le client est VONAGE_DEFAULT_CONVERSATION_IDqui est l'identifiant par défaut de la "salle" pour le chat ! Vous reviendrez plus tard pour modifier la valeur de cette variable d'environnement.
Modifier controllers/server.js et ajoutez le code indiqué ici.
// controllers/server.js
exports.status = function(req, res, next) {
res.json({
+ defaultConversationId: process.env.VONAGE_DEFAULT_CONVERSATION_ID,
status: 'ok'
});
}; Points d'accès utilisateur pour l'authentification du client
Dans les parties suivantes de cette série, un fournisseur d'identité gérera les données de l'utilisateur envoyées par le serveur. En attendant, simulez également ces informations et revenez les modifier lorsque vous les aurez.
Créer un point de terminaison utilisateur
Créez un point de terminaison utilisateur en créant d'abord un user.js à l'aide de votre éditeur ou de cette commande.
En lui donnant ce code.
// controllers/user.js
exports.session = function(req, res, next) {
res.json({
user: process.env.VONAGE_USER,
token: process.env.VONAGE_USER_TOKEN
});
};Maintenant, créez une route pour accéder aux points d'extrémité du contrôleur d'utilisateur à l'aide de votre éditeur ou de cette commande.
Et donnez-lui ce 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;Enfin, modifiez votre fichier app.js et ajoutez la nouvelle route comme indiqué ici.
// 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;Relancez l'application avec npm start; vous pouvez alors accéder à la nouvelle route à l'adresse localhost:3000/api/user/session.

Se connecter à la Conversation API de Vonage
Dans cette section, les étapes suivantes sont les étapes habituelles si vous avez déjà lu l'un de mes tutoriels côté client. Si ce n'est pas le cas, il s'agit de commandes simples pour créer une conversation Vonage à laquelle les utilisateurs peuvent se joindre.
S'installer avec notre CLI
Pour vous connecter à l'API des conversations en tant qu'utilisateur, vous devez d'abord créer une application, une conversation et un utilisateur.
Créer une application
Créez une application dotée de capacités de communication en temps réel (RTC). L'URL d'événement reçoit un journal en direct des événements qui se produisent sur le service, comme les utilisateurs qui rejoignent ou quittent le service, ou qui envoient des messages. Il s'agit d'un exemple d'URL pour le moment, mais vous serez en mesure de capturer et de réagir aux événements dans les parties suivantes de notre série.
Créer une conversation
Deuxièmement, créez une conversation, qui agit comme un salon de discussion. Ou un conteneur pour les messages et les événements.
Créez votre utilisateur
Créez maintenant un utilisateur pour vous-même.
Remarque : Dans cette démonstration, vous ne discuterez pas entre deux utilisateurs. D'autres guides vous montrent comment créer des conversations entre plusieurs utilisateurs. Ce guide se concentre sur la mise en forme de l'interface utilisateur de votre message d'une manière simple mais attrayante.
Ajouter l'utilisateur à une conversation
Ensuite, ajoutez votre nouvel utilisateur à la conversation. Un utilisateur peut être membre d'une application, mais il doit tout de même rejoindre la conversation.
Générer un jeton d'utilisateur
Enfin, générez un jeton pour votre nouvel utilisateur. Ce jeton représente l'utilisateur lorsqu'il accède à l'application. Ce jeton d'accès l'identifie, de sorte que toute personne l'utilisant sera supposée être le bon utilisateur.
En pratique, vous configurerez l'application avec ce jeton. En production, ces jetons doivent être gardés secrets et exposés avec précaution à l'application cliente, si tant est qu'ils le soient.
Le jeton n'est utilisable que pendant 24 heures. Après cette période, vous devrez réexécuter cette commande nexmo jwt:generate pour accorder à nouveau l'accès à votre utilisateur client.
Stocker les informations d'identification dans l'environnement
Maintenant, modifiez .env et ajoutez les informations d'identification que vous avez générées.
Créer un service pour la session utilisateur
Créer un service User.js pour consommer le point de terminaison de la session utilisateur à partir de l'application cliente.
Créez le fichier à l'aide de cette commande ou de votre éditeur.
Et ajoutez ce code pour créer une méthode fetchSession sur le nouveau User service.
// src/services/User.js
import Api from '@/services/Api'
export default {
fetchSession () {
return Api().get('user/session')
}
} Connecter le client à la Conversion API
Pour connecter le client à l'API Conversation, vous devez installer la dernière version du fichier nexmo-client.
Créez un nouveau composant Vonage.vue à l'aide de votre éditeur ou de la commande ci-dessous, qui sera chargé de se connecter à l'API de Conversation à l'aide de la bibliothèque nexmo-client bibliothèque.
Comme pour le composant App.vue le composant Vonage.vue demande au serveur des informations sur la session de l'utilisateur, à l'aide des boutons Loading.vue et Error.vue de la même manière.
<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>
Remplacez maintenant l'utilisation du HelloWorld.vue par le nouveau composant Vonage.vue à l'intérieur de App.vue en effectuant ces changements.
<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>
Après l'écran de chargement "Connecting...", vous verrez un écran de chargement "Logging you in..." avant de charger le composant HelloWorld.vue composant.

Note : Vous n'atteindrez Hello World que si votre application s'est connectée avec succès au serveur : Vous n'atteindrez le Hello World que si votre application s'est connectée avec succès au serveur, a obtenu un statut "OK", a demandé la session de l'utilisateur et a ensuite utilisé le jeton de l'utilisateur pour se connecter à l'API Conversation à l'aide de la bibliothèque
nexmo-clientbibliothèque.
Créer les composants du chat
Maintenant que vous êtes connecté à la Conversation API, vous pouvez commencer à créer votre interface utilisateur de messagerie. Commencez par la structure de base de votre application, la fenêtre de conversation.
Fenêtre de chat
Pour ce faire, créez les composants ChatWindow.vue, ChatWindowHeader.vue, ChatWindowEvents.vue, et ChatWindowFooter.vue à l'aide de la commande ou de votre éditeur.
L'édition ChatWindow.vue, donnez-lui le code suivant.
<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>
Le composant ChatWindow.vue est responsable de la structuration de la présentation du chat. L'en-tête se trouve en haut, les messages au milieu et le pied de page en bas. Il transmet le nom du canal, préfixé par un hash, en tant que prop channelName à l'en-tête. Il transmet également la conversation, l'utilisateur et les membres au composant d'événements. Enfin, il transmet la conversation au pied de page.
Ensuite, éditez ChatWindowHeader.vue et lui donner ce code.
<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>Le composant ChatWindowHeader.vue se contente pour l'instant d'afficher le nom du canal.
Maintenant, éditez ChatWindowEvents.vue et donnez-lui ce 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>
Le composant ChatWindowEvents.vue est chargé de dresser la liste de tous les événements de la conversation. Il le fait de haut en bas, les événements les plus anciens se trouvant en haut de la fenêtre. Faites défiler la fenêtre vers le bas pour voir les messages les plus récents. Il charge un total de 40 messages. Plus loin dans cette série, vous verrez comment charger des messages plus anciens.
Enfin, éditez ChatWindowFooter.vue et lui donner ce 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>
Une fois vos composants créés, modifiez Vonage.vue et remplacez HelloWorld.vue par votre nouveau ChatWindow.vue composant.
<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>
Il y a beaucoup de choses à copier et à coller ici. Une fois en marche, voyez à quoi cela ressemble.

Remarquez la marge, laissée par l'application de démonstration ! Enfin, supprimez ce style en éditant src/App.vue comme suit.
<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>
Pendant que vous y êtes, supprimez HelloWorld.vue. Enfin.

Chat de travail atteint !
Partie 1, terminée ! Vous avez construit un client de chat qui commence à ressembler à Slack. Voici une liste de ce que vous avez fait jusqu'à présent :
Création d'une application Express.js à utiliser comme API
Création d'une application Vue.js à utiliser comme client
Création de points d'extrémité d'API dans Express.js
Points d'extrémité d'API consommés dans Vue.js
Ajout du rechargement à chaud des fichiers Express.js
Ajout simultané à Express.js et Vue.js avec une seule commande
Requêtes API proxy de Vue.js vers Express.js
Styliser Vue.js avec Tailwind CSS
Icônes animées avec FontAwesome
Création d'un composant de chargement plein écran
Connecté à l'API Conversation de Vonage
Création d'une interface utilisateur de messagerie
Si vous êtes intéressé par l'application de démonstration complète, veuillez consulter le repo GitHub pour mon clone Vue js Slack. GitHub pour mon clone Vue.js Slack jusqu'à présent.
Restez à l'écoute pour la deuxième partie, dans laquelle nous aborderons les incontournables de l'expérience utilisateur.
Historique à défilement infini
Positions de défilement collantes lors du défilement de l'historique
Ping à la fin de l'envoi des messages
Notifications de messages non lus
Bouton "marquer comme lu
Nombre de membres du canal
Suppression des messages
Notification des événements de frappe de l'utilisateur (plusieurs personnes sont en train de taper)
Messages multilignes
Style Slack Markdown
À la fin de la deuxième partie, vous aurez obtenu quelque chose qui ressemble à ceci !

Pour en savoir plus
Voici d'autres articles qui pourraient vous être utiles dans votre démarche de création d'une application de chat en ligne.
Et n'oubliez pas, si vous avez des questions, des conseils ou des idées que vous souhaitez partager avec la communauté, n'hésitez pas à vous rendre sur notre espace de travail Slack de la communauté 👇
Partager:
Éducateur technique sympathique, père de famille, défenseur de la diversité, il discute probablement un peu trop. Anciennement ingénieur backend. Parlez-moi de JavaScript (frontend ou backend), de l'incroyable Vue.js, de DevOps, de DevSecOps, de tout ce qui concerne JamStack. Rédacteur sur DEV.to
