Mein Vater erinnert mich gerne daran, dass er als Computeringenieur in den 1970er Jahren " Programmierer war, bevor Programmieren in Mode war ". Er zeigte sogar ein paar Mal alte Fortran- und COBOL-Skripte. Nachdem ich diesen Code gelesen habe, kann ich mit Sicherheit sagen, dass das Programmieren heute definitiv cooler ist .
Ein Kennzeichen moderner Programmiersprachen und Entwicklungsumgebungen ist, wie viel weniger Code ein Entwickler schreiben muss. Durch die Verwendung von Hochsprachen zusammen mit den vielen verfügbaren APIs, Open Source-Paketen und kostenpflichtigen Diensten können Anwendungen - auch solche mit komplexen Anforderungen - relativ schnell erstellt werden.
Ein Vergleich, der die Entwicklung der Softwareentwicklung zeigt, ist die Konstruktion. Es war einmal, als der Bau eines Hauses mit dem Fällen von Bäumen auf Ihrem Gelände begann. Materialien, Werkzeuge und Methoden erschienen jedoch schnell, so dass der Bau schneller abgeschlossen wurde, Objekte stärker wurden und die Arbeiter von einigen elementaren Aufgaben befreit wurden.
Wie viele Wolkenkratzer würden gebaut, wenn die Bauherren ihren eigenen Stahl abbauen würden?
Softwareentwickler, die bis heute weiterarbeiten, fällen zu Beginn ihrer Karriere "ihre eigenen Bäume". Gleichzeitig haben beispiellose Innovationen des letzten Jahrzehnts dazu geführt, dass sich die Softwareindustrie ähnlich wie das Baugewerbe zu entwickeln begann.
Einfach ausgedrückt, moderne Entwickler verfügen jetzt über die Tools, Techniken und Best Practices, um Projekte schneller abzuschließen, stabile Anwendungen zu erhalten und Entwickler vor einfachen Aufgaben zu bewahren.
So erstellen Sie eine Chat-App
Lassen Sie uns schnell etwas erstellen, das früher Tage oder Wochen gedauert hat. Wir werden eine öffentliche Chatroom-Anwendung erstellen, die WebSockets für Echtzeitnachrichten verwendet.
WebSockets werden von allen modernen Browsern nativ unterstützt . Unser Ziel ist es jedoch herauszufinden, welche Tools wir bei der Arbeit verwenden können, und sie nicht neu zu erfinden . In diesem Sinne werden wir die folgenden Technologien verwenden:
Das Starterprojekt und die vollständige README-Datei finden Sie in diesem GitHub-Repository . Wenn Sie nur die fertige Anwendung sehen möchten, werfen Sie einen Blick auf den Zweig des öffentlichen Chatrooms.
Darüber hinaus erklärt das folgende Video (auf Englisch) jeden Schritt ausführlicher.
Lasst uns beginnen.
Sieben Schritte zum Erstellen einer Chat-Anwendung:
1. Projekteinrichtung
Klonen Sie das Starterprojekt und wechseln Sie in das Gruppenchat-Verzeichnis. Sie können selbst entscheiden, ob Sie Garn oder npm zum Installieren von Projektabhängigkeiten verwenden möchten. In jedem Fall benötigen wir alle in der Datei package.json angegebenen NPM-Pakete.
#
git clone https://github.com/8base/Chat-application-using-GraphQL-Subscriptions-and-Vue.git group-chat
#
cd group-chat
#
yarn
Um mit der GraphQL-API zu interagieren, müssen drei Umgebungsvariablen eingerichtet werden. Erstellen Sie mit dem folgenden Befehl eine .env.local-Datei im Stammverzeichnis, und die Vue-App legt automatisch die Umgebungsvariablen fest, die wir dieser Datei nach der Initialisierung hinzugefügt haben. Beide Werte und sollten nicht geändert werden. Sie müssen nur den Wert einstellen . Wenn Sie über einen 8base-Arbeitsbereich verfügen, mit dem Sie mithilfe unseres Lernprogramms eine Chat-Anwendung erstellen möchten, aktualisieren Sie die Datei .env.local mit Ihrer Arbeitsbereich-ID. Wenn nicht, rufen Sie die Arbeitsbereich-ID ab, indem Sie die Schritte 1 und 2 in 8base Quickstart ausführen .
echo 'VUE_APP_8BASE_WORKSPACE_ID=<YOUR_8BASE_WORKSPACE_ID>
VUE_APP_8BASE_API_ENDPOINT=https://api.8base.com
VUE_APP_8BASE_WS_ENDPOINT=wss://ws.8base.com' \
> .env.local
VUE_APP_8BASE_API_ENDPOINT
VUE_APP_8BASE_WS_ENDPOINT
VUE_APP_8BASE_WORKSPACE_ID
2. Schema importieren
Jetzt müssen wir die Serverseite vorbereiten. Im Stammverzeichnis dieses Repositorys sollten Sie die Datei finden
chat-schema.json
. Um es in den Arbeitsbereich zu importieren, müssen Sie nur die 8base-Befehlszeile installieren und sich anmelden und dann die Schemadatei importieren.
# 8base CLI
yarn global add 8base-cli
# CLI
8base login
#
8base import -f chat-schema.json -w <YOUR_8BASE_WORKSPACE_ID>
3. API-Zugriff
Die letzte Aufgabe für das Backend besteht darin, den öffentlichen Zugriff auf die GraphQL-API zu ermöglichen.
In der 8base Konsole gehen Sie zu
App Services > Roles > Guest
. Aktualisieren Sie die Berechtigungen, die sowohl für Beiträge als auch für Benutzer festgelegt wurden, um entweder überprüft oder als Alle Datensätze festgelegt zu werden (siehe Abbildung unten).
Die Rolle "Gast" bestimmt, was der Benutzer tun darf, der eine nicht authentifizierte API-Anforderung stellt.
Rolleneditor in der 8base-Konsole.
4. Schreiben von GraphQL-Abfragen
In diesem Schritt definieren und schreiben wir alle GraphQL-Abfragen, die wir für unsere Chat-Komponente benötigen. Dies hilft uns zu verstehen, welche Daten wir mithilfe der API lesen, erstellen und anhören (über WebSockets).
Der folgende Code sollte in eine Datei eingefügt werden
src / utils / graphql.js
. Lesen Sie die Kommentare über jeder exportierten Konstante, um zu verstehen, was jede Abfrage bewirkt.
/* gql graphQL */
import gql from "graphql-tag";
/* 1. - 10 */
export const InitialChatData = gql`
{
usersList {
items {
id
email
}
}
messagesList(last: 10) {
items {
content
createdAt
author {
id
email
}
}
}
}
`;
/* 2. */
export const CreateUser = gql`
mutation($email: String!) {
userCreate(data: { email: $email, roles: { connect: { name: "Guest" } } }) {
id
}
}
`;
/* 3. */
export const DeleteUser = gql`
mutation($id: ID!) {
userDelete(data: { id: $id, force: true }) {
success
}
}
`;
/* 4. */
export const UsersSubscription = gql`
subscription {
Users(filter: { mutation_in: [create, delete] }) {
mutation
node {
id
email
}
}
}
`;
/* 5. */
export const CreateMessage = gql`
mutation($id: ID!, $content: String!) {
messageCreate(
data: { content: $content, author: { connect: { id: $id } } }
) {
id
}
}
`;
/* 6. . */
export const MessagesSubscription = gql`
subscription {
Messages(filter: { mutation_in: create }) {
node {
content
createdAt
author {
id
email
}
}
}
}
`;
5. Konfigurieren des Apollo-Clients für Abonnements
Nachdem unsere GraphQL-Abfragen geschrieben wurden, ist es Zeit, unsere API-Module einzurichten.
Lassen Sie uns zunächst den API-Client
ApolloClient
mit den erforderlichen Standardeinstellungen behandeln. Für createHttpLink
uns stellen wir unseren vollständig geformten Arbeitsbereich-Endpunkt bereit. Dieser Code ist in src/utils/api.js
.
import { ApolloClient } from "apollo-boost";
import { createHttpLink } from "apollo-link-http";
import { InMemoryCache } from "apollo-cache-inmemory";
const { VUE_APP_8BASE_API_ENDPOINT, VUE_APP_8BASE_WORKSPACE_ID } = process.env;
export default new ApolloClient({
link: createHttpLink({
uri: `${VUE_APP_8BASE_API_ENDPOINT}/${VUE_APP_8BASE_WORKSPACE_ID}`,
}),
cache: new InMemoryCache(),
});
// Note: , // ApolloClient, .
Dann werden wir uns mit
subscriptions-transport-ws
und mit dem Abonnement-Client befassen isomorphic-ws
. Dieser Code ist etwas länger als der vorherige, daher lohnt es sich, sich die Zeit zu nehmen, um die Kommentare im Code zu lesen.
Wir initialisieren
SubscriptionClient
mit unserem WebSockets-Endpunkt und workspaceId
in Parametern connectionParams
. Wir verwenden dann diese eine subscriptionClient
von zwei Methoden, die im Standardexport definiert sind: subscribe()
und close()
.
subscribe
ermöglicht es uns, neue Abonnements mit Daten und Fehlerrückrufen zu erstellen. Mit der Schließmethode können wir die Verbindung schließen, wenn wir den Chat verlassen.
import WebSocket from "isomorphic-ws";
import { SubscriptionClient } from "subscriptions-transport-ws";
const { VUE_APP_8BASE_WS_ENDPOINT, VUE_APP_8BASE_WORKSPACE_ID } = process.env;
/**
* ,
* .
*/
const subscriptionClient = new SubscriptionClient(
VUE_APP_8BASE_WS_ENDPOINT,
{
reconnect: true,
connectionParams: {
/**
* Workspace ID ,
* Websocket
*
*/
workspaceId: VUE_APP_8BASE_WORKSPACE_ID,
},
},
/**
* WebSocket, W3C. * , *WebSocket (, NodeJS)
*/
WebSocket
);
export default {
/**
* , *'data’ 'error’
*/
subscribe: (query, options) => {
const { variables, data, error } = options;
/**
* .
*/
const result = subscriptionClient.request({
query,
variables,
});
/**
* * , ,
* subscriptionClient
*/
const { unsubscribe } = result.subscribe({
/**
*
* , .
*/
next(result) {
if (typeof data === "function") {
data(result);
}
},
/**
* , .
*/
error(e) {
if (typeof error === "function") {
error(e);
}
},
});
return unsubscribe;
},
/**
* subscriptionClient .
*/
close: () => {
subscriptionClient.close();
},
};
// . SubscriptionClient ,
// , .
6. Schreiben einer Vue-Komponente
Wir haben jetzt alles, was wir brauchen, um einen öffentlichen Chat zu erstellen. Es gibt nur noch eine Komponente zum Schreiben
GroupChat.vue
.
Laden Sie die Komponente mit Garnaufschlag und fahren Sie fort.
Ein wichtiger Hinweis: Jeder hat seine eigene Vorstellung von Schönheit, daher habe ich nur die minimalen Stile erstellt, die erforderlich sind, damit die Komponente funktionsfähig ist.
Komponentenskript
Zuerst müssen wir unsere Module, einfachen Stile und GraphQL-Abfragen importieren. Das alles ist in unserem
src / utils
.
Deklarieren Sie die folgenden Importe in
GroupChat.vue
.
/* API */
import Api from "./utils/api";
import Wss from "./utils/wss";
/* graphQL */
import {
InitialChatData,
CreateUser,
DeleteUser,
UsersSubscription,
CreateMessage,
MessagesSubscription,
} from "./utils/graphql";
/* */
import "../assets/styles.css";
Komponentendaten
Wir können definieren, welche Dateneigenschaften wir in der Datenfunktion unserer Komponente verwenden möchten. Wir benötigen lediglich eine Möglichkeit, Chat-Benutzer, Nachrichten, den Namen des "aktuellen" Benutzers und alle noch nicht gesendeten Nachrichten zu speichern. Diese Eigenschaften können wie folgt hinzugefügt werden:
/* imports ... */
export default {
name: "GroupChat",
data: () => ({
messages: [],
newMessage: "",
me: { email: "" },
users: [],
}),
};
Lebenszyklus-Haken
Unsere Lifecycle-Hooks laufen an verschiedenen Punkten im Leben einer Vue-Komponente. Zum Beispiel, wenn es gemountet oder aktualisiert wird. In diesem Fall interessieren wir uns nur für die Erstellung und
beforeDestroy
Komponente. In solchen Fällen möchten wir entweder die Chat-Abonnements öffnen oder schließen.
/* ... */
export default {
/* ... */
/**
* , .
*/
created() {
/**
* ,
*/
Wss.subscribe(UsersSubscription, {
data: this.handleUser,
});
/**
* ,
*/
Wss.subscribe(MessagesSubscription, {
data: this.addMessage,
});
/**
* ( 10 )
*/
Api.query({
query: InitialChatData,
}).then(({ data }) => {
this.users = data.usersList.items;
this.messages = data.messagesList.items;
});
/**
* ,
*/
window.onbeforeunload = this.closeChat;
},
/**
* , .
*/
beforeDestroy() {
this.closeChat();
},
};
Komponentenmethoden
Wir brauchen ein paar Methoden hinzufügen jeden Anruf / API - Antwort zu verarbeiten (
createMessage
, addMessage
, closeChat
, etc.). Alle von ihnen werden im Methodenobjekt unserer Komponente gespeichert.
Eines
ist zu
Dies liegt daran, dass wir Abonnements haben, die diese Mutationen verfolgen. Nach einem erfolgreichen Start werden Ereignisdaten vom Abonnement verarbeitet.
Die meisten
dieser Methoden sprechen für sich. Lesen Sie auf jeden Fall die Kommentare im folgenden Code.
/* ... */
export default {
/* ... */
methods: {
/**
* , .
*/
createUser() {
Api.mutate({
mutation: CreateUser,
variables: {
email: this.me.email,
},
});
},
/**
* ID.
*/
deleteUser() {
Api.mutate({
mutation: DeleteUser,
variables: { id: this.me.id },
});
},
/**
* ,
*
* .
*
* , ,
* , .
*/
handleUser({
data: {
Users: { mutation, node },
},
}) {
({
create: this.addUser,
delete: this.removeUser,
}[mutation](node));
},
/**
* users, , * .
*/
addUser(user) {
if (this.me.email === user.email) {
this.me = user;
}
this.users.push(user);
},
/**
* users ID.
*/
removeUser(user) {
this.users = this.users.filter(
(p) => p.id != user.id
);
},
/* */
createMessage() {
Api.mutate({
mutation: CreateMessage,
variables: {
id: this.me.id,
content: this.newMessage,
},
}).then(() => (this.newMessage = ""));
},
/**
* . * , , *.
*/
addMessage({
data: {
Messages: { node },
},
}) {
this.messages.push(node);
},
/**
* . beforeDestroy .
*/
closeChat () {
/* */
Wss.close()
/* */
this.deleteUser();
/* */
this.me = { me: { email: '' } }
}
},
/* ... */
}
Komponentenvorlage
Zu guter Letzt haben wir eine Komponente
GroupChat.vue
.
Es gibt
Tausende großartiger Tutorials zum Erstellen schöner Benutzeroberflächen. Dies ist keiner von ihnen.
Das folgende
Muster entspricht den Mindestanforderungen für die Chat-Anwendung. Es schön zu machen oder nicht, liegt bei Ihnen. Lassen Sie uns jedoch kurz auf das Schlüssel-Markup eingehen, das wir hier implementiert haben. Lesen Sie
wie
<template>
<div id="app">
<!--
, . ..
-->
<div v-if="me.id" class="chat">
<div class="header">
<!--
, , , , .
-->
{{ users.length }} Online Users
<!--
, closeChat..
-->
<button @click="closeChat">Leave Chat</button>
</div>
<!--
, , div. , , me.
-->
<div
:key="index"
v-for="(msg, index) in messages"
:class="['msg', { me: msg.participant.id === me.id }]"
>
<p>{{ msg.content }}</p>
<small
><strong>{{ msg.participant.email }}</strong> {{ msg.createdAt
}}</small
>
</div>
<!--
newMessage.
-->
<div class="input">
<input
type="text"
placeholder="Say something..."
v-model="newMessage"
/>
<!--
, createMessage.
-->
<button @click="createMessage">Send</button>
</div>
</div>
<!--
. , createUser.
-->
<div v-else class="signup">
<label for="email">Sign up to chat!</label>
<br />
<input
type="text"
v-model="me.email"
placeholder="What's your email?"
@blur="createUser"
required
/>
</div>
</div>
</template>
Und jetzt ist der öffentliche Chat aufgebaut. Wenn Sie es in Ihrem lokalen Netzwerk öffnen, können Sie Nachrichten senden und empfangen. Um jedoch zu beweisen, dass dies ein echter Gruppenchat ist, öffnen Sie einige Fenster und beobachten Sie den Fortschritt der Konversation.
7. Schlussfolgerung und Prüfung
In diesem Tutorial haben wir untersucht, wie wir mithilfe moderner Entwicklungstools in wenigen Minuten reale Anwendungen erstellen können.
Ich hoffe, Sie haben auch gelernt, wie Sie GraphQL-Abfragen, Mutationen und Abonnements effizient in einem 8base-Arbeitsbereich initialisieren
ApolloClient
und SubscriptionClient
ausführen können, sowie ein wenig über VueJS.
Unabhängig davon, ob Sie an einem Handyspiel, Messenger, Benachrichtigungs-Apps oder anderen Projekten arbeiten, für die Echtzeitdaten erforderlich sind, sind Abonnements ein hervorragendes Tool. Und jetzt haben wir gerade begonnen, sie zu betrachten.
Erstellen Sie eine Chat-App mit 8base
8base ist ein schlüsselfertiges serverloses Backend als Service, der von Entwicklern für Entwickler entwickelt wurde. Mit der 8base-Plattform können Entwickler mit JavaScript und GraphQL beeindruckende Cloud-Anwendungen erstellen. Erfahren Sie mehr über die 8base Plattform hier .