Skip to content

fix: dedupe react/react-dom in Vite to stop duplicate-copy hook crash#121

Merged
atomantic merged 1 commit into
mainfrom
fix/react-dup-copies-vite-dedupe
Jun 21, 2026
Merged

fix: dedupe react/react-dom in Vite to stop duplicate-copy hook crash#121
atomantic merged 1 commit into
mainfrom
fix/react-dup-copies-vite-dedupe

Conversation

@atomantic

Copy link
Copy Markdown
Owner

Problem

After a fresh pm2 start, the web UI rendered a blank white page with:

Warning: Invalid hook call. Hooks can only be called inside of the body of a function component.
Uncaught TypeError: Cannot read properties of null (reading 'useRef')
    at BrowserRouter (react-router-dom.js)

This is the classic two copies of React symptom.

Root cause

portos-ai-toolkit (added with the shared-CDP-browser change) declares react/react-dom@^18.3.1 as optional peers. npm auto-installed them and hoisted react@18 + react-dom@18 to the root node_modules/, where hoisted packages (react-router-dom, react-hot-toast, zustand, etc.) deduped onto React 18 — while the app itself loads React 19 from client/node_modules/. When the hoisted react-router-dom's BrowserRouter called useRef, it got the wrong/null React and crashed.

npm overrides can't fix this cleanly: it refuses to override the optional-peer-induced copies.

Fix

Add resolve.dedupe: ['react', 'react-dom'] to client/vite.config.ts, forcing every bare react/react-dom import (including from hoisted packages) to resolve to the single React 19 copy at the client root. This is the documented Vite remedy for "more than one copy of React".

Verification

  • Cleared the stale Vite optimize cache and restarted via PM2.
  • Loaded http://localhost:6373 in a browser: 0 console errors (was the React hook crash); page renders.
  • react-leaflet@5 requires react@19 — dedupe to the client copy satisfies it. scheduler follows react-dom resolution and needs no entry.
  • Client build passes.

portos-ai-toolkit declares react/react-dom@^18 as optional peers, so npm
hoists react@18 to the root node_modules while the app uses react@19 under
client/node_modules. Hoisted packages such as react-router-dom then resolve
the root react@18, loading two copies of React in the browser and crashing
with 'Invalid hook call' / useRef on null (blank page). resolve.dedupe forces
every bare react/react-dom import to the single client copy.
@atomantic atomantic merged commit 47c1326 into main Jun 21, 2026
1 check passed
@atomantic atomantic deleted the fix/react-dup-copies-vite-dedupe branch June 21, 2026 15:37
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.

1 participant