📎

「React コードを隠したまま GitHub Pages でサイトを公開する」の こぼれ話

2024/01/14に公開

はじめに

共著者として書かせていただいた元の記事は以下。
https://zenn.dev/utcarnivaldayo/articles/2024-01-07-deploy-github-pages

本記事ではそこに載せられなかった Tips という名の備忘録を残したい。
なので実際には GitHub Pages とは直接には関係がないものもある。

React Router が GitHub Pages 上でうまく動かない、と思ったら動いた

<BrowerRouter>が GitHub Pages 上でうまくいかない

React Router を導入して記述しようとすると<BrowserRouter>を用いた導入記事をよく見る。しかし GitHub Pages にデプロイすると十分に動かない。厳密にはサイト内のボタン等を使って移動すると問題ないが、例えば~.github.io/portfolio/aboutみたいな URL を直接入力するとうまく動作してくれない。これは GitHub Pages が{root}/about/index.htmlを読みにいこうとして、そのファイルが存在しないからである。React Router が動作するにはまず {root}/index.htmlを読み込まないといけない、つまり~.github.io/portfolio/に一度アクセスしてから出ないと React Router は動作しないのである。これでは自分のサイト内の/aboutのページリンクを貼ってもうまく共有できない。

ということで<HashRouter>を使え!

404のエラーハンドリングを利用して表示させたいページへリダイレクトさせるなど様々な方法があるが、一番手っ取り早いのは React Router にすでにある<HashRouter>を使うことである。<BrowserRouter>の部分を単に<HashRouter>に書き換えれば良い。この解決策が意外と日本語記事で明確に書かれているものが見つけられなかったので今回書くことにした。
これはURLフラグメントという機能を利用して"まるでパスのように見える" URL になって動作する。具体的には~.github.io/portfolio/#/aboutのような URL になる。#(ハッシュ) が挿入されていることがわかる。css を直接勉強したことがある人なら id セレクタといえばわかるだろう。雑にいえばページ内ジャンプの仕組みを利用してページ遷移させるのである。だから#以降はパスに見えるがパスではないのである。
したがって厳密には単一ページであり、~.github.io/portfolio/#/aboutのURLを共有したとしても GitHub Pages は#以前の~.github.io/portfolio/を参照し、{root}/index.htmlを読み込み、 React Router が起動し#以降の部分をパスとして解析してくれるのでそのページを表示できるわけである。

ビルドされるassets/{hash}.jsのファイル名を毎回同じにしたい

Vite によってビルドされるファイルに毎回名前が変わる JavaScript ファイルがある。これを毎回同じ名前にするには以下のように設定する。

vite.config.ts
export default defineConfig({
  /* ... */
  build: {
    rollupOptions: {
      output: {
        entryFileNames: `assets/[name].js`,
        chunkFileNames: `assets/[name].js`,
        assetFileNames: `assets/[name].[ext]`
      }
    }
  },
})

https://funbrew.tech/2023/03/25/4011/

パスエイリアスが便利

これはどちらかというと備忘録。
以下のサイトを参考に設定すれば、importのパスで結構いい感じに開発できるようになる。
https://zenn.dev/fugithora812/articles/825a3374c10e61

tsconfig.json
{
  "compilerOptions": {
    /* ... */
    "baseUrl": ".",
    "paths": {
      "src/*": ["./src/*"],
      "@images/*": ["./src/public/images/*"],
    },
}
vite.config.ts
export default defineConfig({
  /* ... */
  resolve: {
    alias: [
      { find: 'src/', replacement: `/src/` },
      { find: '@images/', replacement: `/src/public/images/` },
    ],
  },
})
ぬまごたつ

Discussion