Remixからのアップグレード
このページについて

Remix からのアップグレード

React Router v7 は、Remix v2 の後のメジャーバージョンです(詳細は、"React 19への段階的な移行"ブログ投稿 を参照してください)。

すべてのRemix v2 の将来的なフラグを有効にしている場合、Remix v2 から React Router v7 へのアップグレードは、主に依存関係の更新を伴います。

手順 2~8 の大部分は、コミュニティメンバーのJames Restall が作成したcodemod を使用して自動的に更新できます。

1. 将来的なフラグを採用する

👉 将来的なフラグを採用する

Remix v2 アプリケーションですべての既存の将来的なフラグを採用します。

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 は、ノードの `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` フラグを使用している場合)

// app/routes.ts
-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 [
  // however your routes are defined
] satisfies RouteConfig;

👉 `routes.ts` ファイルを追加する(Remix v2 の `v3_routeConfig` フラグを使用していない場合)

touch app/routes.ts

下位互換性のため、そしてファイルベースの規約を好む人のために、新しい `@react-router/fs-routes` パッケージを介して、Remix v2 で使用しているのと同じ「フラットルート」規約を選択できます。

import { type RouteConfig } from "@react-router/dev/routes";
import { flatRoutes } from "@react-router/fs-routes";

export default flatRoutes() satisfies RouteConfig;

または、`routes` オプションを使用して設定ベースのルートを定義していた場合

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` オプションを使用していた場合は、削除してください。

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 の将来的なフラグを削除する必要があります。

touch react-router.config.ts
// vite.config.ts
export default defineConfig({
  plugins: [
-   remix({
-     ssr: true,
-     future: {/* all the v3 flags */}
-   }),
+   remix(),
    tsconfigPaths(),
  ],
});

// react-router.config.ts
+import type { Config } from "@react-router/dev/config";
+export default {
+  ssr: true,
+} satisfies Config;

6. `vite.config` に React Router プラグインを追加する

codemod を使用した場合は、自動的に完了しているため、この手順をスキップできます。

👉 `vite.config` に `reactRouter` プラグインを追加する

`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` に追加する必要があります。新しい型安全性の機能の詳細については、こちらを参照してください。

👉 `.gitignore` に `.react-router/` を追加する

.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" {
  // Your AppLoadContext used in v2
  interface AppLoadContext {
    whatever: string;
  }

  // TODO: remove this once we've migrated to `Route.LoaderArgs` instead for our loaders
  interface LoaderFunctionArgs {
    context: AppLoadContext;
  }

  // TODO: remove this once we've migrated to `Route.ActionArgs` instead for our actions
  interface ActionFunctionArgs {
    context: AppLoadContext;
  }
}

export {}; // necessary for TS to treat this as a module

`declare module` を使用して型を登録することは、モジュール拡張と呼ばれる標準的な TypeScript の手法です。これは、`tsconfig.json` の `include` フィールドで対象となる任意の TypeScript ファイルで行うことができますが、アプリディレクトリ内の専用の `env.ts` をお勧めします。

👉 **新しい型を使用する**

新しい型生成を採用したら、`LoaderFunctionArgs`/`ActionFunctionArgs` の拡張を削除し、代わりに`Route.LoaderArgs``Route.ActionArgs` から `context` 引数を使用できます。

declare module "react-router" {
  // Your AppLoadContext used in v2
  interface AppLoadContext {
    whatever: string;
  }
}

export {}; // necessary for TS to treat this as a module
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 への移行が完了しました。アプリケーションを実行して、すべてが期待通りに動作することを確認してください。

ドキュメントと例 CC 4.0