React Router Framework SPAをGithub Pagesで公開する
Github Pagesで公開したいが、動的ルーティングかつファイルベースルーティングを使いたいときのReact Routerの設定をまとめた。
コードは以下にある。
React Routerを設定
npx create-react-router
で作られるテンプレートはファイルベースルーティングではない。ドキュメント通り、@react-router/fs-routes
を入れ、app/routes.ts
を設定する。
SPAモードも有効ではないので、ドキュメント通り、react-router.config.ts
のssr
フラグを反転させる。
出力パスを設定
Github Pagesはユーザーページでなければ、https://<user>.github.io/<repo>/
のようにディレクトリ名付きのURLで公開される。よって、scriptタグの参照や内部リンクは公開先のパスにしなければならない。
scriptタグの参照はvite.config.ts
でbase: '/<repo>/'
と、内部リンクはreact-router.config.ts
でbasename: '/<repo>/'
を設定する必要がある。ただし、そのまま設定するとローカル開発環境は壊れてしまう。よって、本番と開発で設定を振り分ける必要がある。以下のように設定する。
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()],
-});
+}));
import type { Config } from '@react-router/dev/config';
export default {
+ basename: import.meta.env.PROD ? '/<repo>/' : '/',
ssr: false,
} satisfies Config;
index.html以外へのアクセスを設定
Github Pagesにはカスタム404ページがある。この機能を使えばindex.html以外のアクセスが捌ける。そのため、ルート以外は404 Not FoundのHTTPステータスとなる。コンテンツが存在するのに404となるが、一方でSPAをGithub Pagesに置く判断をしている時点でSEOは考慮しない判断はしているはずなので問題は大きくないと考えている。
やることはindex.html
を404.html
にコピーするだけ。npm scriptsのpostbuildにcp build/client/{index,404}.html
と書いても動くと思うが、react-routerの設定に良いタイミングがあるのでそこに差し込む。
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;
Github Pagesの設定
GithubリポジトリのSettings内のPages、Build and deploymentのSourceをGitHub Actionsに変更し、コミットに示すワークフローを動かせばGithub Pagesにデプロイできる(pushを先にした場合はワークフローが失敗しているのでActionsからRe-runする)。
あとがき
React Routerのexamplesやdiscussionsではこのやり方を見つけることができなかったので書いた。
Github Pagesのカスタム404ページの機能を知らなかったので、動的ルーティングを動かすにはHash routerが必須だと考えており、ワークアラウンドがあったことが自分の中では発見だった。
Discussion