package tpl import ( "html/template" "io/fs" "os" "path/filepath" "sync" ) // Options for the template type Options struct { BaseDir string BasePath string DynamicReload bool FuncMap template.FuncMap Fsys fs.FS } var cache = make(map[string]template.Template) var cacheMutex = new(sync.RWMutex) // Load new template func Load(opts *Options) (*template.Template, error) { if !opts.DynamicReload { if tpl, ok := getCache(opts.BasePath); ok { return &tpl, nil } } tpl, err := readFiles(opts.BasePath, opts) if err != nil { return nil, err } if !opts.DynamicReload { setCache(opts.BasePath, *tpl) } return tpl, nil } func readFiles(basePath string, opts *Options) (*template.Template, error) { var ( tpl *template.Template err error files []string ) if !opts.DynamicReload { if err := fs.WalkDir(opts.Fsys, basePath, func(path string, d fs.DirEntry, err error) error { if !d.IsDir() { files = append(files, path) } return nil }); err != nil { return nil, err } tpl, err = template.New(opts.BaseDir). Funcs(FuncMap()). Funcs(opts.FuncMap). ParseFS(opts.Fsys, files...) if err != nil { return nil, err } } else { if err := filepath.Walk(basePath, func(path string, info os.FileInfo, err error) error { if !info.IsDir() { files = append(files, path) } return nil }); err != nil { return nil, err } tpl, err = template.New(opts.BaseDir). Funcs(FuncMap()). Funcs(opts.FuncMap). ParseFiles(files...) if err != nil { return nil, err } } return tpl, nil }