RemixからReact Router v7に移行する方法をまとめました|東京のWEB制作会社・ホームページ制作会社|株式会社GIG

RemixからReact Router v7に移行する方法をまとめました

2024-11-29 制作・開発

こんにちは!GIGのサービス開発事業部でアプリケーションエンジニアとして働くちいかた(片田)です!

私が開発に関わっている専門知識なしで使えるCMS『LeadGrid』では、フロントエンドにReactを採用しており、ルーティングはReact Routerというルーティングライブラリを採用しています。

React Routerは、v6までルーティングライブラリとして開発されていました。しかし、今回プレリリースされたv7からは、フルスタックフレームワークのRemixと統合され、React Router v7自体がフルスタックフレームワークとなりました!

今回の記事ではモダンフロントエンドが大好きな私ちいかたが、Remixで構築した個人アプリを実際にアップデートしながら、プレリリース版のReact Router v7について解説します!

React Router, Remixとは

React Routerの概要

React Routerは、Reactアプリケーションのためのルーティングライブラリ。フレームワークを使用せずにReactでSingle Page Applicationを開発する際には、必ずと言っていいほど必要になるライブラリです。

React Router 公式ドキュメント

Remix概要

Remixとは、React Routerをベースにしたフルスタックフレームワークです。React Routerは単なるルーティングライブラリですが、RemixはReact Routerにサーバーサイドの機能を実装することで、Reactを使ったWEB開発をより開発しやすくしてくれます。

Remix 公式ドキュメント

名称は異なりますが、React RouterもRemixも同じチームがメンテナンスしており、Remixも90%がReact Routerであると公式ドキュメントで公言しています。

そんな背景もあり、先日RemixとReact Routerを統合したReact Router v7という新しいバージョンが発表されました。

React Router v7の変更点

React Router v6から何が変わったかと言われれば、すべててが変わったと言わざるを得ません。ここでは、そのなかでも大きな変化について、Remix v2とも比較して2点紹介します。

ルーティング

React Router v7 - Routing

Remixではflag routesが採用されていたため、appディレクトリ配下に「.(ドット)」区切りで命名したファイルを配置することでルーティングが構成されていました。

React Router v7ではコンフィグベースなルーティングとなり、公式サイトでも下記のようなサンプルが紹介されてます。

import {
    type RouteConfig,
    route,
    index,
    layout,
    prefix,
} from "@react-router/dev/routes";

export const routes: RouteConfig = [
    index("./home.tsx"),
    route("about", "./about.tsx"),

    layout("./auth/layout.tsx", [
        route("login", "./auth/login.tsx"),
        route("register", "./auth/register.tsx"),
    ]),

    ...prefix("concerts", [
        index("./concerts/home.tsx"),
        route(":city", "./concerts/city.tsx"),
        route("trending", "./concerts/trending.tsx"),
    ]),
];


layout, index, route, prefix関数をそれぞれ使い、ルーティングの設定を定義します。

また、Remixのようなファイルベースルーティングも別ライブラリをインストールすることで実現できるので、扱い慣れたルーティングを選択することも可能です。

React Router v7 - File Route Conventions

loader関数の型定義

Remixでloader関数を定義する際、最もネックになっていたのが型定義でした。

たとえば下記のようなページがあった場合、クライアントでloader関数の結果を受け取る際に型エラーが発生してしまいました。

import type { LoaderFunction } from '@remix-run/cloudflare'
import {
  type ClientLoaderFunction,
  json,
  useLoaderData,
} from '@remix-run/react'

// 遅延を発生させるユーティリティ関数
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))

export const loader: LoaderFunction = async () => {
  // 5秒の遅延をシミュレーション
  await delay(5000)
  return json({
    'message': 'ok'
  })
}

export default function Index() {
  // Property 'message' does not exist on type 'unknown'.
  const { message } = useLoaderData<typeof clientLoader>()

  return (
    ...
  )
}


これを回避するためには、typedjsonという外部のパッケージを利用する必要がありました。Web標準の考え方が好きでRemixを使っているのに、外部パッケージを多用するのもちょっと……とモヤモヤする気持ちを感じていた人も多いのではないでしょうか

React Router v7では、 react-router typegen というコマンドを実行することで各パスに紐づいているRouteコンポーネントの型が自動生成されます。

これにより、useLoaderDataで受け取れるデータの型がunknownにならず、型の恩恵を受けられるようになります。

パスパラメータやクエリパラメータの型定義も可能のようで、さらに型安全なアプリケーションを実装しやすくなりました。

Remix v2系からReact Router v7に移行する方法

それでは実際にRemix v2からReact Router v7に移行していきましょう!

React Router v7の公式ドキュメントに手順を記載してくれているので、この手順に沿って移行していきます。

Upgrading from Remix
※React Router v7は2024年11月現在プレリリース版なので、正式リリースの前にアップデートされる際は十分に注意をしてください。

1. すべてのfeatureフラグを有効化します

最新のRemixで用意されているfeatureフラグの機能をすべてオンにしました。

出来あがったvite.config.tsがこちらです。

import adapter from '@hono/vite-dev-server/cloudflare'
import {
  vitePlugin as remix,
  cloudflareDevProxyVitePlugin as remixCloudflareDevProxy,
} from '@remix-run/dev'
import serverAdapter from 'hono-remix-adapter/vite'
import { defineConfig } from 'vite'
import tsconfigPaths from 'vite-tsconfig-paths'

import { getLoadContext } from './load-context'

export default defineConfig({
  plugins: [
    remixCloudflareDevProxy({ getLoadContext }),
    remix({
      future: {
        v3_fetcherPersist: true, // 以下5つのfeatureフラグをオンにしました
        v3_relativeSplatPath: true,
        v3_throwAbortReason: true,
        v3_singleFetch: true,
        v3_lazyRouteDiscovery: true
      },
    }),
    serverAdapter({
      adapter,
      entry: 'server/index.ts',
    }),
    tsconfigPaths(),
  ],
})


2. 依存するパッケージの更新

いままで「@remix-run/*」系のパッケージを使用していましたが、これらを「react-router」、「@react-router/*」系のパッケージに置き換えていきます。

具体的にどのパッケージに置き換えたら良いかは公式ドキュメントに記載されているためそちらをご確認ください。

じつはpreバージョンのパッケージを入れるのは初めての経験だったのでちょっとドキドキしました……!

pnpm add react-router@pre


パッケージを最新化したら、各コンポーネントから呼び出しているモジュールも今回アップデートしたReact Routerのものに変更してください。

3. package.jsonのscriptを変更

アプリケーションの起動やビルドなどを行うスクリプトもReact Router v7用に書き換えましょう。

私の場合、package.jsonのscript部分は下記のようになりました。

"scripts": {
  "build": "react-router build",
  "deploy": "pnpm run build && wrangler pages deploy",
  "dev": "react-router dev",
  "lint": "eslint --ignore-path .gitignore --cache --cache-location ./node_modules/.cache/eslint .",
  "start": "wrangler pages dev build/client",
  "typegen": "wrangler types",
  "typecheck": "tsc",
  "prepare": "husky"
},


4. vite.config.tsのplugin名を変更

vite.config.tsをさらに変更します。

先ほど追加したfeatureフラグを削除し、remixプラグインを呼び出していたところをreactRouterプラグインに変更しました。

import { reactRouter } from "@react-router/dev/vite";
import serverAdapter from 'hono-remix-adapter/vite'
import { defineConfig } from 'vite'
import tsconfigPaths from 'vite-tsconfig-paths'

import { getLoadContext } from './load-context'

export default defineConfig({
  plugins: [
    remixCloudflareDevProxy({ getLoadContext }),
    reactRouter(),
    serverAdapter({
      adapter,
      entry: 'server/index.ts',
    }),
    tsconfigPaths(),
  ],
})
5. route.tsファイルを追加


5. route.tsファイルを追加

従来のReact Routerのようなルーティングに変更したい方はここでroute.tsファイルを追加し、コンフィグベースのルーティングに変更することができます。

私は従来のRemixのファイルベースルーティングがいいので、上述した通り@react-router/fs-routesパッケージをインストールしてファイルベースルーティングのまま使います。

6. entryファイルでインポートしているコンポーネントを変更する

entry.server.tsx, entry.client.tsxで使っている下記のコンポーネントをReact Router用に置き換えます。

entry.server.tsx

import { ServerRouter } from "react-router";
import { isbot } from 'isbot'
import { renderToReadableStream } from 'react-dom/server'

export default async function handleRequest(
  request: Request,
  responseStatusCode: number,
  responseHeaders: Headers,
  remixContext: EntryContext,
  // This is ignored so we can keep it in the template for visibility.  Feel
  // free to delete this parameter in your app if you're not using it!
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  loadContext: AppLoadContext,
) {
  const body = await renderToReadableStream(
    <ServerRouter context={remixContext} url={request.url} />,
...


entry.client.tsx

 /**
 * By default, Remix will handle hydrating your app on the client for you.
 * You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
 * For more information, see https://remix.run/file-conventions/entry.client
 */
import { HydratedRouter } from "react-router/dom";
import { StrictMode, startTransition } from 'react'
import { hydrateRoot } from 'react-dom/client'


startTransition(() => {
  hydrateRoot(
    document,
    <StrictMode>
      <HydratedRouter />
    </StrictMode>,
  )
})


これで無事に移行作業が完了しました!

おわりに

RemixからReact Router v7への移行はほとんどつまづくことなくスムーズに完了しました。

アップデートのたびに思うことですが、React RouterやRemixはアップデートのしやすさがよく考えられているなと感じます。

モダンフロントエンドはとくに技術の変化が早いため、常にアップデートに追従する必要がありますが、こういったReact RouterやRemixのような技術を使うことで、アップデートしやすく、最新の技術を使ってハイパフォーマンスなWebサイトを構築しやすくなります。

フロントエンドのアップデートに苦手意識がある人でも、React RouterやRemixなら良いDXで開発・アップデートを実施できるのでぜひ使ってみてください。

株式会社GIGは、ナショナルクライアントからスタートアップまで、Webコンサルティング、UI/UXデザイン、システム開発など、DX支援をおこなうデジタルコンサルティング企業です。また、50,000人以上が登録するフリーランス・副業向けマッチングサービス『Workship』や、7,000人以上が登録するデザイナー特化エージェントサービス『クロスデザイナー』、リード獲得に必要な機能を備えたCMS『LeadGrid』、UXコンサルティングサービス『UX Design Lab』などを展開しています。

WebやDX支援のご相談はいつでもご連絡ください。

Web制作/Webマーケティングに関するご相談・ご依頼はこちら
会社紹介資料のダウンロードはこちら

また、株式会社GIGでは一緒に働くメンバーも募集中です!技術が好きなエンジニアも多く、モダンな技術に関しても常に情報交換しながら切磋琢磨しています。挑戦したいことにはどんどん挑戦できる環境なので、LeadGridの開発に少しでもご興味を持っていただいた方は、ぜひカジュアル面談でお話しましょう。

採用応募はこちら(GIG採用サイト)
採用応募はこちら(Wantedly)

片田 凌太

1997年10月生まれ。自動車のコネクティッドサービス開発や日本最大のコーヒーサブスクリプションサービス開発などの経験を経て2023年10月に株式会社GIGに入社。現在は、Webサイト制作からコンテンツSEO、問い合わせ管理、LP制作などWebマーケティングに必要な機能をもったCMS『LeadGrid』の開発チームに所属。