package templating import ( "html/template" "io" "io/fs" "sync" ) type Engine struct { // NOTE: LayoutRegistry and TemplateRegistry have their own syncronization & cache and do not require a mutex here LayoutRegistry *LayoutRegistry TemplateRegistry *TemplateRegistry mu *sync.Mutex FuncMap template.FuncMap } func NewEngine(layouts, templates *fs.FS) *Engine { return &Engine{ mu: &sync.Mutex{}, LayoutRegistry: NewLayoutRegistry(*layouts), TemplateRegistry: NewTemplateRegistry(*templates), FuncMap: template.FuncMap{}, } } func (e *Engine) Load() error { wg := sync.WaitGroup{} wg.Add(2) go func() { defer wg.Done() e.LayoutRegistry.Load() }() go func() { defer wg.Done() e.TemplateRegistry.Load() }() wg.Wait() return nil } func (e *Engine) Render(out io.Writer, path string, data interface{}, layout ...string) error { // TODO: check if a reload is needed if files on disk have changed var l *template.Template if layout == nil || len(layout) == 0 { lay, err := e.LayoutRegistry.Default() if err != nil { return err } l = lay } else { lay, err := e.LayoutRegistry.Layout(layout[0]) if err != nil { return err } l = lay } lay, err := l.Clone() if err != nil { return err } err = e.TemplateRegistry.Add(path, lay) if err != nil { return err } err = lay.Execute(out, data) if err != nil { return err } return nil }