fastify / fastify/fastify-vite

Conflicting websockets between vite and `@fastify/websocket` causing infinite redirects

Open
#129 4 comments 10 reactions 0 assignees View on GitHub
bug help wanted
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.