honojs / vite-plugins

Vite Plugins for Hono
https://hono.dev
130 stars 34 forks source link

[@hono/vite-dev-server] add bun websocket support #140

Open youcefs21 opened 5 months ago

youcefs21 commented 5 months ago

dev server does not run websocket:

import { Hono } from "hono";
import { createBunWebSocket } from "hono/bun";

const { upgradeWebSocket, websocket } = createBunWebSocket();

const app = new Hono();

const ws = app.get(
    "/ws",
    upgradeWebSocket((c) => {
        console.log("WebSocket connected");
        let intervalId: Timer;
        return {
            onOpen(_event, ws) {
                intervalId = setInterval(() => {
                    ws.send(new Date().toString());
                }, 200);
            },
            onClose() {
                clearInterval(intervalId);
            },
        };
    }),
);

export default {
    fetch: app.fetch,
    websocket,
};

desired behaviour: should connect to websocket server when new WebSocket("ws://localhost:5173/ws") is called current behaviour: fetch requests work fine, websocket request hangs

Blankeos commented 4 months ago

+1 on this.

As a workaround I did this: (Separating 3000 backend and 3001 for ws) https://github.com/honojs/hono/issues/3013#issuecomment-2182893397

But encountered this: (Two instances of EventEmitter if I separate them, so not really viable for realtime stuff) https://github.com/trpc/trpc/discussions/5815#discussioncomment-9842891

It works fine on prod tho. Just dev that kinda sucks for devx.

Blankeos commented 4 months ago

To add more to the discussion. Here's a video to demonstrate that visually.

I was thinking I could just change the HMR port so it doesn't conflict with each other inside vite.config.js (It did not work tho).

https://github.com/honojs/vite-plugins/assets/38070918/4450a8c5-0a3b-454c-a372-d282a91ef31c

Have not tested on Node yet. But will try if I can when I get time.

yusukebe commented 4 months ago

Hi @youcefs21 @Blankeos

Hmmmm. I've reconsidered this issue. However, the WebSocket matter is tricky for the Vite dev-server. We can trust fetch based API is common for Cloudflare, Deno, Bun, and Node.js. Unfortunately, however, WebSocket is not standardized. As for that, there is a difference between Bun and Node.js:

Bun:

import { Hono } from 'hono'
import { createBunWebSocket } from 'hono/bun'

const { upgradeWebSocket, websocket } = createBunWebSocket()

// ...

Bun.serve({
  fetch: app.fetch,
  websocket,
})

Node.js:

import { createNodeWebSocket } from '@hono/node-ws'
import { Hono } from 'hono'
import { serve } from '@hono/node-server'

const app = new Hono()

const { injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app })

app.get('/ws', upgradeWebSocket((c) => ({
  // https://hono.dev/helpers/websocket
})))

const server = serve(app)
injectWebSocket(server)

To enable supporting both, we may add the option for choosing the current running runtime of Vite like the following:

import devServer from '@hono/vite-dev-server'
import { defineConfig } from 'vite'
import { runtime } from '@hono/vite-dev-server/bun'

export default defineConfig({
  plugins: [
    devServer({
      runtime
    })
  ]
})

I think this is relevant to Vite's new environment API: https://github.com/vitejs/vite/discussions/16358

Perhaps we can use a different runtime in Vite, like Node.js or worked (or Bun?). So, the better way is not to hurry up and follow the Vite's action though we have to figure out a workaround.