Remix からのアップグレード
React Router v7 では、以下の最小バージョンが必要です。
node@20react@18react-dom@18
React Router v7 は、v2 以降の Remix の次のメジャーバージョンです (詳細については、"React 19 への段階的なパス" ブログ記事 を参照してください)。
Remix v2 のすべての future フラグ を有効にしている場合、Remix v2 から React Router v7 へのアップグレードは、主に依存関係の更新になります。
ステップ 2~8 の大部分は、コミュニティメンバーの James Restall が作成した codemod を使用して自動的に更新できます。
1. future フラグを採用する
👉 future フラグを採用する
Remix v2 アプリケーションで既存のすべての future フラグ を採用します。
2. 依存関係を更新する
以前はランタイム固有のパッケージ (@remix-run/node、@remix-run/cloudflare など) を介して再エクスポートされていた「共有」API のほとんどは、v7 ではすべて react-router にまとめられました。そのため、@react-router/node や @react-router/cloudflare からインポートする代わりに、react-router から直接インポートすることになります。
-import { redirect } from "@remix-run/node";
+import { redirect } from "react-router";v7 でランタイム固有のパッケージからインポートする必要がある API は、Node の createFileSessionStorage や Cloudflare の createWorkersKVSessionStorage など、そのランタイムに固有の API のみです。
👉 codemod を実行する (自動)
次の codemod を使用して、パッケージとインポートを自動的に更新できます。この codemod は、すべてのパッケージとインポートを更新します。変更を元に戻す必要がある場合に備えて、codemod を実行する前に保留中の変更をコミットしてください。
npx codemod remix/2/react-router/upgrade👉 新しい依存関係をインストールする
codemod で依存関係が更新されたら、依存関係をインストールして Remix パッケージを削除し、新しい React Router パッケージを追加する必要があります。
npm install👉 依存関係を更新する (手動)
codemod を使用しない場合は、依存関係を手動で更新できます。
アルファベット順のパッケージ名変更の表を表示するには展開してください
| Remix v2 パッケージ | React Router v7 パッケージ | |
|---|---|---|
@remix-run/architect | ➡️ | @react-router/architect |
@remix-run/cloudflare | ➡️ | @react-router/cloudflare |
@remix-run/dev | ➡️ | @react-router/dev |
@remix-run/express | ➡️ | @react-router/express |
@remix-run/fs-routes | ➡️ | @react-router/fs-routes |
@remix-run/node | ➡️ | @react-router/node |
@remix-run/react | ➡️ | react-router |
@remix-run/route-config | ➡️ | @react-router/dev |
@remix-run/routes-option-adapter | ➡️ | @react-router/remix-routes-option-adapter |
@remix-run/serve | ➡️ | @react-router/serve |
@remix-run/server-runtime | ➡️ | react-router |
@remix-run/testing | ➡️ | react-router |
3. package.json の scripts を変更する
codemod を使用した場合は、自動的に完了しているため、このステップをスキップできます。
👉 package.json のスクリプトを更新する
| スクリプト | Remix v2 | React Router v7 | |
|---|---|---|---|
dev | remix vite:dev | ➡️ | react-router dev |
build | remix vite:build | ➡️ | react-router build |
start | remix-serve build/server/index.js | ➡️ | react-router-serve build/server/index.js |
typecheck | tsc | ➡️ | react-router typegen && tsc |
4. routes.ts ファイルを追加する
codemod と Remix v2 v3_routeConfig フラグを使用した場合は、自動的に完了しているため、このステップをスキップできます。
React Router v7 では、app/routes.ts ファイルを使用してルートを定義します。詳細については、ルーティングのドキュメント を参照してください。
👉 依存関係を更新する (Remix v2 v3_routeConfig フラグを使用している場合)
-import { type RouteConfig } from "@remix-run/route-config";
-import { flatRoutes } from "@remix-run/fs-routes";
-import { remixRoutesOptionAdapter } from "@remix-run/routes-option-adapter";
+import { type RouteConfig } from "@react-router/dev/routes";
+import { flatRoutes } from "@react-router/fs-routes";
+import { remixRoutesOptionAdapter } from "@react-router/remix-routes-option-adapter";
export default [
// ルートがどのように定義されているか
] satisfies RouteConfig;👉 routes.ts ファイルを追加する (Remix v2 v3_routeConfig フラグを 使用していない 場合)
touch app/routes.ts後方互換性のため、Remix v2 でのルート設定に合わせて routes.ts を導入するには、いくつかの方法があります。
-
「フラットルート」の ファイルベースの規約 を使用していた場合、新しい
@react-router/fs-routesパッケージを介して引き続きそれを使用できます。app/routes.ts import { type RouteConfig } from "@react-router/dev/routes"; import { flatRoutes } from "@react-router/fs-routes"; export default flatRoutes() satisfies RouteConfig; -
@remix-run/v1-route-conventionパッケージを介して Remix v1 の「ネストされた」規約を使用していた場合も、@react-router/remix-routes-option-adapterと組み合わせて引き続きそれを使用できます。app/routes.ts import { type RouteConfig } from "@react-router/dev/routes"; import { remixRoutesOptionAdapter } from "@react-router/remix-routes-option-adapter"; import { createRoutesFromFolders } from "@remix-run/v1-route-convention"; export default remixRoutesOptionAdapter( createRoutesFromFolders, ) satisfies RouteConfig; -
routesオプションを使用して構成ベースのルートを定義していた場合、@react-router/remix-routes-option-adapterを介してその構成を保持できます。app/routes.ts import { type RouteConfig } from "@react-router/dev/routes"; import { remixRoutesOptionAdapter } from "@react-router/remix-routes-option-adapter"; export default remixRoutesOptionAdapter( (defineRoutes) => { return defineRoutes((route) => { route("/", "home/route.tsx", { index: true }); route("about", "about/route.tsx"); route("", "concerts/layout.tsx", () => { route("trending", "concerts/trending.tsx"); route(":city", "concerts/city.tsx"); }); }); }, ) satisfies RouteConfig;-
vite.config.tsのroutesオプションも必ず削除してください。vite.config.ts export default defineConfig({ plugins: [ remix({ ssr: true, - ignoredRouteFiles: ['**/*'], - routes(defineRoutes) { - return defineRoutes((route) => { - route("/somewhere/cool/*", "catchall.tsx"); - }); - }, }) tsconfigPaths(), ], });
-
5. React Router 構成を追加する
👉 react-router.config.ts をプロジェクトに追加する
以前は vite.config.ts の remix プラグインに渡されていた構成は、react-router.config.ts からエクスポートされるようになりました。
注: この時点で、ステップ 1 で追加した v3 future フラグを削除する必要があります。
touch react-router.config.tsexport default defineConfig({
plugins: [
- remix({
- ssr: true,
- future: {/* all the v3 flags */}
- }),
+ reactRouter(),
tsconfigPaths(),
],
});+import type { Config } from "@react-router/dev/config";
+export default {
+ ssr: true,
+} satisfies Config;6. React Router プラグインを vite.config に追加する
codemod を使用した場合は、自動的に完了しているため、このステップをスキップできます。
👉 reactRouter プラグインを vite.config に追加する
vite.config.ts を変更して、@react-router/dev/vite から新しい reactRouter プラグインをインポートして使用します。
-import { vitePlugin as remix } from "@remix-run/dev";
+import { reactRouter } from "@react-router/dev/vite";
import { defineConfig } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";
export default defineConfig({
plugins: [
- remix(),
+ reactRouter(),
tsconfigPaths(),
],
});7. 型安全性を有効にする
TypeScript を使用していない場合は、このステップをスキップできます。
React Router は、ルートモジュールの型をアプリのルートにある .react-router/ ディレクトリに自動的に生成します。このディレクトリは React Router によって完全に管理され、gitignore にする必要があります。新しい型安全機能 の詳細をご覧ください。
👉 .react-router/ を .gitignore に追加する
.react-router/👉 tsconfig.json を更新する
tsconfig.json の types フィールドを更新して、以下を含めます。
includeフィールドの.react-router/types/**/*パスtypesフィールドの適切な@react-router/*パッケージ- 相対インポートを簡略化するための
rootDirs
{
"include": [
/* ... */
+ ".react-router/types/**/*"
],
"compilerOptions": {
- "types": ["@remix-run/node", "vite/client"],
+ "types": ["@react-router/node", "vite/client"],
/* ... */
+ "rootDirs": [".", "./.react-router/types"]
}
}8. エントリファイル内のコンポーネントの名前を変更する
codemod を使用した場合は、自動的に完了しているため、このステップをスキップできます。
アプリケーションに entry.server.tsx および/または entry.client.tsx ファイルがある場合は、これらのファイル内のメインコンポーネントを更新する必要があります。
-import { RemixServer } from "@remix-run/react";
+import { ServerRouter } from "react-router";
-<RemixServer context={remixContext} url={request.url} />,
+<ServerRouter context={remixContext} url={request.url} />,-import { RemixBrowser } from "@remix-run/react";
+import { HydratedRouter } from "react-router/dom";
hydrateRoot(
document,
<StrictMode>
- <RemixBrowser />
+ <HydratedRouter />
</StrictMode>,
);9. AppLoadContext の型を更新する
remix-serve を使用していた場合は、このステップをスキップできます。これは、Remix v2 でカスタムサーバーを使用していた場合にのみ適用されます。
React Router は React フレームワーク と スタンドアロンのルーティングライブラリの両方として使用できるため、LoaderFunctionArgs および ActionFunctionArgs の context 引数はオプションになり、デフォルトでは any として型付けされるようになりました。ロードコンテキストの型を登録して、ローダーとアクションの型安全性を確保できます。
👉 ロードコンテキストの型を登録する
新しい Route.LoaderArgs および Route.ActionArgs 型に移行する前に、移行を容易にするために、ロードコンテキスト型で LoaderFunctionArgs および ActionFunctionArgs を一時的に拡張できます。
declare module "react-router" {
// v2 で使用される AppLoadContext
interface AppLoadContext {
whatever: string;
}
// TODO: ローダーで `Route.LoaderArgs` に移行したら、これを削除します
interface LoaderFunctionArgs {
context: AppLoadContext;
}
// TODO: アクションで `Route.ActionArgs` に移行したら、これを削除します
interface ActionFunctionArgs {
context: AppLoadContext;
}
}
export {}; // これをモジュールとして扱うために TS に必要declare module を使用して型を登録することは、モジュール拡張 と呼ばれる標準的な TypeScript テクニックです。
これは、tsconfig.json の include フィールドでカバーされる任意の TypeScript ファイルで実行できますが、アプリディレクトリ内の専用の env.ts をお勧めします。
👉 新しい型を使用する
新しい型生成 を採用したら、LoaderFunctionArgs/ActionFunctionArgs の拡張を削除し、代わりに Route.LoaderArgs および Route.ActionArgs から context 引数を使用できます。
declare module "react-router" {
// v2 で使用される AppLoadContext
interface AppLoadContext {
whatever: string;
}
}
export {}; // これをモジュールとして扱うために TS に必要import type { Route } from "./+types/my-route";
export function loader({ context }: Route.LoaderArgs) {}
// { whatever: string } ^^^^^^^
export function action({ context }: Route.ActionArgs) {}
// { whatever: string } ^^^^^^^おめでとうございます! これで React Router v7 を使用できるようになりました。アプリケーションを実行して、すべてが期待どおりに動作していることを確認してください。