Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(middleware-mode): single server for http and websocket #16

Merged
merged 5 commits into from
Jan 28, 2023

Conversation

naruaway
Copy link
Contributor

@naruaway naruaway commented Jan 10, 2023

This comes from vitejs/vite#11487

I think we should utilize Vite's ability to reuse an existing HTTP server for WebSocket for middleware-mode example in this repo.
I consider Vite's middleware mode's very important feature is to be able to rely on single HTTP server for everything including HMR.
The server can:

  • Serve HTML files with custom logic
  • Serve static files such as JS / CSS from Vite middleware under dedicated path
  • Work as WebSocket server for HMR

I think this repo is a perfect place to demonstrate / advertise this useful pattern with minimal example.
One of the reasons why I like this setup and why I think we should advertise more is because this setup is simpler than others and more composable than others with other configurations such as reverse proxy.
As long as reverse proxy supports proxing WebSocket, the simplest set up Custom Server <-> Proxy <-> Browser is possible. There is no need to make sure browser can talk to Vite's hard-coded port (24678) for HMR.
Also, TCP port is shared resource. With this setup, users of this server can just choose one port and it will just work without causing conflicts with other local dev servers in the same host.

If this looks good for maintainers, we can merge this after merging vitejs/vite#11487 since the test in this PR is failing due to "a bug" fixed there

Verification

Before this PR, HMR in examples/middleware-mode was working via the hard-coded 24678 port, which means it was not possible to run multiple instances simultaneously on the same host. Also if there is proxy-ish thing which only allows single port to be relayed (e.g. SSH port forward and/or HTTP reverse proxy), this setup was not working out of the box.

After this PR with vitejs/vite#11487, it will always try to connect to the "current server", which means it will always work even the server is hidden under reverse proxy and Vite server itself is not reachable (e.g. due to firewall or SSH port forward)
The following screenshot is taken with the Vite PR, where we see WebSocket is using the same port as the main URL:

ok

Other considerations

  • I added base config to vite.config.js because without this, Vite client will try to connect to / for WebSocket HMR. Considering this is an example of "custom server", I think this is not reasonable since the owner of the custom server should be able to freely use that "root namespace" for WebSocket. I think it makes sense to have "proper namespacing" even for this minimal example. Vite should not "occupy" the root name space ("/")

  • If this is acceptable, we need to update the diagram in README.md as well. It will look like the following (this diagram visually shows the simplicity of the new config hopefully; browser does not need to know Vite, which is "abstracted away" by custom server, which is fully controlled by integrators):

    • after-pr
  • "Direct websocket connection fallback" does not work as expected with this setup but I personally think it's fine. For this setup, it's user's responsibility to make sure browsers can connect to the custom server for WebSocket

  • (completely out of scope but I'm thinking whether it's possible to use Server Sent Events instead of WebSocket for further simplification for Vite HMR setup (e.g. some corporate proxy can block WebSocket)...)

@sapphi-red
Copy link
Owner

Thanks!

Would you add a test for the original one (one without the server.hmr.server), too?
https://github.com/sapphi-red/vite-setup-catalogue/tree/main/tests/fixtures and https://github.com/sapphi-red/vite-setup-catalogue/tree/main/tests/fixtures-cases

(completely out of scope but I'm thinking whether it's possible to use Server Sent Events instead of WebSocket for further simplification for Vite HMR setup (e.g. some corporate proxy can block WebSocket)...)

There are some cons of SSE. Recently esbuild implemented a live reload feature and described about these. https://github.com/evanw/esbuild/releases/tag/v0.17.0#:~:text=The%20EventSource%20API,itself%20(see%20below).

WebSocket connections have a different connection pool from the normal HTTP connections. (https://stackoverflow.com/a/26013035) So by using WebSockets, we can effectively use the 6 connections to serve the JS/CSS files from Vite.

@naruaway
Copy link
Contributor Author

naruaway commented Jan 18, 2023

Thanks @sapphi-red, now I added a new test case "middleware-mode-with-separated-vite" in cf19771, which replicates the behavior of the original one (simplified a little like removing fs.readFile('index.html') thing since it was doing nothing because Vite's middleware mode serves index.html by default when we do not have appType)

For the comment about SSE: Thanks for sharing, especially an attempt in esbuild. Really interesting and now feeling it's not worth exploring much for Vite. Ooccupying 1 connection out of the precious 6 connections are really bad...

@sapphi-red
Copy link
Owner

Thanks for adding the test case. I updated the README image.
As your PR to Vite was released in Vite 4.1.0-beta.1, this PR is now passing the test 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants