-
-
Notifications
You must be signed in to change notification settings - Fork 7.2k
Description
Clear and concise description of the problem
vite's WebSocket proxy doesn't work in middleware mode even if set ws: true
like the following.
import vite from 'vite';
import http from 'http';
let handler = (req, res) => {};
const parentServer = http.createServer(handler);
const viteServer = await vite.createServer({
server: {
middlewareMode: true,
proxy: {
'/ws': {
target: 'ws://localhost:8080',
changeOrigin: true,
ws: true, // even if true, websocket proxy doesn't work.
}
}
}
});
handler = (req, res) => async () => {
viteServer.middlewares(req, res, async () => {...})
}
parentServer.listen();
Because httpServer
is required to set up WebSocket proxy but httpServer
becomes null
in middleware mode.
vite/packages/vite/src/node/server/index.ts
Lines 315 to 317 in 5c177db
const httpServer = middlewareMode | |
? null | |
: await resolveHttpServer(serverConfig, middlewares, httpsOptions) |
vite/packages/vite/src/node/server/index.ts
Line 462 in 5c177db
middlewares.use(proxyMiddleware(httpServer, config)) |
vite/packages/vite/src/node/server/middlewares/proxy.ts
Lines 60 to 73 in 5c177db
if (httpServer) { | |
httpServer.on('upgrade', (req, socket, head) => { | |
const url = req.url! | |
for (const context in proxies) { | |
if (url.startsWith(context)) { | |
const [proxy, opts] = proxies[context] | |
if ( | |
(opts.ws || opts.target?.toString().startsWith('ws:')) && | |
req.headers['sec-websocket-protocol'] !== HMR_HEADER | |
) { | |
if (opts.rewrite) { | |
req.url = opts.rewrite(url) | |
} | |
proxy.ws(req, socket, head) |
So, we have to add WebSocket proxy code in our code with a way like copy&paste from proxyMiddleware
in proxy.ts
. This is a little inconvenient.
// add dependency for creating proxyServer
import { httpProxy } from 'http-proxy';
...
parentServer.on('upgrade', () => {
//
// copy & paste from
// https://github.com/vitejs/vite/blob/main/packages/vite/src/node/server/middlewares/proxy.ts#L35-L78
//
}).listen();
Suggested solution
I think it would be very useful to be able to pass the parent server like hmr
.
- vite/src/node/server/index.ts
export interface ServerOptions {
...
// current
// middlewareMode?: boolean | 'html' | 'ssr'
// this proposal
middlewareMode?:
| boolean
| 'html'
| 'ssr'
| { mode: true | 'html' | 'ssr'; parentServer: http.Server }
...
}
The following link shows an example implementation.
tomoam@38e54e7
In this case, WebSocket proxy will work in middleware mode, without adding any complicated code.
const parentServer = http.createServer(...);
...
const viteServer = await vite.createServer({
server: {
middlewareMode: {
mode: 'ssr',
parentServer: parentServer // pass the parent server
},
proxy: {
'/ws': {
target: 'ws://localhost:8080',
changeOrigin: true,
ws: true
}
}
}
});
...
parentServer.listen();
Alternative
export proxyMiddleware
.
- vite/src/node/index.ts
// add export
export { proxyMiddleware } from './server/middlewares/proxy'
The following link shows an example implementation.
tomoam@328610d
In this case, we will need to find and update the configured proxy middleware, but we will not need to copy and paste the code from proxy.ts
and import http-proxy
, and the impact will be minimal for vite.
...
const parentServer = http.createServer(...);
const viteServer = await vite.createServer({
server: {
middlewareMode: true,
proxy: {
'/ws': {
target: 'ws://localhost:8080',
changeOrigin: true,
ws: true
}
}
}
});
// find the proxy middleware in ViteDevServer.middlewares
const index = viteServer.middlewares.stack.findIndex(
(mw) =>
mw.route === '' &&
typeof mw.handle === 'function' &&
mw.handle.name === 'viteProxyMiddleware'
);
// update the proxy middleware with exported `proxyMiddleware`
viteServer.middlewares.stack[index].handle = vite.proxyMiddleware(
parentServer, // pass the parent server
viteServer.config
);
parentServer.listen();
Additional context
No response
Validations
- Follow our Code of Conduct
- Read the Contributing Guidelines.
- Read the docs.
- Check that there isn't already an issue that request the same feature to avoid creating a duplicate.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status