🚢

React Router Framework SPAをGithub Pagesで公開する

に公開

Github Pagesで公開したいが、動的ルーティングかつファイルベースルーティングを使いたいときのReact Routerの設定をまとめた。

コードは以下にある。

https://github.com/ofk/example-react-router-github-pages

React Routerを設定

npx create-react-routerで作られるテンプレートはファイルベースルーティングではない。ドキュメント通り、@react-router/fs-routesを入れ、app/routes.tsを設定する。

https://reactrouter.com/how-to/file-route-conventions

SPAモードも有効ではないので、ドキュメント通り、react-router.config.tsssrフラグを反転させる。

https://reactrouter.com/how-to/spa

出力パスを設定

Github Pagesはユーザーページでなければ、https://<user>.github.io/<repo>/のようにディレクトリ名付きのURLで公開される。よって、scriptタグの参照や内部リンクは公開先のパスにしなければならない。

scriptタグの参照はvite.config.tsbase: '/<repo>/'と、内部リンクはreact-router.config.tsbasename: '/<repo>/'を設定する必要がある。ただし、そのまま設定するとローカル開発環境は壊れてしまう。よって、本番と開発で設定を振り分ける必要がある。以下のように設定する。

vite.config.ts
 import { defineConfig } from 'vite';
 import tsconfigPaths from 'vite-tsconfig-paths';

-export default defineConfig({
+export default defineConfig(({ mode }) => ({
+  base: mode === 'production' ? '/<repo>/' : undefined,
   plugins: [tailwindcss(), reactRouter(), tsconfigPaths()],
-});
+}));
react-router.config.ts
 import type { Config } from '@react-router/dev/config';

 export default {
+  basename: import.meta.env.PROD ? '/<repo>/' : '/',
   ssr: false,
 } satisfies Config;

https://github.com/ofk/example-react-router-github-pages/commit/a1b99e250b944c6bf52539bebae6d4ba981840a2

index.html以外へのアクセスを設定

Github Pagesにはカスタム404ページがある。この機能を使えばindex.html以外のアクセスが捌ける。そのため、ルート以外は404 Not FoundのHTTPステータスとなる。コンテンツが存在するのに404となるが、一方でSPAをGithub Pagesに置く判断をしている時点でSEOは考慮しない判断はしているはずなので問題は大きくないと考えている。

やることはindex.html404.htmlにコピーするだけ。npm scriptsのpostbuildにcp build/client/{index,404}.htmlと書いても動くと思うが、react-routerの設定に良いタイミングがあるのでそこに差し込む。

react-router.config.ts
 import type { Config } from '@react-router/dev/config';

+import { copyFile } from 'node:fs/promises';
+import path from 'node:path';

 export default {
   basename: import.meta.env.PROD ? '/<repo>/' : '/',
+  async buildEnd(args): Promise<void> {
+    if (!args.viteConfig.isProduction) return;
+    const buildPath = args.viteConfig.build.outDir;
+    await copyFile(path.join(buildPath, 'index.html'), path.join(buildPath, '404.html'));
+  },
   ssr: false,
 } satisfies Config;

https://github.com/ofk/example-react-router-github-pages/commit/fac8dbe070d533de542ca98fb1e6976770a6793c

Github Pagesの設定

GithubリポジトリのSettings内のPages、Build and deploymentのSourceをGitHub Actionsに変更し、コミットに示すワークフローを動かせばGithub Pagesにデプロイできる(pushを先にした場合はワークフローが失敗しているのでActionsからRe-runする)。

https://github.com/ofk/example-react-router-github-pages/commit/31584d9e1f0e99798d21ed8d5fc8fc0d5478adbb

あとがき

React Routerのexamplesやdiscussionsではこのやり方を見つけることができなかったので書いた。
Github Pagesのカスタム404ページの機能を知らなかったので、動的ルーティングを動かすにはHash routerが必須だと考えており、ワークアラウンドがあったことが自分の中では発見だった。

Discussion