cli icon indicating copy to clipboard operation
cli copied to clipboard

HTTP/2 dev server

Open ProgramRipper opened this issue 4 months ago • 4 comments

Describe the feature

In development mode, large chunks of JS code create a large number of parallel HTTP/1.1 requests. And browsers like Chromium limit the max-connections-per-server to 6, which will quickly become overwhelming.

In my case, a single http request would wait nearly 6 sec before being sent, with a response within milliseconds.

I tested this idea by using Caddy (which can handle HTTP/2 requests) as a reverse proxy for the development server. It successfully reduces the wait time for individual requests to milliseconds (and all in parallel!).

I believe that if the Nuxt dev server could support HTTP/2 directly, we could achieve even better performance than my workaround. 😉

Additional information

  • [x] Would you be willing to help implement this feature?
    • unjs/listhen#206
  • [ ] Could this feature be implemented as a module?

Final checks

ProgramRipper avatar Sep 04 '25 10:09 ProgramRipper

cc: @pi0 - what do you think?

danielroe avatar Sep 04 '25 11:09 danielroe

I patch 2 lines of code and cracklingly impl it:

https://github.com/unjs/listhen/blob/a5890835cc0a10b3d7befde9cf565d84024e3846/src/listen.ts#L3

- import { createServer as createHTTPSServer } from "node:https";
+ import { createSecureServer as createHTTPSServer } from "node:http2";

https://github.com/unjs/httpxy/blob/73d2180e368e80379b6d6681f18e274df1006706/src/_utils.ts#L48

-   outgoing.headers = { ...req.headers };
+   outgoing.headers = Object.fromEntries(  // remove http/2 pseudo headers
+     Object.entries(req.headers).filter(([key]) => !key.startsWith(':'))
+   );

and gain even more performance than the reverse proxy solution in the original issue.

Here is a comparison of waterfall and a random request timing:

Image Image

I hope this information helps. 😉

ProgramRipper avatar Sep 04 '25 13:09 ProgramRipper

cc: @pi0 - what do you think?

@danielroe You have the patch for http2 headers and the http2 preset in my private repo (vite-ssg + md3 experiment repo), ping me at discord if required

EDIT:

patch for h3
diff --git a/dist/index.mjs b/dist/index.mjs
index 3ae960df62debc1840bb0f4d3187f4a402d321e3..3b9701545cba1d957dffede7be1ef1bb6f84da8c 100644
--- a/dist/index.mjs
+++ b/dist/index.mjs
@@ -1816,15 +1816,21 @@ function isEvent(input) {
 function createEvent(req, res) {
   return new H3Event(req, res);
 }
+function _normalizeHeaderName(name) {
+  if (name && name.length > 1 && name[0] === ":") {
+    return name.slice(1);
+  }
+  return name;
+}
 function _normalizeNodeHeaders(nodeHeaders) {
   const headers = new Headers();
   for (const [name, value] of Object.entries(nodeHeaders)) {
     if (Array.isArray(value)) {
       for (const item of value) {
-        headers.append(name, item);
+        headers.append(_normalizeHeaderName(name), item);
       }
     } else if (value) {
-      headers.set(name, value);
+      headers.set(_normalizeHeaderName(name), value);
     }
   }
   return headers;

userquin avatar Sep 04 '25 13:09 userquin

It looks like we may have to wait for listhen to migrate to srvx.

ProgramRipper avatar Sep 17 '25 10:09 ProgramRipper