docs.waku.org/docs/clients/js-waku/build-chat-app.mdx

283 lines
6.9 KiB
Plaintext
Raw Normal View History

2023-03-26 22:39:24 +00:00
---
title: Build a Chat App
---
# Build a Chat App
In this guide, you will learn how to receive and send messages using Waku by building an app from scratch.
If you want to learn how to add Waku to an existing app, check the [Quick Start](./quick-start) guide.
## Pre-Requisites
### 1. Set up Project
Setup a new npm package:
```shell
mkdir waku-app
cd waku-app
npm init -y
```
### 2. Set up Web Server
Use the `serve` package as a web server
```shell
npm i -D serve
```
Add a `start` script to the `package.json` file:
```json
{
"scripts": {
"start": "serve ."
}
}
```
### 3. Create Files
Finally, create empty files for your project:
```shell
touch index.html index.js
```
## Write Your App
## 1. Add HTML Elements
In `index.html`, add a button, text box and `div` for messages to have a basic chat app.
Also, import the `index.js` file.
```html title=index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
<title>Waku Chat App</title>
</head>
<body>
<label for="textInput">Message text</label>
<input id="textInput" placeholder="Type your message here" type="text"/>
<button disabled id="send" type="button">
Send message using Light Push
</button>
<br/>
<div id="messages"></div>
<script src="./index.js" type="module"></script>
</body>
</html>
```
## 2. Access HTML Elements
::: note
From now on, all changes need to be done in the `index.js` file.
:::
Initialize variables to easily modify the HTML content:
```js
const sendButton = document.getElementById("send")
const messagesDiv = document.getElementById("messages")
const textInput = document.getElementById("textInput")
```
## 3. Start a Waku Node
Create and start a Waku Node:
```js
2023-04-17 06:57:20 +00:00
import {createLightNode} from "https://unpkg.com/@waku/create@0.0.12/bundle/index.js"
2023-03-26 22:39:24 +00:00
const wakuNode = await createLightNode({defaultBootstrap: true})
await wakuNode.start()
```
:::info
Setting the `defaultBootstrap` option to true allows your Waku node to connect to a set of pre-defined nodes.
:::
## 4. Wait for Connection to be Established
Your Waku node needs to connect to a remote node in order to access the network.
To wait for this, use the `waitForRemotePeer` function:
```js
2023-04-17 06:57:20 +00:00
import * as waku from "https://unpkg.com/@waku/core@0.0.16/bundle/index.js"
2023-03-26 22:39:24 +00:00
await waku.waitForRemotePeer(wakuNode)
```
## 5. Define a Content Topic
The `contentTopic` is a metadata `string` used for categorizing messages on the Waku network.
Depending on your use case, you can create one or more new `contentTopic`(s).
2023-05-27 06:45:58 +00:00
Refer to our [How to Choose a Content Topic](/) guide more details.
2023-03-26 22:39:24 +00:00
For this guide, we'll use `/chat-app-guide/1/message/utf8`.
Note that our payload will be encoded using `utf-8`.
We recommended using Protobuf for production purposes.
```js
const contentTopic = `/chat-app-guide/1/message/utf8`
```
## 6. Render Incoming Messages
Let's store incoming messages in an array and create a function to render them in the `messages` div:
```js
const updateMessages = (msgs, div) => {
div.innerHTML = "<ul>"
msgs.forEach((msg) => (div.innerHTML += `<li>${msg}</li>`))
div.innerHTML += "</ul>"
2023-04-17 06:57:20 +00:00
}
2023-03-26 22:39:24 +00:00
const messages = []
```
## 7. Create a Decoder
Waku supports various encryption protocols.
A decoder allows you to specify the content topic to use and how to decrypt messages.
For the chosen content topic, create a plain text decoder (without encryption):
```js
const decoder = waku.createDecoder(contentTopic)
```
## 8. Listen for Incoming Messages
Messages sent over the network are `Waku Message`s,
as defined in the [14/WAKU2-MESSAGE](https://rfc.vac.dev/spec/14/#wire-format) RFC.
Messages returned by the plain text decoder implement the [`DecodedMessage`](https://js.waku.org/classes/_waku_core.DecodedMessage.html) interface.
For now, we will just use the `payload` field.
It is a byte array field that can be used to encode any data.
We will store messages as a `utf-8` string.
Listen to messages using the decoder and add them to the `messages` div upon reception:
```ts
2023-04-17 06:57:20 +00:00
import * as utils from "https://unpkg.com/@waku/utils@0.0.4/bundle/bytes.js"
2023-03-26 22:39:24 +00:00
wakuNode.filter.subscribe([decoder], (message) => {
const str = utils.bytesToUtf8(message.payload)
messages.push(str)
updateMessages(messages, messagesDiv);
})
```
## 9. Send Messages
Finally, create a plain text encoder and set up the `send` button to send messages.
Users will be able to enter the message using the `textInput` div.
Once done, we can enable the `send` button.
```ts
2023-04-17 06:57:20 +00:00
const encoder = waku.createEncoder({contentTopic})
2023-03-26 22:39:24 +00:00
sendButton.onclick = async () => {
2023-04-17 06:57:20 +00:00
const text = textInput.value
2023-03-26 22:39:24 +00:00
2023-04-17 06:57:20 +00:00
await wakuNode.lightPush.send(encoder, {
2023-03-26 22:39:24 +00:00
payload: utils.utf8ToBytes(text),
});
2023-04-17 06:57:20 +00:00
textInput.value = null
2023-03-26 22:39:24 +00:00
};
sendButton.disabled = false
```
### 10. Run the App
You can now start a local web server to run the app:
```shell
npm start
```
Click on the link in the console (http://localhost:3000/) and send a message!
You can open your app in several tabs to see messages being sent around.
## Conclusion
Congratulations on building your first Waku chat app. You can find the complete files below:
```html title=index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
<title>JS-Waku Quick Start App</title>
</head>
<body>
<label for="textInput">Message text</label>
<input id="textInput" placeholder="Type your message here" type="text"/>
<button disabled id="send" type="button">
Send message using Light Push
</button>
<br/>
<div id="messages"></div>
<script src="./index.js" type="module"></script>
</body>
</html>
```
```js title=index.js
2023-04-17 06:57:20 +00:00
import {createLightNode} from "https://unpkg.com/@waku/create@0.0.12/bundle/index.js"
import * as waku from "https://unpkg.com/@waku/core@0.0.16/bundle/index.js"
import * as utils from "https://unpkg.com/@waku/utils@0.0.4/bundle/bytes.js"
2023-03-26 22:39:24 +00:00
const sendButton = document.getElementById("send")
const messagesDiv = document.getElementById("messages")
const textInput = document.getElementById("textInput")
const wakuNode = await createLightNode({defaultBootstrap: true})
await wakuNode.start()
await waku.waitForRemotePeer(wakuNode)
const contentTopic = `/chat-app-guide/1/message/utf8`
const updateMessages = (msgs, div) => {
div.innerHTML = "<ul>"
2023-04-17 06:57:20 +00:00
msgs.forEach((msg) => (div.innerHTML += `<li>${msg}</li>`))
2023-03-26 22:39:24 +00:00
div.innerHTML += "</ul>"
2023-04-17 06:57:20 +00:00
}
2023-03-26 22:39:24 +00:00
const messages = []
2023-04-17 06:57:20 +00:00
const decoder = waku.createDecoder(contentTopic)
2023-03-26 22:39:24 +00:00
wakuNode.filter.subscribe([decoder], (message) => {
2023-04-17 06:57:20 +00:00
console.log("message received", message)
2023-03-26 22:39:24 +00:00
const str = utils.bytesToUtf8(message.payload)
messages.push(str)
updateMessages(messages, messagesDiv);
})
2023-04-17 06:57:20 +00:00
const encoder = waku.createEncoder({contentTopic})
2023-03-26 22:39:24 +00:00
sendButton.onclick = async () => {
2023-04-17 06:57:20 +00:00
const text = textInput.value
2023-03-26 22:39:24 +00:00
2023-04-17 06:57:20 +00:00
await wakuNode.lightPush.send(encoder, {
2023-03-26 22:39:24 +00:00
payload: utils.utf8ToBytes(text),
2023-04-17 06:57:20 +00:00
})
textInput.value = null
}
2023-03-26 22:39:24 +00:00
sendButton.disabled = false
```