Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Bun+Elysia+socket.io together

I'm trying to build a web backend for a chat app using the runtime Bun, the library Elysia to write a REST API and the library socket.io to deliver the messages in realtime.

I went through the documentation of those 3 components, but I can't find a way to make them work together, either my GET requests are discarded by socket.io and never forwared to Elysia, or the opposite, Elysia doesn't forward the requests to socket.io.

I was trying to use the "Express" example of socket.io where they use "createServer(app)" of the http library where app is the express app, but I couldn't manage to do this for the Elysia app...

I know I could use two separate ports for the API and the socket or use Express for my REST API, but that's two options I'd like not to use.

If there is a working example for another modern router library like Hono, I could switch to another library.

Is there any documentation to do what I'm trying to do somewhere ?

Thanks !

Edit : I'm basically trying to do what is done on this link but with Bun and Elysia : https://socket.io/get-started/chat#integrating-socketio

like image 620
MrDaves Avatar asked Dec 05 '25 21:12

MrDaves


1 Answers

I've been trying to combine Elysia with Socket.io for a while and yet no perfect solution. But here is what I found.

Method 1: Proxy request form "/socket.io" to standalone Socket.io server.

This approach does not support native websocket protocol, so Socket engine will likely fallback to polling transport.

import { Elysia } from 'elysia'
import { Server } from 'socket.io'

const io = new Server().listen(21234)

io.on('connection', socket => {
  console.log('a user connected')
})

const app = new Elysia()
.all('/socket.io*', async ({ request }) => {
  const url = new URL(request.url)

  return fetch(url.toString().replace(url.origin, 'http://localhost:21234'), {
    method: request.method,
    headers: request.headers,
    body: new Uint8Array(await request.arrayBuffer()),
  })
})
.listen(3000)

Method 2: Using http server as entry point for both Elysia & Socket.io

Unlike first method, implement this way will allow socket.io support websocket transport, but all route registered by Elysia.ws will have no effect since upgrade websocket protocol aren't forward to Elysia.

import Elysia from 'elysia'
import { Server } from 'socket.io'
import { createServer } from 'node:http'

const app = new Elysia().get('/', 'hello world')

const http = createServer(async (req, res) => {
  const url = `http://${req.headers.host}${req.url || '/'}`

  // convert {IncomingMessage} to {Request}
  const request = new Request(url, {
    method: req.method,
    headers: new Headers(req.headers as any),
    body: req.method?.match(/GET|HEAD/i) ? null : new ReadableStream({
      start(controller) {
        req.on('error', err => controller.error(err))
        req.on('data', chunk => controller.enqueue(chunk))
        req.on('end', () => controller.close())
      }
    }),
  })

  const response = await app.handle(request) // wait for elysia handle request

  // Send {Response} from elysia to the client
  response.headers.forEach((value, key) => res.setHeader(key, value))
  res.writeHead(response.status, response.statusText)

  response.body?.pipeTo(new WritableStream({
    abort: reason => { res.destroy(reason) },
    write: chunk => { res.write(chunk) },
    close: () => { res.end() },
  }))
})

const io = new Server(http)

io.on('connection', socket => {
  console.log('a user connected', socket.id)
})

http.listen(3000)


Both of solution you could run on Bun and performance is lower because Elysia using Bun.fetch under the hood.

like image 109
Alex Avatar answered Dec 09 '25 21:12

Alex



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!