フルスタックアプリを1つの実行ファイルで!PocketBase に Vite を埋め込む方法
PocketBase は、実行ファイル1つで動作する BaaS です。PocketBase の実行ファイルをそのままバックエンドとして利用するだけでも十分便利ですが、Go で拡張することで、さらに多くの機能を追加できます。
今回はその例として、Vite で作成したフロントエンドを go:embed
を用いて PocketBase の実行ファイルに埋め込み、フロントエンドとバックエンドを1つの実行ファイルに統合する方法を紹介します。
PocketBase 自体については、こちらの記事で説明しています。
サンプルコード
GitHub にコードを公開しています。
ディレクトリ構成
ディレクトリの構造は以下のようになっています。Go のプロジェクト内に /site
ディレクトリがあり、その中に Vite(React)のプロジェクトが含まれています。
.
├── Makefile
├── go.mod
├── go.sum
├── main.go
├── pb_data
└── site
├── README.md
├── bun.lock
├── embed.go <-- `go:embed`
├── eslint.config.js
├── index.html
├── package.json
├── public
│ └── vite.svg
├── src
│ ├── App.css
│ ├── App.tsx
│ ├── assets
│ ├── index.css
│ ├── main.tsx
│ └── vite-env.d.ts
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts
embed.go
の実装
embed.go
には、フロントエンドを埋め込むための設定が記述されています。
package site
import (
"embed"
"io/fs"
)
//go:embed all:dist
var distDir embed.FS
// DistDirFS は、埋め込まれた `dist` ディレクトリのファイル群を指す
var DistDirFS, _ = fs.Sub(distDir, "dist")
ここで指定している dist
ディレクトリは、フロントエンドのビルド後に生成される静的ファイルを格納する場所です。これにより、フロントエンドのファイルを実行ファイル内に埋め込むことができます。
main.go
での活用
埋め込まれた静的ファイルは main.go
で以下のように使用されます。
func main() {
// 開発環境かどうかを判定
isGoRun := strings.HasPrefix(os.Args[0], os.TempDir())
app := pocketbase.New()
app.OnServe().BindFunc(func(se *core.ServeEvent) error {
switch isGoRun {
case true:
// 開発環境では Vite の開発サーバーへ転送
proxy := httputil.NewSingleHostReverseProxy(&url.URL{
Scheme: "http",
Host: "localhost:5173",
})
se.Router.GET("/", func(e *core.RequestEvent) error {
proxy.ServeHTTP(e.Response, e.Request)
return nil
})
default:
// 本番環境では埋め込まれた静的ファイルを提供
se.Router.GET("/{path...}", apis.Static(site.DistDirFS, true))
}
return se.Next()
})
if err := app.Start(); err != nil {
log.Fatal(err)
}
}
PocketBase では、/api
以下のパスはバックエンド API 用、/_
以下のパスは管理画面用に予約されています。上記のコードでは、それ以外のパスをすべて静的ファイルへルーティングするよう設定しています。
また、apis.Static(site.DistDirFS, true)
の第2引数を true
にすることで Index Fallback を有効化しています。これにより、対応する静的ファイルが存在しないパスへのリクエストが index.html
にフォールバックされるため、SPA のルーティングが適切に機能します。
実行ファイルのビルド
以下のコマンドを実行すると、フロントエンドとバックエンドが統合された実行ファイルが作成されます。GitHub のコードでは Makefile
に記載されています。
cd site && bun install && bun run build
cd .. && go build
開発環境でのフロントエンド更新
本番環境ではフロントエンドを実行ファイルに埋め込む形を取りますが、開発環境ではフロントエンドを変更するたびに再ビルドするのは手間がかかります。
そのため、開発環境では httputil.NewSingleHostReverseProxy
を用いて、リクエストを Vite の開発サーバー (localhost:5173
) へ転送する仕組みを導入しています。これにより、Vite のホットリロードを活用できます。
開発時の実行方法は以下のとおりです。
cd site && bun dev
別のターミナルで:
go run . serve
まとめ
この方法を使うことで、PocketBase のシンプルなバックエンド機能と、Vite を用いたモダンなフロントエンドを1つの実行ファイルに統合できます。開発環境では Vite のホットリロードを活用し、本番環境では静的ファイルを埋め込むことでシンプルなデプロイが可能になります。
Beszel
この記事は Beszel という PocketBase 製のサーバー監視ソフトウェアのリポジトリを参考にしました。シンプルで使いやすく,とても気に入っているソフトウェアのひとつです。
Discussion