jet
jet copied to clipboard
Adding support for Go 1.16's FS interface
Go 1.16 introduces the fs package and a FS interface. Implementing a Jet loader for this seems like an ideal use case. Are there any plans for this, would it be easy?
EDIT: actually, maybe it is as simple as this?
type StdFileSystemLoader struct{ fs.FS }
func (l StdFileSystemLoader) Open(templatePath string) (io.ReadCloser, error) {
return l.FS.Open(templatePath)
}
func (l StdFileSystemLoader) Exists(templatePath string) bool {
_, err := l.Open(templatePath)
return err == nil && !os.IsNotExist(err)
}
Yes, that adapter should be all you need to use 1.16's FS interface! Let me know if it works, It probably makes sense to have this boilerplate directly in Jet.
I actually just found a way to do this without an extra type by using jets loaders/httpfs
package:
//go:embed *.html
var tfs embed.FS
// loader allows for loading templates
func loader() (jet.Loader, error) {
return httpfs.NewLoader(http.FS(tfs))
}
it is a bit weird to require a "httpfs/http" package for something that just have to deal with filesystems but it works as expected.
@advanderveer How did you pass this func loader to Jet Engine so it is loading files from tfs
?
I have someting like this: main.go:
//go:embed templates
var assets embed.FS //stored in: Repo.App.TemplatesFS
handlers.go:
var view = jet.NewSet(
jet.NewOSFileSystemLoader("./templates"),
jet.InDevelopmentMode(), // remove in production
)
func loader() (jet.Loader, error) {
return httpfs.NewLoader(http.FS(Repo.App.TemplatesFS))
}
but I have no idea how to link this together :-)
Hello again,
I've tried this way:
var view *jet.Set
func init() {
httpFsLoader, err := loader()
if err != nil {
log.Panicln("error: ", err)
}
view = jet.NewSet(
httpFsLoader,
jet.InDevelopmentMode(),
)
}
func loader() (jet.Loader, error) {
return httpfs.NewLoader(http.FS(Repo.App.TemplatesFS))
}
where Repo.App.TemplatesFS stores:
type ApplicationConfig struct {
InfoLog *log.Logger
ErrorLog *log.Logger
InDevelopment bool
Session *scs.SessionManager
TemplatesFS embed.FS
}
//go:embed templates
var assets embed.FS
var app config.ApplicationConfig
app.TemplatesFS = assets
But compiler does not like this part:
func loader() (jet.Loader, error) {
return httpfs.NewLoader(http.FS(Repo.App.TemplatesFS))
}
error: cannot use httpfs.NewLoader(http.FS(Repo.App.TemplatesFS)) (value of type jet.Loader) as jet.Loader value in return statement: wrong type for method Open (have func(templatePath string) (io.ReadCloser, error), want func(templatePath string) (io.ReadCloser, error))compilerInvalidIfaceAssign
but Repo.App.TemplatesFS is embed.FS so it is the same type as in example from @advanderveer
Ok I also found solution for my case:
func InitTemplateSystem(assets embed.FS) *jet.Set {
httpFsLoader, err := httpfs.NewLoader(http.FS(assets))
if err != nil {
log.Panicln("error: ", err)
}
return jet.NewSet(httpFsLoader, jet.InDevelopmentMode())
}
the error was caused by wrong import - VSCode is suggesting:
"github.com/CloudyKit/jet/v6"
"github.com/CloudyKit/jet/loaders/httpfs"
instead of:
"github.com/CloudyKit/jet/v6"
"github.com/CloudyKit/jet/v6/loaders/httpfs"
Now I am calling: app.View = handlers.InitTemplateSystem(web.WebFiles)
in my main.go file and initialize once Jet engine. Web files are loaded in "./web/web.go" module:
import "embed"
//go:embed templates
var WebFiles embed.FS
which is on the same level as templates
directory.
Maybe not the best solution (because of passing Jet engine to app config - which I do not like very much for now) but for the beginning I think it is ok. When I learn more then problably will change that to maybe something more sophisticated.