devlog

go:embed でファイルが見つからないとき all を付ける

2023-11-20

概要

  • Go には embed という機能があり、ビルドするときファイルを埋め込むことができます
  • embed は全てのファイルを埋め込んでくれる訳ではありません
  • デフォルトで ._ で始まるファイルを無視します
  • all をつけると全てのファイルを埋め込みます

経緯

Next.js の dist を go:embed で埋め込んだところ「一部のファイルが見つからない」という事象が見受けられました。具体的には次のようなコードです。

package main import ( "embed" "fmt" "strings" "github.com/gofiber/fiber/v2" ) //go:embed dist/* var Dist embed.FS func main() { app := fiber.New() app.Get("/*", func(c *fiber.Ctx) error { requestPath := c.Path() // like `/` path := fmt.Sprintf("dist%s", requestPath) // like `dist/` if strings.HasSuffix(path, "/") { path += "index.html" } f, err := admin.Dist.ReadFile(path) if err != nil { return err } // 省略: content-type 付与処理など return c.SendString(string(f)) }) app.Listen(":3000") }

Dist と言う変数に Next.js の dist を埋め込んでいます。 HTTPでアクセスがあると Dist からファイルを探し、それをそのまま返す処理を書いてます。

go run してウェブブラウザで確認したところ、なぜか一部のファイルが読み込まれない、という事象が起きました。

調査を進めると、、まず

  • Next.js は _ で始まるファイルを生成する。例: _buildManifest.js
  • _ で始まるファイルが見つからない
  • Dist にも見つからない

という事が分かりました。

原因

GitHubでIssueを探したところ、golang/go#43854 というIssueを見つけました。

確認したところ上記の挙動は go:embed の仕様のようです。
embedパッケージのドキュメントにも記載がありました。

If a pattern names a directory, all files in the subtree rooted at that directory are embedded (recursively), except that files with names beginning with ‘.’ or ‘_’ are excluded

._ で始まるファイルは除外される、とのことです。

対策

all を付けます

//go:embed all:dist/* var Dist embed.FS

これもドキュメントに記載がありました。

If a pattern begins with the prefix ‘all:’, then the rule for walking directories is changed to include those files beginning with ‘.’ or ‘_’.

終わりに

なかなか気付きにくい挙動だと思います。

が、例えば .git や .env を意図せず埋め込んでしまうのは避けたいので、多少合理的ではあるかなあ、と感じました。

  • 作成日
    2023-11-20
  • 更新日
    2023-11-20