Skip to content

react-router@7 & vite@5 + SSL doesn't work #12558

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

Closed
iwan-uschka opened this issue Dec 16, 2024 · 12 comments
Closed

react-router@7 & vite@5 + SSL doesn't work #12558

iwan-uschka opened this issue Dec 16, 2024 · 12 comments
Labels
awaiting release This issue has been fixed and will be released soon bug

Comments

@iwan-uschka
Copy link

iwan-uschka commented Dec 16, 2024

Reproduction

I simply followed the instructions at https://reactrouter.com/start/framework/installation

npx create-react-router@latest my-react-router-app
cd my-react-router-app
npm i
npm run dev

and http://localhost:5173 just works.

Installing and adding @vitejs/plugin-basic-ssl to vite.config.js like

import { reactRouter } from "@react-router/dev/vite";
import autoprefixer from "autoprefixer";
import tailwindcss from "tailwindcss";
import { defineConfig } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";
import basicSsl from "@vitejs/plugin-basic-ssl";

export default defineConfig({
  css: {
    postcss: {
      plugins: [tailwindcss, autoprefixer],
    },
  },
  plugins: [reactRouter(), tsconfigPaths(), basicSsl()],
});

results in a server error when trying to open https://localhost:5173/:

npm run dev

> dev
> react-router dev

Re-optimizing dependencies because lockfile has changed
  ➜  Local:   https://localhost:5173/
  ➜  Network: use --host to expose
  ➜  press h + enter to show help
12:36:13 PM [vite] Internal server error: Headers.set: ":method" is an invalid header name.
      at Object.webidl.errors.exception (node:internal/deps/undici/undici:3564:14)
      at Object.webidl.errors.invalidArgument (node:internal/deps/undici/undici:3575:28)
      at _Headers.set (node:internal/deps/undici/undici:8814:31)
      at fromNodeHeaders (/Users/iwanuschka/projects/react-router-test/my-react-router-app/node_modules/@react-router/dev/dist/vite.js:803:17)
      at fromNodeRequest (/Users/iwanuschka/projects/react-router-test/my-react-router-app/node_modules/@react-router/dev/dist/vite.js:819:14)
      at nodeHandler (/Users/iwanuschka/projects/react-router-test/my-react-router-app/node_modules/@react-router/dev/dist/vite.js:1968:30)
      at /Users/iwanuschka/projects/react-router-test/my-react-router-app/node_modules/@react-router/dev/dist/vite.js:1975:23

I checked if the error occurs without React Router by following the instructions at https://vite.dev/guide/#scaffolding-your-first-vite-project

npm create vite@latest
npm create vite@latest my-react-app -- --template react

and installing and adding @vitejs/plugin-basic-ssl to vite.config.js like

import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import basicSsl from "@vitejs/plugin-basic-ssl";

// https://vite.dev/config/
export default defineConfig({
  plugins: [react(), basicSsl()],
});

. Result: https://localhost:5173/ does work.


The error does not occur after adding server.proxy = {} to vite.config.js:

import { reactRouter } from "@react-router/dev/vite";
import autoprefixer from "autoprefixer";
import tailwindcss from "tailwindcss";
import { defineConfig } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";
import basicSsl from "@vitejs/plugin-basic-ssl";

export default defineConfig({
  css: {
    postcss: {
      plugins: [tailwindcss, autoprefixer],
    },
  },
  server: {
    proxy: {},
  },
  plugins: [reactRouter(), tsconfigPaths(), basicSsl()],
});

According to vitejs/vite#4184 this leads to the usage of HTTP/1.1.


Probably related:


System Info

System:
    OS: macOS 15.1.1
    CPU: (10) arm64 Apple M1 Max
    Memory: 1.07 GB / 64.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.18.1 - ~/.nvm/versions/node/v20.18.1/bin/node
    npm: 10.8.2 - ~/.nvm/versions/node/v20.18.1/bin/npm
    pnpm: 9.0.6 - ~/Library/pnpm/pnpm
  Browsers:
    Brave Browser: 131.1.73.97
    Chrome: 131.0.6778.140
    Firefox Nightly: 126.0a1
    Safari: 18.1.1
  npmPackages:
    @react-router/dev: ^7.0.2 => 7.0.2 
    @react-router/node: ^7.0.2 => 7.0.2 
    @react-router/serve: ^7.0.2 => 7.0.2 
    react-router: ^7.0.2 => 7.0.2 
    vite: ^5.4.11 => 5.4.11

Used Package Manager

npm

Expected Behavior

Dev server running on HTTPS should work.

Actual Behavior

Dev server running on HTTPS doesn't work.

@iwan-uschka
Copy link
Author

Is it related and worth noting that undici (https://github.com/remix-run/react-router/blob/main/package.json#L108) now marks http/2 support as stable in https://github.com/nodejs/undici/releases/tag/v7.1.0?

@timdorr
Copy link
Member

timdorr commented Dec 16, 2024

What happens if you set your own server.https options? https://vite.dev/config/server-options.html#server-https

I'm using Remix+Vite with SSL myself (with some certs from mkcert) and don't have this issue. If it's helpful, this is my config:

import { resolve } from 'path'
import { existsSync, readFileSync } from 'fs'

import { vitePlugin as remix } from '@remix-run/dev'
import { defineConfig } from 'vite'
import tsconfigPaths from 'vite-tsconfig-paths'

const crtPath = resolve(__dirname, 'tls.crt')
const keyPath = resolve(__dirname, 'tls.key')

const httpsOptions = existsSync(crtPath)
  ? {
      cert: readFileSync(crtPath),
      key: readFileSync(keyPath)
    }
  : {}

export default defineConfig({
  server: {
    port: 1234,
    host: 'localhost',
    https: httpsOptions
  },
  plugins: [
    remix({
      future: {
        v3_routeConfig: true,
        v3_fetcherPersist: true,
        v3_relativeSplatPath: true,
        v3_throwAbortReason: true,
        v3_singleFetch: true,
        v3_lazyRouteDiscovery: true
      }
    }),
    tsconfigPaths()
  ]
})

@Inkvii
Copy link

Inkvii commented Dec 17, 2024

@timdorr
reproduced same error on fresh react router v7 with https. Error

[vite] Internal server error: Headers.set: ":method" is an invalid header name.
      at Object.webidl.errors.exception (node:internal/deps/undici/undici:3610:14)
      at Object.webidl.errors.invalidArgument (node:internal/deps/undici/undici:3621:28)
      at _Headers.set (node:internal/deps/undici/undici:8898:31)

Error occurs by adding config to vite.config.ts.

server: {
	host: "my.host.com",
	https: {
		key: fs.readFileSync("./key.pem"),
		cert: fs.readFileSync("./cert.pem"),
	},
},

Just for clarification - this happens ONLY if you try to use react-router. If you init project with https://remix.run/docs/en/main/start/quickstart (just like you seem to have) there is no error and https works

@iwan-uschka
Copy link
Author

iwan-uschka commented Dec 22, 2024

Thank you @timdorr. I'm having the same problems after following your suggestion and configuring https on my own using a self signed certificate.

@stephencattaneo
Copy link

FWIW the proxy: {}, workaround mentioned here remix-run/remix#7867 works

@neilhsmith
Copy link

Same issue here when setting the https option manually with self signed certs. But the empty proxy option does work for me too.

@ConnorCallison

This comment has been minimized.

timdorr added a commit that referenced this issue Jan 22, 2025
When HTTPS is enabled, the dev server switches to HTTP/2. This creates H2 psuedo-headers in the request that are currently incompatible with unidici's parsing. This strips out those headers, with special handling for :authority (see RFC 9113: https://www.rfc-editor.org/rfc/rfc9113.html#section-8.3.1-2.3.5).

Fixes #12558
@timdorr
Copy link
Member

timdorr commented Jan 22, 2025

Dug into this a bit more. Figured out how to strip out those HTTP/2 pseudo-headers and have the dev server load with an HTTPS config set. Submitted a PR over here: #12830

I tested it locally with my project that I've now converted to RR7 and it works great, AFAICT. In fact, the whole upgrade to RR7 took me only a few minutes, so that's pretty awesome 👍

@brophdawg11
Copy link
Contributor

Thanks for the PR @timdorr! this is resolved by #12830 and will be available in the next release

@brophdawg11 brophdawg11 added the awaiting release This issue has been fixed and will be released soon label Feb 19, 2025
@iwan-uschka
Copy link
Author

iwan-uschka commented Mar 30, 2025

I was finally able to test the new version of react-router. I am still getting errors after removing proxy: {} from vite.config.ts:

4:12:58 PM [vite] Internal server error: HTTP/1 Connection specific headers are forbidden: "transfer-encoding"
at mapToHeaders (node:internal/http2/util:644:13)
at ServerHttp2Stream.respond (node:internal/http2/core:2795:25)
at Http2ServerResponse.[begin-send] (node:internal/http2/compat:894:19)
at Http2ServerResponse.writeHead (node:internal/http2/compat:769:21)
at Http2ServerResponse.write (node:internal/http2/compat:808:12)
at Readable.ondata (node:internal/streams/readable:1009:22)
at Readable.emit (node:events:518:28)
at addChunk (node:internal/streams/readable:561:12)
at readableAddChunkPushObjectMode (node:internal/streams/readable:538:3)
at Readable.push (node:internal/streams/readable:393:5)
at nextAsync (node:internal/streams/from:194:22)
at processTicksAndRejections (node:internal/process/task_queues:95:5)

It seems to work until images are loaded.

My current setup:

@timdorr, how did you decide which header to remove in https://github.com/remix-run/react-router/pull/12830/files#diff-489c649e7a38f1ca9213711bd588eb3694144b24ad42a1f9b18c75621dbe7cbeR15 ?

@timdorr
Copy link
Member

timdorr commented Mar 30, 2025

From the spec: https://www.rfc-editor.org/rfc/rfc9113.html#name-request-pseudo-header-field

@iwan-uschka
Copy link
Author

In my project i have a route /api proxying to a separate backend API. This route is also used for fetching assets/images (causing the trouble). On the remote production system a proxy server is taking care of these request and the RR route /api isn't used. So it's purpose has always been dev-only.

I now ended up adding a proper proxy configuration in my vite.config.ts to be able to remove that route completely. Which is a bit funny because i solved this "problem" of not being forced to set proxy: {} by adding a proper proxy configuration :)

Nevertheless, thanks for taking care of this issue @timdorr!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
awaiting release This issue has been fixed and will be released soon bug
Projects
None yet
Development

No branches or pull requests

7 participants