概要・できること
本記事では、React Routerを設定したReact フロントエンドページをビルドして、
Go言語のWebフレームワークGinでホスティングする流れを記載します。
この記事のような設定をすることで、
Goでサーバー起動した時に、React Routerで指定されたパスに対してアクセスされても、正常にルーティングされたページが表示されるようになります。
なお、Ginで定義したAPIエンドポイントも共存利用が可能です。
前提:プロジェクトディレクトリの構成
今回取り上げるプロジェクトの構成は下記のようになっています。
- プロジェクトルートにサーバーを起動するmain.goを配置
- フロントエンドReactアプリは
frontend配下に配置- ビルドしたものは
frontend/dist/に配置される
- ビルドしたものは
.
├── frontend
│ ├── dist // <-------(Reactのビルド済みファイル群)
│ │ ├── assets
│ │ │ ├── index-DRSpbdMT.css
│ │ │ └── index-IRtkWgFT.js
│ │ ├── index.html
│ ├── package.json
│ ├── src
│ ├── App.tsx
│ :
├── src // <-------(サーバー用ソースコード一式)
│ ├─
│ :
│
├── main.go // <------ サーバー起動用メインファイル
また、フロントエンドではReactRouterを使っており、App.tsxでルーティング設定を行なっています。
export default function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/auth/signup" element={<Signup />} />
<Route path="/auth/signin" element={<Signin />} />
<Route element={<AuthedRoutes />}>
<Route path="/" element={<PostNote />} />
<Route path="/post" element={<PostNote />} />
<Route path="/questions" element={<PostQuestions />} />
<Route path="/diaries" element={<Diaries />} />
<Route path="/auth/signout" element={<Signout />} />
</Route>
</Routes>
</BrowserRouter>
);
}
Goサーバーでのホスティング時の問題
Goサーバーで/にアクセスされた際だけ、frontend/dist/index.html等へアクセスするようなロジックを組むと、/auth/signinや/post等へブラウザのURL欄で直接入力した場合にうまくReact Routerが使えません。
これは、
- 先にGin側のパスの解釈・レスポンスがあり、
- Reactページが開いてからReactRouterでのパス解釈・対応コンポーネント表示
という流れのためです。
解決:Ginサーバーで登録済みのAPI以外は静的ファイルを返す
解決策は、あらかじめ登録したAPIのパス以外は静的ファイルを探して、それをレスポンスとするものです。
下記のようなGo設定例となります。
func main() {
//略
// 先にAPIエンドポイントを宣言
v1.GET("/api/diaries", diaryController.Get)
v1.POST("/api/diaries", diaryController.Post)
v1.DELETE("/api/diaries/:postId", diaryController.Delete)
// 略
// 後に静的ファイルへのルーティングの設定
r.NoRoute(func(c *gin.Context) {
_, file := path.Split(c.Request.RequestURI)
ext := filepath.Ext(file)
if file == "" || ext == "" {
c.File("./frontend/dist" + "/index.html")
} else {
c.File("./frontend/dist" + c.Request.RequestURI)
}
})
//略
}
アクセスされたくないファイルはdist配下へ入れないようにしましょう。
入れてしまうと、URLから当該ファイルへアクセス可能になってしまいます...。