Skip to content

HTTP/2 dev server #1027

Open

Description

@ProgramRipper

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

Final checks

Activity

  1. transferred this issue fromnuxt/nuxton Sep 4, 2025
  2. danielroe commented on Sep 4, 2025

    @danielroe
    Member

    cc: @pi0 - what do you think?

  3. ProgramRipper commented on Sep 4, 2025

    @ProgramRipper
    Author

    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. 😉

  4. userquin commented on Sep 4, 2025

    @userquin
    Member

    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;
  5. ProgramRipper commented on Sep 17, 2025

    @ProgramRipper
    Author

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions