如何在go embed中包含有下划线(_)的文件 + Gin SPA

tl;dr

使用 all标题来解决问题。

related issue: go@issue43854

//go:embed public
var fs embed.FS

过程

今天在尝试用go embed来提供前端文件的时候遇到了一个问题,有些文件就是加载不出来。

image-20240215190617849

我用了这个函数尝试获取所有文件,看看到底是哪里出了问题

func getAllFilenames(fs *embed.FS, dir string) (out []string, err error) {
	if len(dir) == 0 {
		dir = "."
	}

	entries, err := fs.ReadDir(dir)
	if err != nil {
		return nil, err
	}

	for _, entry := range entries {
		fp := path.Join(dir, entry.Name())
		if entry.IsDir() {
			res, err := getAllFilenames(fs, fp)
			if err != nil {
				return nil, err
			}

			out = append(out, res...)

			continue
		}

		out = append(out, fp)
	}

	return
}

from source

我得到了如下输出

[public/200.html public/404.html public/admin/credential/index.html public/admin/login/index.html public/admin/panel/index.html public/favicon.ico public/index.html public/search/answer/index.html public/search/article/index.html] <nil>

发现任何在_nuxt文件夹下的文件都不在里面。于是我猜测go embed默认不会包含开头为_的文件或者文件夹

经过搜索,果然发现了解决方案。

https://github.com/golang/go/issues/43854

使用all即可

//go:embed all:pattern

Gin Gingle Page Application

solution

type GinSPA struct {
	sgin.CommonApp
	fsEmbed fs.ReadFileFS
}

func NewGinSPA(fsEmbed *embed.FS, fsPrefix string) *GinSPA {
	fsys, err := fs.Sub(fsEmbed, fsPrefix)
	if err != nil {
		panic(err)
	}
	return &GinSPA{
		fsEmbed: fsys.(fs.ReadFileFS),
	}
}

func (g *GinSPA) Create(engine *gin.Engine, router gin.IRouter) error {
	engine.NoRoute(g.handleSpa)
	return nil
}


func (g *GinSPA) handleSpa(c *gin.Context) {
	path := c.Request.URL.Path
	if len(path) > 0 {
		path = path[1:]
	}
	if data, err := g.fsEmbed.ReadFile(path); err == nil {
		c.Data(200, mime.TypeByExtension(filepath.Ext(path)), data)
		return
	}
	if data, err := g.fsEmbed.ReadFile("index.html"); err != nil {
		c.String(404, "404 Not Found")
	} else {
		c.Data(200, mime.TypeByExtension(".html"), data)
	}
}