Skip to content

Move the frontend to React 19, Vite 8 and React Router 8 - #58

Merged
Sulaiman-Dauda merged 3 commits into
mainfrom
deps/react-19-vite-8
Oct 6, 2026
Merged

Sulaiman-Dauda merged 3 commits into
mainfrom
deps/react-19-vite-8

Conversation

@Sulaiman-Dauda

@Sulaiman-Dauda Sulaiman-Dauda commented Oct 6, 2026 •

Copy link
Copy Markdown
Owner

What this changes

The frontend moves to React 19, Vite 8 and React Router 8 in one step, as #41 planned. Dependabot's separate PRs cannot pass alone, since react-dom 19 needs @types/react 19 in step, @vitejs/plugin-react 6 needs Vite 8, and React Router 8 needs React 19.2.7 or later.

Package From To
react, react-dom 18.3.1 19.3.0
@types/react, @types/react-dom 18.3 19.3.0
vite 6.4.3 8.3.3
@vitejs/plugin-react 4.3.4 6.1.2
react-router 7.18.4 8.4.0

The only source change is the type of useModalFocus's ref in web/src/ui/Modal.tsx. React 19 types useRef(null) as RefObject<T | null>, and the hook already guarded against a null element.

The lockfile removes 98 packages (Babel, Rollup, esbuild) and adds 31 (Rolldown and Lightning CSS with their platform builds, plus @remix-run/route-pattern and cookie-es for the router). None of the new ones has an install script and all resolve from the npm registry. source-map-js moves to 1.2.2, which closes Dependabot alert 7. The libc markers on the Linux native packages are kept, taken from each package's registry manifest, so npm ci installs only the glibc builds. Without them local npm 10 would drop the markers and CI would fetch both glibc and musl binaries.

Worth knowing

  • Bundle size. The main script grows from 114 to 132 kB gzipped, mostly React 19.
  • Browser floor. Vite 8's default build target is Chrome 111, Firefox 114 and Safari 16.4, and Lightning CSS writes media queries in range syntax (width>=40rem). Tailwind 4 already needed the same browsers, so no supported browser loses anything.
  • CSS rules are equivalent. I built main and this branch and compared them. Both have the same 678 selectors in the main stylesheet and 48 in the terminal stylesheet, with the same !important rules, written differently by the new minifier. The terminal stylesheet is smaller mostly because Lightning CSS drops xterm's licence comment. The same notice still ships in xterm's JavaScript.
  • Licence headers. Review found that Rolldown's minifier drops the @license comments esbuild kept, so the embedded bundle would have shipped React, React Router and xterm without their notices. The second commit sets rolldownOptions.output.comments.legal, which restores every notice main shipped (22 headers in the main script, 4 in the terminal script), for 0.6 kB gzipped.
  • Node 22.22 or later is now needed to build the frontend, because of React Router 8. CI already gets 22.23 from node-version: 22, and CONTRIBUTING.md now says 22.22+.

How it was verified

  • npm run build (typecheck included), npm test 23 of 23, and npm audit reports 0 vulnerabilities.
  • The Playwright smoke test passed on the first attempt against a fresh local instance built from this branch. It claims the instance, creates a project, deploys it for real, follows the live log and signs out.
  • A navigation harness ran 75 checks in headless Chromium, all passing. It covers every top-level page and every settings section, and every project tab clicked from three starting tabs with the active tab marked. It also covers back and forward through the tab history, the in-project links on the Overview, command palette navigation from inside a project, and picking a deployment (?d=) to show its log. Modal focus is checked too (focus moves in, Tab stays inside, Escape closes and focus returns), and the terminal connects and runs a command inside the container.
  • To check the harness can actually catch a routing bug, I rebuilt with the project tabs switched back to relative links, the bug from the React Router 7 move. It failed 46 checks.
  • The mobile navigation drawer, which shares useModalFocus, was checked at 390 px wide. Focus is trapped, Escape closes it, and a link navigates and closes it.
  • No page errors and no React warnings in the console. The only failed request was /system/update, which got a 502 because GitHub rate limits unauthenticated release checks after many local restarts.

Not checked: the route error boundary's fallback, because nothing in the app can throw a render error on demand. Its class API (getDerivedStateFromError, componentDidCatch) is unchanged in React 19.

Once this is merged, #49, #50 and #52 are superseded and will be closed.

Fixes #41

🤖 Generated with Claude Code

Sulaiman-Dauda and others added 3 commits October 6, 2026 16:18
Dependabot raised these as separate PRs that cannot pass alone (#49, #50,
#52): react-dom 19 needs @types/react 19 in step, @vitejs/plugin-react 6
needs Vite 8, and React Router 8 needs React 19.2.7 or later. They move
together here (#41).

- react, react-dom, @types/react and @types/react-dom 18 to 19.3
- vite 6.4 to 8.3 and @vitejs/plugin-react 4 to 6
- react-router 7.18 to 8.4

The only source change is the type of useModalFocus's ref. React 19 types
useRef(null) as RefObject<T | null>, and the hook already handled a null
element.

The lockfile drops Babel, Rollup and esbuild for Rolldown and Lightning
CSS, adds no package with an install script, and moves source-map-js to
1.2.2, which closes Dependabot alert 7. The libc markers on the Linux
native packages are kept, so npm ci installs only the glibc builds.

Fixes #41

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…de 22.22

Vite 8 minifies with Rolldown and Lightning CSS, which drop the @license
comments esbuild kept. The release binary embeds web/dist, so it would
have shipped React, React Router and xterm without the notices their MIT
licences require. Rolldown's comments.legal option keeps them. xterm's
notice in its stylesheet still goes, but the same notice ships in its
JavaScript, as it did before.

React Router 8 needs Node 22.22 or later, so CONTRIBUTING.md now says so.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@Sulaiman-Dauda
Sulaiman-Dauda merged commit 8cb51f6 into main Oct 6, 2026
6 checks passed
@Sulaiman-Dauda
Sulaiman-Dauda deleted the deps/react-19-vite-8 branch October 6, 2026 15:34
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.

Upgrade the frontend to React 19 and Vite 8

1 participant