JORVEL

Troubleshooting

Hit a wall? Run jorvel diagnose first — it inspects Node, pnpm, ports, federation configs, and React-duplication risks. The issues below cover the rest.

Invalid hook call after loading a remote

Two copies of React are loaded. Symptoms include the console error Invalid hook call. Hooks can only be called inside of the body of a function component. firing the moment a remote mounts.

Checklist:

  1. react + react-dom must be singleton: true on both host and remote.
  2. Host sets eager: true on shared React; remotes use the default eager: false.
  3. Use native dynamic import('remote/App') — not a runtime loadRemoteModule() helper. Native imports let Rspack bridge the share scope at build time.
  4. Run jorvel diagnose — it will flag duplicate React versions discovered in node_modules.

Remote container not found after loading remoteEntry.js

The remoteEntry.jsscript loaded but the global container was never assigned. Usually the remote's name in its federation config does not match the name the host tries to load.

bash
# Verify both sides
cat apps/dashboard/jorvel.federation.json  | jq .name        # "dashboard"
cat apps/shell/rspack.config.mjs         | grep -A2 remotes # dashboard@...

# Regenerate if you renamed
jorvel federation

Dev-time 404 for a remote split chunk

Cross-origin chunks require CORS or same-origin. The fix is one flag:

bash
jorvel dev --proxy-remotes

That proxies /jorvel/remotes/<name>/* on the host origin to http://localhost:<port>/* on the remote — no CORS dance required.

Routes not updated after adding a page

The file-based routes manifest is static. One of:

  • Run jorvel routes once after adding/renaming a file in src/pages/.
  • Run jorvel routes --watch in a second terminal during dev — it regenerates on every change.
  • Add it to your pnpm dev alongside jorvel dev via concurrently or npm-run-all.

Hydration mismatch on SSR

The server rendered a different tree than the client. Most common causes:

  • Date.now(), Math.random(), locale-dependent number/date formatting.
  • Reading window / document in a shared component.
  • Persistent state (localStorage, cookies) consulted on the client but not the server.
  • Third-party widgets that mutate the DOM before hydration (chat widgets, A/B testing snippets).
tsx
// Guard browser-only reads
const isClient = typeof window !== 'undefined';
const theme = isClient ? localStorage.getItem('theme') : 'light';

// Or defer to useEffect so SSR and first paint match
const [theme, setTheme] = React.useState<'light' | 'dark'>('light');
React.useEffect(() => {
  setTheme((localStorage.getItem('theme') as 'light' | 'dark') ?? 'light');
}, []);

CSP blocks the hydration script

Pass the same nonce to the CSP header and the hydration tag. A mismatch (or no nonce in either place) and the browser drops the script silently.

ts
import { buildCsp, generateNonce } from '@jorvel/security';
import { serializeState } from '@jorvel/ssr';

const nonce = generateNonce();
response.setHeader('Content-Security-Policy', buildCsp({ nonce, strictDynamic: true }));
html = html.replace('</head>', serializeState(state, { nonce }) + '</head>');

Rspack 1.x type-error on lazyCompilation

Put lazyCompilation: false at the top of rspack.config.mjs, not inside experiments. The shape moved in 1.7.7.

rspack.config.mjs
js
export default {
  lazyCompilation: false,    //  ← top level
  experiments: {
    // lazyCompilation: false  ← do NOT put it here
  },
  // ...
};

Router fires twice in React StrictMode

StrictMode double-invokes effects in dev. Calling createRouter() inside a useEffectcreates two routers, two history subscriptions, and you'll see duplicated jorvel:navigate handling.

Fix: call getRouter() at module scope in bootstrap.tsx. It returns a singleton — the second invocation is a no-op.

Windows: pnpm install hangs / EPERM

  • Make sure Windows Defender / corporate antivirus is not scanning node_modules in real time. Add a workspace-wide exclusion.
  • If symlinks fail, run PowerShell as Administrator once, or enable Developer Mode (Settings → Privacy & security → For developers).
  • As a last resort: pnpm install --shamefully-hoistfor a flat layout that plays nicer with tools that don't follow pnpm symlinks.

Port already in use

powershell
# Windows — find and stop the holder
Get-NetTCPConnection -LocalPort 3000 | Select-Object -ExpandProperty OwningProcess | ForEach-Object { Stop-Process -Id $_ -Force }
bash
# macOS / Linux
lsof -ti:3000 | xargs kill -9

Or change the port in jorvel.app.json and re-run jorvel federation to update remote URLs in the host config.

Suspected memory leak in dev

HMR + Rspack + StrictMode together can hold onto event listeners if a remote forgets to clean up. Common culprits:

  • useEventBus subscribers without a returned off() in the cleanup phase.
  • useNavigationEvents handlers that capture state via closure but never unmount.
  • Service Workers caching stale remoteEntry.js across reloads — unregister the SW while iterating on a remote.

Still stuck?

Run jorvel diagnose for a full environment report, and set JORVEL_DEBUG=1 to surface stack traces. Open an issue at github.com/Ravikisha/JorvelJS/issues with the diagnose output attached.