1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

単一サーバーからfrontend, backendで分けたら疎通できなくなってしもうた話💀

1
Posted at

どぅも、こんちくわー

タイトルにあるように、HonoでSSR(Server Side Rendering)を配信していたのですが、

ReactとHonoで分けたほうがイマっぽくね〜🕶

と思って分けたら、結構しっかりハマったのでその反省文 ナレッジを記載したいと思います!

主にこれらが重要なパス指定なので、非常に大事になります

  • Caddy
  • Vite base
  • React Router basename
  • fetch先URL
  • deploy先

この流れで配信する想定です。

bun run build
↓
dist 生成
↓
Caddy が静的配信

ハマりポイント1

Vite/Reactのローカル開発手法と、静的ファイル配信はパスが若干変わるので、そこがハマりましたね。

開発: vite dev server
本番: build した dist を静的配信

ハマりポイント2

Caddyfile の root パスが間違っていた。そのため、distフォルダの指定が誤っていたので、not foundになる。
Caddy が存在しないパスを見ていたので、当然配信できない。

解決
Caddyfile の root を実際のサーバーパスに合わせた。
しっかりとlsを使って確認しよう涙 あたりまえですがねぇ

ハマりポイント3

/home/ubuntu の権限で 403 になった

/home/user/hono-repoo/distを参照していたら、rootからは実行不可により、403 Forbidden(権限なし)となってしまっていた。

namei -l で確認したら下記の状態で、caddyユーザーの権限がなく、403 errorであった。

/home/user -> drwxr-x---

最終的にはリポジトリ直下をそのまま配信するのではなく、公開用ディレクトリへコピーする方針に寄せた。

/var/www/my-domain/react-app/frontend

ハマりポイント4

vite.config.ts の base が / で壊れていた
App.tsx はこうなっていた。

<BrowserRouter basename="/hono-note/frontend">

でも vite.config.ts はこうでした。

base: "/"

React Router の URL は /react-app/frontend 前提なのに、
JS/CSS の asset パスは /assets/... 前提で build される可能性がある。

解決
本番の base を /react-app/frontend/ に合わせた。

学び
basename と base は別物だけど、公開パスがあるなら両方の整合が必要。

React Router basename -> 画面ルーティング
Vite base            -> JS/CSS/画像の配信パス

ハマりポイント5

dist/index.html は正しいのに JS/CSS が 404 だった
状況

dist/index.html を見ると、読み込む JS/CSS は正しかった。

<script src="/hono-note/frontend/assets/index-....js">
<link href="/hono-note/frontend/assets/index-....css">

しかし、ブラウザではこれが 404 だった。

/hono-note/frontend/assets/index-....js
/hono-note/frontend/assets/index-....css

学び

HTML が返せていても、asset が返せていなければ画面は壊れる。
まず curl -I で asset を直接叩くのが大事。

ハマりポイント6

handle_path / try_files の理解不足で混乱した
状況

Caddy 側で handle_path と try_files を使っていた。

問題

try_files {path} /index.html は SPA 用には便利だが、
存在しない JS/CSS に対しても index.html を返してしまうと、ブラウザ側では

module script が欲しいのに HTML が来た

になってエラーになる。

実際にこうなった。

Failed to load module script

解決
curl -I で実体を確認し、
「JS/CSS に 200 が返っているか」「Content-Type が正しいか」を見た。

学び
SPA の fallback は強力だけど、
asset の 404 を隠してしまうので切り分けが難しくなる。
curl -I は必須。

ハマりポイント7

ファイル名の見間違いでも混乱した
状況

途中で確認した URL が実際の build 生成物とズレていた。

例:
index-DkDJhGV1.js が本物
なのに
index-Cim0XEfe.js を見ていた

あるいは逆に

.js と .css を取り違えて curl していた
問題
存在しないファイルを見て「設定がおかしい」と思い込みやすい。

解決
dist/index.html に書かれている実ファイル名をそのまま使って curl -I した。

学び
ハッシュ付き asset は毎回変わる。
必ず dist/index.html を source of truth にする。

ハマりポイント8

deploy が「build だけ」で、公開先反映が抜けていた
状況
最初の prd-deploy.sh はこれだけだった。

bun install
bun run build
sudo systemctl reload caddy

問題
build はされるが、Caddy が見ている公開ディレクトリに新しいファイルが反映されない。
その結果、

HTMLは新しい
assetsは古い

みたいなズレが起こる。

解決
dist を公開ディレクトリへ同期する工程が必要だと分かった。

rsync -av --delete dist/ /var/www/my-domain/react-app/frontend/
学び
本番 deploy は build だけでは終わらない。

解決方法まとめ

  1. BrowserRouter basename と Vite base は揃える。
  2. 本番の Vite は dist を配信する。5173 は開発用。
  3. Caddy が見るディレクトリと deploy 先は一致させる。
  4. /home/... 配下を直接配信すると権限でハマりやすい。
  5. curl -I で asset を直接確認すると、かなり早く切り分けできる。
  6. dist/index.html に書かれた実ファイル名を信じる。
  7. rsync --delete は hashed asset 配信でかなり重要。

最終的に理解すべき構成

これが今回の正解です。

React/Vite source
↓
bun run build
↓
dist
↓
rsync で公開ディレクトリへ反映
↓
Caddy が静的配信

API 側は別。

Browser
↓
Caddy
↓
/hono-note/backend/* -> Hono
/hono-note/frontend/* -> 静的ファイル

まとめ

個人開発をしているといろんな学びがありますねぇ〜
なるべく、本番とローカルで環境に差異がないように努めるのも大事ですね!

お茶目ミスも多かったですが、これが同時にハマるとまじで見えないんですよね。。

このようなミスがないと経験値がアップしないので、やってみてよかったです!

では!

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?