Migration guides
Two starting points: a classic SPA (Create React App + react-router) you want to split into federated remotes, or an existing hand-rolled Module Federation setup you want JORVEL's conventions on top of. Both are incremental — JORVEL doesn't require a big-bang rewrite.
From Create React App + react-router
CRA is unmaintained and has no federation story. The migration is two phases: get the app building under JORVEL's Rspack pipeline, then carve out remotes.
1. Scaffold a workspace and move the app in
npx jorvel init my-workspace # host + one remote skeleton
cd my-workspace
# copy your CRA src/ into apps/shell/src, then:
pnpm install2. Swap react-router for the JORVEL router
The two-tier router is History-API based — no <BrowserRouter> needed. Map routes to the host table and use NestedRouter for in-app layouts.
// before (react-router v6)
<Routes>
<Route path="/dashboard/*" element={<Dashboard />} />
</Routes>
// after (JORVEL) — see /docs/routing and /docs/nested-routes
import { NestedRouter, type NestedRoute } from '@jorvel/runtime';
const routes: NestedRoute[] = [
{ path: '/dashboard', element: <DashboardShell />, children: [
{ index: true, lazy: () => import('./pages/overview.js'), loading: <Skeleton /> },
] },
];| react-router | JORVEL |
|---|---|
useNavigate() | useNavigate() (@jorvel/runtime) |
useParams() | useOutletParams() / useParams() |
useSearchParams() | useSearchParams() |
<Outlet /> | <Outlet /> |
<Link to> | <NavLink to label> |
loader / action | defineLoader (ssr) / defineAction |
3. Carve out the first remote
Pick a route subtree owned by another team. Move it to apps/<remote>, expose ./App, and wire it into the host:
jorvel add remote billing --port 3002
jorvel federation # regenerate jorvel.federation.json
jorvel federation diff --base main # confirm the host contract is intact
jorvel devFrom an existing Module Federation setup
If you already run Webpack/Rspack ModuleFederationPlugin by hand, JORVEL adds conventions, a typed contract layer, and tooling without forcing you to relinquish control.
- Translate each app's plugin config into a
jorvel.app.json(name,type: host | remote,port) and runjorvel federation— it emits thejorvel.federation.jsonJORVEL consumes. Diff it against your current plugin options to confirm parity. - Replace your bespoke remote loader with
loadRemoteEntry/loadRemoteModulefrom@jorvel/runtime— you get the origin allowlist, SRI enforcement, version-skew warnings, and last-good fallback for free. - Adopt
defineFederationContractfor the modules a host depends on, then gate PRs withjorvel federation diffso a remote can't silently drop an expose.
Codemods
@mfjs/* packages? jorvel migrate ships three codemods (mfjs-to-jorvel, builtins-define, routes-host-rename). Dry-run by default; --apply commits.Migrate incrementally
jorvel federation diff + contract tests, deploy, then repeat. A big-bang split loses you the ability to bisect a regression.