Hi! π
Today we're taking a look at Socket.IO and how we can integrate it into our SvelteKit project. As an example, we'll be building a realtime chat app in this demo.
Setup the project
First, we need a SvelteKit project. If you already have a project, you can skip this step. If not, you can simply create one with the following commands:
npm init svelte@next live-chat-app
cd live-chat-app
npm install
npm run dev -- --open
I'm using Tailwind CSS in this demo. I've already written an article on how to add Tailwind CSS to SvelteKit.
Install the dependencies
All we need is Socket.IO for the server-side part (handling the incoming requests and connections) and the Socket.IO-Client for the client-side part (sending and receiving messages).
npm i socket.io socket.io-client
Inject the Socket.IO server
We can inject the Socket.IO server directly in the SvelteKit config:
// ... (other imports here)
import { Server } from 'socket.io'; // <-- Import the Socket.IO server
const config = {
// ...
kit: {
adapter: adapter(),
vite: {
plugins: [
{
name: 'sveltekit-socket-io',
configureServer(server) {
const io = new Server(server.httpServer);
// Socket.IO stuff goes here
console.log('SocketIO injected');
}
}
]
}
},
// ...
};
export default config;
Server-side part
For this demo, I'll keep things simple and generate a random username for each client and just broadcast incoming messages along with the username and time.
// This is located in the svelte config (see above "Socket.IO stuff goes here")
io.on('connection', (socket) => {
// Generate a random username and send it to the client to display it
let username = `User ${Math.round(Math.random() * 999999)}`;
socket.emit('name', username);
// Receive incoming messages and broadcast them
socket.on('message', (message) => {
io.emit('message', {
from: username,
message: message,
time: new Date().toLocaleString()
});
});
});
Please note: This guide is not a full Socket.IO guide. The example is pretty simple and only to show you how to use Socket.IO with SvelteKit.
Client-Side part
Connect to Socket.IO
Because you may want to use the Socket.IO connection in multiple components or pages, I recommend to separate the connection stuff:
// src/lib/realtime.js
import ioClient from "socket.io-client";
const ENDPOINT = "http://localhost:3000";
const socket = ioClient(ENDPOINT)
export const io = socket
Now we can import and use io
everywhere in our project.
Layout
Before we add Socket.IO to the client-side, I'll create a simple UI for our demo. Because this is only the chat, I'll do this directly in the src/routes/index.svelte
:
<script>
import { onMount } from "svelte";
let textfield = ""
let username = ""
let messages = []
function sendMessage() {
}
</script>
<div class="h-screen w-screen bg-zinc-800">
<div class="h-full w-full max-w-md mx-auto bg-zinc-500 flex flex-col">
<header class="px-6 py-4 border-b border-zinc-800 bg-zinc-700 text-white shrink-0 flex items-center justify-between">
<span class="font-bold text-xl">My Chat app</span>
<span>{username}</span>
</header>
<div class="h-full w-full p-4">
{#each messages as message}
<div class="bg-zinc-300 rounded-xl rounded-tl-none px-4 py-3 my-4 w-fit">
<span class="flex items-center space-between gap-4">
<b>{message.from}</b>
<i>{message.time}</i>
</span>
{message.message}
</div>
{/each}
</div>
<form action="#" on:submit|preventDefault={sendMessage}
class="px-6 py-4 border-t border-zinc-800 bg-zinc-700 text-white shrink-0 flex items-center"
>
<input type="text" bind:value={textfield} placeholder="Type something..." class="bg-transparent border-none px-4 py-3 w-full" />
<button type="submit" class="shrink-0 border border-white rounded-lg px-4 py-3">Send</button>
</form>
</div>
</div>
As you can see, I'm storing all messages inside the messages
array and output them inside the each
loop.
To send messages, I've attached a listener to the form sendMessage
.
Send messages
First, we need to import io
from the file we just created (realtime.js).
In our send function, we can simply trigger the message
event (that's how we called it in the server-side part) with the message:
<script lang="ts">
import { io } from "$lib/realtime";
import { onMount } from "svelte";
let textfield = ""
let username = ""
let messages = []
function sendMessage() {
const message = textfield.trim()
if(!message) return
textfield = ""
io.emit("message", message) // Send the message
}
</script>
Receive messages
To receive messages, we need to listen to the message
event (that's how we called it in the server-side part). The object we receive is the same object we sent (server-side) and we can just add it to the messages
array:
<script lang="ts">
import { io } from "$lib/realtime";
import { onMount } from "svelte";
let textfield = ""
let username = ""
let messages = []
onMount(() => {
io.on("message", message => { // Listen to the message event
messages = [...messages, message]
})
io.on("name", name => { // Another listener for the name:
username = name // Update the name so it can be displayed
})
})
function sendMessage() {
const message = textfield.trim()
if(!message) return
textfield = ""
io.emit("message", message) // Send the message
}
</script>
Now, run npm run dev
and test it out:
And that's it - now you can send data in realtime between the server and the client! π
Thanks for reading and have a great day π€
This article helped you? β¬οΈ
Top comments (2)
Thanks a lot for sharing this
how do you use socket in api route? For example, I got api route "register" with the file name +server.ts
In there, after user register, I want to emit a message call "success".
How can I access the io inside that +server.ts file?