DEV Community

Cover image for SvelteKit with SocketIO in Production
Shivam Meena
Shivam Meena

Posted on • Edited on

SvelteKit with SocketIO in Production

Read if:

  • You wanna learn how to use SocketIO with SvelteKit.

Resources

Introduction

This is going to be a series, this is first part of the series and from now on in every 2 days I'll release a new part of this series. Where I'm gonna make a fully fledge chat app using SvelteKit, socketIO, Express and maybe redis. This chat app going to have some features like: Making a group for chat, single chat and allow to join private group link using invitation.

Here I'm going to explain hoe to integrate SocketIO in SvelteKit because SvelteKit doesn't have a built-in support for WebSocket and we have to find a way to use SocketIO in the project for development and production.

Setup the project

First setup your SvelteKit project using init.

npm init svelte@latest anonChatApp
cd anonChatApp
npm install
npm run dev -- --open
Enter fullscreen mode Exit fullscreen mode

I'm using Tailwind CSS in this demo. I've already written an article on Using TailwindCSS in SvelteKit to make a Design System : Part One.

Here we will gonna use node adapter because of SvelteKit doesn't have built-in support for WebSockets. So we can't use auto adapter which help us to deploy it on vercel which is now out of the scope, we have to deploy it on our sever.

  • We are going to install adapter-node in our project
npm i -D @sveltejs/adapter-node
Enter fullscreen mode Exit fullscreen mode
  • Make the adapter changes in svelte.config.js file
import adapter from '@sveltejs/adapter-node';
import preprocess from 'svelte-preprocess';

/** @type {import('@sveltejs/kit').Config} */
const config = {
    // Consult https://github.com/sveltejs/svelte-preprocess
    // for more information about preprocessors
    preprocess: [
        preprocess({
            postcss: true
        })
    ],
    kit: {
        adapter: adapter()
    }
};

export default config;

Enter fullscreen mode Exit fullscreen mode

Adding SocketIO server

Install the dependencies for socket.io for server, socket.io-client for client and we also going to need express.

npm i socket.io socket.io-client express
Enter fullscreen mode Exit fullscreen mode

Here We going to make a vite plugin that going to help us with WebSocket in development version.

// webSocketPluginVite.js 
import injectSocketIO from './socketIoHandler.js';

export const webSocketServer = {
    name: 'webSocketServer',
    configureServer(server) {
        injectSocketIO(server.httpServer);
    }
};
Enter fullscreen mode Exit fullscreen mode
  • Above we are importing injectSocketIO from socketIoHandler.js. This file handles are all socketIO events e.g. connection, message, error.
// socketIoHandler.js
import { Server } from 'socket.io';

export default function injectSocketIO(server) {
    const io = new Server(server);

    io.on('connection', (socket) => {
        let username = `User ${Math.round(Math.random() * 999999)}`;
        socket.emit('name', username);

        socket.on('message', (message) => {
            io.emit('message', {
                from: username,
                message: message,
                time: new Date().toLocaleString()
            });
        });
    });

    console.log('SocketIO injected');
}

Enter fullscreen mode Exit fullscreen mode

That's a normal setup for dev now we have add plugin to our vite.config.js. So we can use websocket in development.

import { sveltekit } from '@sveltejs/kit/vite';
import { webSocketServer } from './webSocket.js';

/** @type {import('vite').UserConfig} */
const config = {
    server: {
        port: 3000
    },
    preview: {
        port: 3000
    },
    plugins: [sveltekit(), webSocketServer]
};

export default config;
Enter fullscreen mode Exit fullscreen mode
  • Above i have imported our plugin and added to vite plugin configuration which will now run our WebSockets in development mode.

  • But we have to add more to make it work in production. So, we have to make a build using node adapter that we configured in the start.

npm run build
Enter fullscreen mode Exit fullscreen mode
  • This will generate a build for your project now we have to extend our SvelteKit server to use WebSockets in it. That's why we needed express which is going to help us extend our default server of SvelteKit.
// server.js

import http from 'http';
import express from 'express';
import injectSocketIO from '../socketIoHandler.js';
import { handler } from '../build/handler.js';

const app = express();
const server = http.createServer(app);

// Inject SocketIO
injectSocketIO(server);

// SvelteKit handlers
app.use(handler);

server.listen(3000, () => {
    console.log('Running on http://localhost:3000');
});
Enter fullscreen mode Exit fullscreen mode
  • Now you can make a build and run it on production which is running on port 3000.

Adding SocketIO on Client

We already installed the dependency for client side of SocketIO. We gonna add a file in lib folder webSocketConnection.js which going to handle our socket connection for client.

import ioClient from 'socket.io-client';
const ENDPOINT = 'http://localhost:3000';

const socket = ioClient(ENDPOINT);

export const io = socket;
Enter fullscreen mode Exit fullscreen mode
  • In this we are exporting our socket which uses our endpoint which is running in port 3000.

  • Now we gonna take a look on client uses of SocketIO

<script lang="ts">
    import { io } from '$lib/webSocketConnection.js';
    import { onMount } from 'svelte';

    let textfield = '';
    let username = '';

    let messages = [];

    onMount(() => {
        io.on('message', (message) => {
            messages = [...messages, message];
        });
        io.on('name', (name) => {
            username = name;
        });
    });

    function sendMessage() {
        const message = textfield.trim();
        if (!message) return;

        textfield = '';
        io.emit('message', message);
    }
</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>
Enter fullscreen mode Exit fullscreen mode
  • As above in script section we are importing are client side socket connection and going to use it in our onMount function so we can get all the new messages and a username that is randomly generated on server. For sending message we are using emit in sendMessage function to send message on server and broadcast to all users.

It a basic setup for SocketIO on dev and prod in SvelteKit. We will continue in second part from here. If you wanna suggest some add on functionalities or features for project please comment it down.

Future me writing this, due to SvelteKit going to make some breaking changes in next update.

This is me writing for you. If you wanna ask or suggest anything please put it in comment.

Top comments (13)

Collapse
 
zeroql profile image
ZeroQLi

Eagerly waiting for the 2nd part

Collapse
 
theether0 profile image
Shivam Meena

Thanks you for your support. I'll try as soon as possible to write second part after i cover all the sveltekit changes.

Collapse
 
haond10adp profile image
Nguyễn Đức Hào

I'm looking forward to this

Collapse
 
fxmt2009 profile image
Ade

Anyone aware of a github repo with this setup?
Or a github with expressjs server integrated with sveltekit?

I'm trying to spin my own cutom express server but I get errors. It seems that the handlers.js is not passing anything to the expressjs once I add app.use(handlers) after I require handlers.js on top of the express server file of course.

Collapse
 
theether0 profile image
Shivam Meena
Collapse
 
jaodevtobi profile image
Tobi kin

Going through this in 2023 just wondering is they a better way to do this now? Or ..

Collapse
 
theether0 profile image
Shivam Meena

It depends on your need. What you wanna work in what is goal with it.

Collapse
 
jaodevtobi profile image
Tobi kin

Just for real time conversation on An online platform.

Is it possible without using expressjs like one of the +server files or something similer

Thread Thread
 
theether0 profile image
Shivam Meena

not yet. We have to extend it to use web-sockets. It works only for node adapter.

Thread Thread
 
jaodevtobi profile image
Tobi kin

Thanks for the reply..

Collapse
 
badalya1 profile image
badalya1

This is not so good, there is no way to get your sicketio instance into the apps server side code.

Collapse
 
hansamann profile image
Sven Haiges

the example works but how would I send a server side message from an api call in svelte to all in a room? i need to get access to the io object for this... how can I share it an svelte api?

Collapse
 
theether0 profile image
Shivam Meena