Using WebSockets With SvelteKit

Published May 1, 2022

Table of Contents

Using WebSockets

If youโ€™re reading this in the future SvelteKit might have native support for WebSockets similar to how it does HTTP request methods so it might be worth checking the documentation.

+server.ts
// HTTP request methods
export function GET() {}
export function POST() {}

// Doesn't exist yet! ๐Ÿ˜…
export function WS() {}

You can read the discussion about native support for WebSockets inside SvelteKit if you want.

One solution is to create a separate server but then you have to run two things on separate ports so let me show you how you can do it using SvelteKit instead.

WebSockets For Development

To be able to use WebSockets during development you need to write a simple plugin for Vite using the configureServer method to hook into the development server.

Credit goes to Bob Fanger for the solution.

Install the Node adapter with npm i -D @sveltejs/adapter-node because itโ€™s required for this to work.

vite.config.ts
import { sveltekit } from '@sveltejs/kit/vite'
import { type ViteDevServer, defineConfig } from 'vite'

import { Server } from 'socket.io'

const webSocketServer = {
	name: 'webSocketServer',
	configureServer(server: ViteDevServer) {
		if (!server.httpServer) return

		const io = new Server(server.httpServer)

		io.on('connection', (socket) => {
			socket.emit('eventFromServer', 'Hello, World ๐Ÿ‘‹')
		})
	}
}

export default defineConfig({
	plugins: [sveltekit(), webSocketServer]
})

๐Ÿฟ๏ธ Use a dynamic import if you need to import code thatโ€™s not a module inside webSocketServer for example const code = await import('./code.js') otherwise youโ€™re going to encounter an error.

Hereโ€™s an example how this works using Socket.io on the client.

+page.svelte
<script lang="ts">
  import { io } from 'socket.io-client'

  const socket = io()

  socket.on('eventFromServer', (message) => {
    console.log(message)
  })
</script>

If you start the development server with npm run dev it should work and you should see the Hello, World ๐Ÿ‘‹ message in the console.

If you want to emit a message when a value changes donโ€™t forget you can use a reactive declaration block.

+page.svelte
<script lang="ts">
  // ...

  $: {
    // send message to server
    socket.emit('eventFromClient', $reactiveValue)
  }
</script>

WebSockets For Production

Thanks to the Sveltekit Node adapter you can create a custom server and do whatever you want.

Iโ€™m going to use Express because itโ€™s a minimal web framework.

terminal
npm i express @types/express

The Node adapter creates the index.js and handler.js files in your build folder when you run npm run build.

To use a custom server you have to import the handler from build/handler.js and use the custom server instead of index.js.

Create the build folder.

terminal
npm run build

I have created the server/index.js file at the root of the project for convenience but this depends on your build step and where youโ€™re deploying it.

server/index.js
import express from 'express'
import { createServer } from 'http'
import { Server } from 'socket.io'

import { handler } from '../build/handler.js'

const port = 3000
const app = express()
const server = createServer(app)

const io = new Server(server)

io.on('connection', (socket) => {
  socket.emit('eventFromServer', 'Hello, World ๐Ÿ‘‹')
})

// SvelteKit should handle everything else using Express middleware
// https://github.com/sveltejs/kit/tree/master/packages/adapter-node#custom-server
app.use(handler)

server.listen(port)

Add the script to start the server inside package.json.

package.json
{
  "scripts": {
    "start": "node ./server"
    // ...
  }
}

You can run npm start and open http://localhost:3000/ to check if everything works.

Thatโ€™s it! ๐Ÿฅณ

Support

You can subscribe on YouTube, or consider becoming a patron if you want to support my work.

Patreon
Found a mistake?

Every post is a Markdown file so contributing is simple as following the link below and pressing the pencil icon inside GitHub to edit it.

Edit on GitHub