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
I've been trying to combine Elysia with Socket.io for a while and yet no perfect solution. But here is what I found.
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)
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With