fastify / fastify/fastify-vite
Conflicting websockets between vite and `@fastify/websocket` causing infinite redirects
- Dominant language
- TypeScript
- Stars
- 1.1k
- Forks
- 103
- Avg merge
- 6h 54m
- Merged PRs (30d)
- 7
Description
### Prerequisites
- [X] I have written a descriptive issue title
- [X] I have searched existing issues to ensure the bug has not already been reported
### Fastify version
4.24.3
### Plugin version
5.0.6
### Node.js version
20.x
### Operating system
Linux
### Operating system version (i.e. 20.04, 11.3, 10)
22.04
### Description
I have registered the plugin `@fastify/websocket` on my server and in development mode it is causing what is basically an infinite redirect when loading a page.
This appears to be due to how the `@fastify/websocket` plugin is attempting to handle the upgrade `GET 101` which is being initiated by the `vite` HMR client on page loading.
See this line in `@fastify/websocket` which is attempting to route any request upgrades on the server.
[https://github.com/fastify/fastify-websocket/blob/v8.3.1/index.js#L57](https://github.com/fastify/fastify-websocket/blob/v8.3.1/index.js#L57)
If I change `@fastify/vite` settings to _not_ attach the HMR server to the current application server, it will correct this infinite redirect behavior.
```javascript
# https://github.com/fastify/fastify-vite/blob/v5.0.6/packages/fastify-vite/mode/development.js#L18
// Create and enable Vite's Dev Server middleware
const devServerOptions = mergeConfig(
defineConfig({
configFile: false,
server: {
middlewareMode: true,
hmr: {
- server: this.scope.server
+ // server: this.scope.server
+ port: 5137 // set distinct port just for debugging
}
},
appType: 'custom'
}),
config.vite
)
```
So it appears that the vite dev server has been configured to piggy back on the application server so that it can share https/http2 configurations.
https://github.com/fastify/fastify-vite/commit/568e178a10768211944bfc1aaf6e57a6a091693d
That seems reasonable, but so does being able to easily use a plugin like `@fastify/websocket` and it seems reasonable for `@fastify/websocket` to handle upgrade requests for all requests against the application server to which it is attached, so I'm not sure what the best fix might be.
For my purpose it seems to work fine to add this to my projects `vite.config.js`
```
server: {
hmr: {
server: false,
port: 5173,
clientPort: 5173,
},
},
```
`false` is not technically a valid option for `vite.server.hmr.server` but it will prevent the application server settings being merged in from `@fastify/vite` where as `server: undefined` will not.
With realtime applications being more and more common, having support for websockets would be very helpful so at the very least including a note on this behavior, I think, would be a good idea.
Happy to submit a PR once a direction is discussed.
Thanks!
### Steps to Reproduce
- Start new project from up to date starter kit, ie "base" or "kitchensink"
- Install `@fastify/websocket` packages `npm install @fastify/websocket`
- Register plugin in `server.js`
```
await server.register(import('@fastify/websocket'))
```
- load index page and observe browser network tab or server logs for evidence of request re-routing and resulting page refresh loop.
You can check out this codesandbox for an example:
[Fastify Vite Kitchen Sink React Template](https://codesandbox.io/p/devbox/g86594?layout=%257B%2522sidebarPanel%2522%253A%2522EXPLORER%2522%252C%2522rootPanelGroup%2522%253A%257B%2522direction%2522%253A%2522horizontal%2522%252C%2522contentType%2522%253A%2522UNKNOWN%2522%252C%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522id%2522%253A%2522ROOT_LAYOUT%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522UNKNOWN%2522%252C%2522direction%2522%253A%2522vertical%2522%252C%2522id%2522%253A%2522clr401shx0007206cdx8mi54h%2522%252C%2522sizes%2522%253A%255B70%252C30%255D%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522EDITOR%2522%252C%2522direction%2522%253A%2522horizontal%2522%252C%2522id%2522%253A%2522EDITOR%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522contentType%2522%253A%2522EDITOR%2522%252C%2522id%2522%253A%2522clr401shx0003206cntc170pd%2522%257D%255D%257D%252C%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522SHELLS%2522%252C%2522direction%2522%253A%2522horizontal%2522%252C%2522id%2522%253A%2522SHELLS%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522contentType%2522%253A%2522SHELLS%2522%252C%2522id%2522%253A%2522clr401shx0004206cpoioh5q7%2522%257D%255D%252C%2522sizes%2522%253A%255B100%255D%257D%255D%257D%252C%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522DEVTOOLS%2522%252C%2522direction%2522%253A%2522vertical%2522%252C%2522id%2522%253A%2522DEVTOOLS%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522contentType%2522%253A%2522DEVTOOLS%2522%252C%2522id%2522%253A%2522clr401shx0006206cckw23w1k%2522%257D%255D%252C%2522sizes%2522%253A%255B100%255D%257D%255D%252C%2522sizes%2522%253A%255B50%252C50%255D%257D%252C%2522tabbedPanels%2522%253A%257B%2522clr401shx0003206cntc170pd%2522%253A%257B%2522id%2522%253A%2522clr401shx0003206cntc170pd%2522%252C%2522activeTabId%2522%253A%2522clr408ty9006t206brxu3ur8g%2522%252C%2522tabs%2522%253A%255B%257B%2522id%2522%253A%2522clr401shx0002206c3egayg8z%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522type%2522%253A%2522FILE%2522%252C%2522filepath%2522%253A%2522%252FREADME.md%2522%252C%2522state%2522%253A%2522IDLE%2522%257D%252C%257B%2522type%2522%253A%2522FILE%2522%252C%2522filepath%2522%253A%2522%252F.codesandbox%252Ftasks.json%2522%252C%2522id%2522%253A%2522clr408ty9006t206brxu3ur8g%2522%252C%2522mode%2522%253A%2522permanent%2522%257D%255D%257D%252C%2522clr401shx0006206cckw23w1k%2522%253A%257B%2522id%2522%253A%2522clr401shx0006206cckw23w1k%2522%252C%2522activeTabId%2522%253A%2522clr408pmi0045206btkch92z4%2522%252C%2522tabs%2522%253A%255B%257B%2522type%2522%253A%2522TASK_PORT%2522%252C%2522taskId%2522%253A%2522dev%2522%252C%2522port%2522%253A3000%252C%2522id%2522%253A%2522clr408pmi0045206btkch92z4%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522path%2522%253A%2522%252F%2522%257D%255D%257D%252C%2522clr401shx0004206cpoioh5q7%2522%253A%257B%2522id%2522%253A%2522clr401shx0004206cpoioh5q7%2522%252C%2522tabs%2522%253A%255B%255D%257D%257D%252C%2522showDevtools%2522%253Atrue%252C%2522showShells%2522%253Atrue%252C%2522showSidebar%2522%253Atrue%252C%2522sidebarPanelSize%2522%253A20.06100934306724%257D)
### Expected Behavior
To be able to use blessed fastify plugins (like `@fastify/websocket`) on the application server without very special configuration settings.
Contributor guide
Assessment
This issue has not been assessed yet.