kiliman/remix-express-vite-plugin

Built (prod) HTTP/2 server doesn't work on Windows

Closed this issue ยท 8 comments

On Windows (Node 20 and tried 18 just for fun), I get the following (with Node's --trace-warnings enabled) when running the built/prod output:

Express server listening at https://localhost:3000/
(node:3800) UnsupportedWarning: Status message is not supported by HTTP/2 (RFC7540 8.1.2.4)
    at statusMessageWarn (node:internal/http2/compat:121:13)
    at Http2ServerResponse.set statusMessage [as statusMessage] (node:internal/http2/compat:704:5)
    at write (C:\dev\test\remix-vite-express\node_modules\finalhandler\index.js:279:23)
    at AsyncResource.runInAsyncScope (node:async_hooks:206:9)
    at listener (C:\dev\test\remix-vite-express\node_modules\on-finished\index.js:170:15)
    at onFinish (C:\dev\test\remix-vite-express\node_modules\on-finished\index.js:101:5)
    at callback (C:\dev\test\remix-vite-express\node_modules\ee-first\index.js:55:10)
    at Http2ServerRequest.onevent (C:\dev\test\remix-vite-express\node_modules\ee-first\index.js:93:5)
    at Http2ServerRequest.emit (node:events:518:28)
    at endReadableNT (node:internal/streams/readable:1696:12)
TypeError: Headers.set: ":method" is an invalid header name.
    at Object.webidl.errors.exception (node:internal/deps/undici/undici:1801:14)
    at Object.webidl.errors.invalidArgument (node:internal/deps/undici/undici:1812:28)
    at _Headers.set (node:internal/deps/undici/undici:2400:31)
    at createRemixHeaders (C:\dev\test\remix-vite-express\node_modules\@remix-run\express\dist\server.js:59:17)
    at createRemixRequest (C:\dev\test\remix-vite-express\node_modules\@remix-run\express\dist\server.js:82:14)
    at file:///C:/dev/test/remix-vite-express/node_modules/remix-create-express-app/dist/middleware.js:18:23
    at file:///C:/dev/test/remix-vite-express/node_modules/remix-create-express-app/dist/index.js:56:67

I still get the warning on macOS, but I don't get the error (and it works).

Here's a reproduction repo, but it's essentially your example:

https://github.com/wKovacs64/remix-vite-express

Ok, I'll check it out. Are you able to get a basic http2 server on Windows without Remix, Vite, etc. Just want to confirm baseline support.

Good question, never had the need - will try it.

Ok, I'll check it out. Are you able to get a basic http2 server on Windows without Remix, Vite, etc. Just want to confirm baseline support.

Yes, this works fine:

import fs from "node:fs";
import path from "node:path";
import http2 from "node:http2";
import http2Express from "http2-express-bridge";
import express from "express";

const app = http2Express(express);

app.get("/", (req, res) => {
  res.send("Hello World!");
});

const server = http2.createSecureServer(
  {
    key: fs.readFileSync(path.resolve("other/localhost-key.pem")),
    cert: fs.readFileSync(path.resolve("other/localhost-cert.pem")),
    allowHTTP1: true,
  },
  app,
);

server.listen(3000, () => {
  console.log(`listening on port 3000`);
});
$ curl --insecure https://localhost:3000
Hello World!

Hmm.. ran this on Windows 11 and it "works", but it's not using HTTP/2. I'm not sure what it's doing.

image

Sorry, I should have clarified - dev "works" (HTTP/1.1) fine. It's prod that doesn't. Updated the issue.

Yeah, brain fart. I forgot that Vite controls the dev server...

Anyway, I got it working on Windows with a production build. Middleware doesn't seem to be working as the session middleware isn't committing the cookie.

But you can see it's using the h2 protocol. I'll clean this up in the morning and push an update.

image

But it does work correctly with Vite dev server, including the h2 protocol.

Session updates properly as well.

image

The rule is that anything having to do with dev is configured by Vite. My plugin helps you with the prod server.

export default defineConfig({
  build: {
    target: "esnext",
  },
  server: {
    https: {
      key: fs.readFileSync(
        path.resolve(path.join(process.cwd(), "other/localhost-key.pem"))
      ),
      cert: fs.readFileSync(
        path.resolve(path.join(process.cwd(), "other/localhost-cert.pem"))
      ),
    },
  },
  plugins: [
    expressDevServer(),
    envOnly(),
    remix({
      future: { unstable_singleFetch: true },
    }),
    tsconfigPaths(),
  ],
});

Fixed in v0.3.3

I sent you a PR for your example app wKovacs64/remix-vite-express#1

Sweet, thank you!