vite icon indicating copy to clipboard operation
vite copied to clipboard

`vite.middleware` but for WinterCG `Request/Response`

Open juliusmarminge opened this issue 2 years ago • 11 comments

Description

https://vitejs.dev/guide/ssr#setting-up-the-dev-server shows how to setup a dev server for ssr using express. with more and more server frameworks moving away from the Node.js Connect style API to be more Request/Response, I wonder if maybe Vite should have middlewares for those applications too?

Suggested solution

import { Hono } from 'hono'
import { createServer as createViteServer } from 'vite'
  
const app = new Hono()
const vite = await createViteServer({
  server: { middlewareMode: "winter-cg" },
  appType: 'custom'
})

app.use("*", (c, next) => {
  // run the vite middlewares
  await vite.middlewares(c.req, c.res, next)
});

or similar to make it compatible with req/res frameworks?

Alternative

No response

Additional context

No response

Validations

juliusmarminge avatar Dec 19 '23 15:12 juliusmarminge

Hi @juliusmarminge

I'm a creator of Hono. We are working on a similar project for Hono. Below is a dev server Vite plugin for Hono and fetch-based applications.

https://github.com/honojs/vite-plugins/tree/main/packages/dev-server

Whether or not Vite itself will implement these things is a matter of discussion, but for now, try this.

yusukebe avatar Jan 16 '24 02:01 yusukebe

Hi @yusukebe , I think the dev-server plugin for Hono has a limitation with websockets currently, specifically for Node and Bun.

I'm wondering if it's possible to expose a createMiddleware function as an optional function from the package instead of a whole Vite plugin?

The limitation I encountered is with Websockets and mainly because of its forced-way of writing the Entry Point in Dev.

It forces you to always do this at the entry point:

export default {
  fetch: app.fetch,
  port: 3000,
};

as well as making sure your pnpm dev script calls vite


In Node The dealbreaker with Node is that I can't use serve() during dev. Which I think is the only option for me to run websockets in Node: https://github.com/honojs/vite-plugins/issues/148

In Bun Since I can't use Bun.serve in dev either, websockets don't seem to behave correctly. Even if you can attach websocket on the entry point: https://github.com/honojs/vite-plugins/issues/140

export default {
   fetch: app.fetch,
   port: 3000,
   websocket: websocket
}

If there was a createViteToHonoMiddleware function, maybe we could have the option to do something like this at the handler instead:

import { resolve } from 'node:path';

if (privateConfig.NODE_ENV !== 'production') {
  const root = resolve(__dirname, '../..');

  // Instantiate Vite's development server and integrate its middleware to our server.
  // ⚠️ We should instantiate it *only* in development. (It isn't needed in production
  // and would unnecessarily bloat our server in production.)
  const vite = await import('vite');
  const viteDevMiddleware = (
    await vite.createServer({
      root,
      server: {
        middlewareMode: true,
        hmr: { port: privateConfig.HMR_PORT },
      },
    })
  ).middlewares;

  // @ts-ignore
  app.use(createViteToHonoMiddleware(viteDevMiddleware)); // 👈  createViteToHonoMiddleware
}

And then be able to keep pnpm dev as tsx server.ts instead of vite.


I am basing this on the implementation here: https://github.com/blankeos/express-vike-websockets wherein both HMR and websockets work in a custom express server with Vite.

Blankeos avatar Jun 26 '24 20:06 Blankeos

Hi @Blankeos

createViteToHonoMiddleware sounds good.

This is not only for the Vite matter, but if we can use the Connect in the Hono app, we can use vite.middlewares.

yusukebe avatar Jun 28 '24 22:06 yusukebe

Awesome! @yusukebe Let me know if you want to move this discussion elsewhere, but after researching some more, I found that it's actually possible to overcome the limitation I mentioned. (But only on Node).

I have recreated the express-vike-websockets example above but in Hono: https://github.com/blankeos/hono-vike-websockets

I think a createViteToHonoMiddleware that works on both Bun and Node would be cool. But I don't know if it's possible because Bun does not expose an http.Incoming for the Bun.serve like Node does with @hono/node-server serve(..) (but maybe I'm just missing something).

Credits to @phonzammi's solution on Discord for making Hono + Vite's createServer work.

Blankeos avatar Jun 28 '24 23:06 Blankeos

Great Hono has a solution however a WinterCG middleware is still needed for other modern servers like Elysia, H3 (v2), etc..

quentindutot avatar Jul 25 '24 10:07 quentindutot

@Blankeos https://github.com/vikejs/vike-node/blob/main/packages/vike-node/src/runtime/adapters/connectToWeb.ts Supports streaming and Bun.serve also

const webHandler = connectToWeb(vite.middlewares)
const response = await webHandler(request)
return response

nitedani avatar Jul 31 '24 17:07 nitedani

I agree with @QuentinDutot. I think a general WinterCG solution should exist since Vite is part of the "modern web toolchain" and the connect middleware pattern is not (imo).

Is there any update on this?

bene avatar Mar 06 '25 21:03 bene

I think a more standard pattern should also be supported.

I created universal-middleware to support this same vision more globally. There are really powerful thing that we can do if we try to standardize those patterns. @universal-middlweware/express already supports casting Universal Middleware to Connect ones, so implementation in Vite could be done without too much pain at first IMO. I have an example of such usage in vite-plugin-vercel.

In Vike, universal-middleware allows us to declare middlewares and make them run on any server we can, deploy anywhere we want, while only writing them once.

magne4000 avatar Mar 06 '25 22:03 magne4000

I stumbled onto that problem today, and considering we are in 2025 now, it feels more and more urgent to easlily integrate WinterCG compliant servers in the local ViteJS dev server! Having adapters is a workaround but they are fairly complicated and having a native support in Vite.js would bring a great performance improvement! 🙏

zipang avatar May 03 '25 09:05 zipang

Ideally, Vite would only use web standards such as Request and Response — which already cover a lot of what Vite needs. That said, there is still a gap between web standards and what Vite needs. That's where universal-middleware steps in: it's a minimal library built around web standards to fill the gap between web standards and common needs.

FYI, in the context of building Vike, we tried to only use web standards but unfortunately realized that web standards alone aren't enough. That's why we built universal-middleware: it's the missing library that is unopinionated while filling the gap.

We think it also makes sense for Vite: replacing Connect middlewares with web standards + universal-middleware would enable Vite's middlewares to directly run in non-Connect environments.

Edit: for the Vite ecosystem folks who have access to #ecosystem on Vite's Discord, this reply was copied from a discussion we had on Discord.

brillout avatar May 03 '25 10:05 brillout

I wonder if connect could be replaced with the unopinionated srvx which works in all runtimes and has node.js compat too

TheAlexLichter avatar May 20 '25 20:05 TheAlexLichter

For people struggling with this: the easiest workaround I found is using https://github.com/mhart/fetch-to-node

bene avatar Jul 03 '25 18:07 bene