iris icon indicating copy to clipboard operation
iris copied to clipboard

[FEATURE REQUEST]Does iris support 'embed' package in Go 1.16 release?

Open yuanzicheng opened this issue 4 years ago • 7 comments

The currently released new version 1.16 of Go provide package embed, so we can embed files like *.html and others into the compiled binary executable file.

I want to know how iris works with embed package when serving static files.

yuanzicheng avatar Feb 19 '21 19:02 yuanzicheng

I find out a solution to serve static files with 'embed' package, what we need to do is coverting embed.FS to http.FileSystem. Note that we need to strip off the directory prefix from the embed.FS with fs.Sub so that it matches what is produced by the os.DirFS.

Reference: how-to-use-go-embed

The below are the code: embed build folder (a react.js single page application) to embed.FS

//go:embed build
var build embed.FS

GetFileSystem function in tools package to convert embed.FS to http.FileSystem

package tools

import (
	"io/fs"
	"log"
	"net/http"
	"os"
)

// GetFileSystem ..
func GetFileSystem(useOS bool, dir string, fsys fs.FS) http.FileSystem {
	if useOS {
		log.Print("using live mode")
		return http.FS(os.DirFS(dir))
	}

	log.Print("using embed mode")
	fsys, err := fs.Sub(fsys, dir)
	if err != nil {
		panic(err)
	}

	return http.FS(fsys)
}

serving static files in iris

app.HandleDir("/", tools.GetFileSystem(false, "build", build), iris.DirOptions{
	IndexName: "index.html",
	ShowList:  false,
	SPA:       true,
})

But i have no idea how to use Localization feature with 'embed' package in Go 1.16, without using go-bindata, except for your reply!

yuanzicheng avatar Feb 21 '21 07:02 yuanzicheng

This is my way, looking forward to a better way.

//go:embed web var embedWeb embed.FS

type webFS struct { FS embed.FS }

func (e *webFS) Asset(name string) ([]byte, error) { return e.FS.ReadFile(name) }

func (e *webFS) AssetInfo(name string) (fs.FileInfo, error) { file, err := e.FS.Open(name) if err != nil { return nil, err } return file.Stat() }

// file list manually func (e *webFS) AssetNames() []string { names := []string{ "web/index.html", "web/public/js/app.js", "web/public/css/app.css", } return names }


server := iris.New()

myWebFS := &webFS{FS: embedWeb}

server.HandleDir("/", "./web", iris.DirOptions{ Asset: myWebFS.Asset, AssetInfo: myWebFS.AssetInfo, AssetNames: myWebFS.AssetNames, })

bladewhite avatar Mar 25 '21 08:03 bladewhite

Try my way.

first update your iris to master latest. go get github.com/kataras/iris/v12@master

then

        //go:embed dist/*
        var embedWeb embed.FS

	fsys, _ := fs.Sub(embedWeb, "dist")
	app.RegisterView(iris.HTML(http.FS(fsys), ".html"))
	app.HandleDir("/", http.FS(fsys))

That works for me.

Sloaix avatar May 18 '21 22:05 Sloaix

better way:

        //go:embed dist/*
        var embedWeb embed.FS

	fsys := iris.PrefixDir("dist", http.FS(embedWeb))
	app.RegisterView(iris.HTML(fsys, ".html"))
	app.HandleDir("/", fsys)

Sloaix avatar May 19 '21 03:05 Sloaix

@Sloaix your code is really much more concise and clean than mine! and i will have a check if it works correctly.
About the further question, do u know how can the Localization feature of Iris works with the 'embed' package in Go 1.16 release?

yuanzicheng avatar May 19 '21 12:05 yuanzicheng

here is my solution, works fine for me.

		{
			app.OnErrorCode(http.StatusNotFound, func(c *irisContext.Context) {
				req := c.Request()
				req.URL.Path = "/frontend/dist" + req.URL.Path
				println(req.URL.Path)
				fs := http.FileServer(http.FS(EmbedWeb))
				fs.ServeHTTP(c.ResponseWriter(), req)
			})
		}

axetroy avatar May 24 '21 08:05 axetroy

@axetroy thanks! It works fine.

huyinghuan avatar Jul 12 '21 02:07 huyinghuan

Hello @yuanzicheng, @Sloaix , @bladewhite, @huyinghuan , @yuanzicheng, @axetroy

This is directly supported to view engines (e.g. app.RegisterView(iris.HTML(..))) and File Server (app.HandleDir).

Please update:

go get github.com/kataras/iris/v12@master
go mod tidy

kataras avatar Sep 21 '22 20:09 kataras