package views import ( "bytes" "embed" "fmt" "html/template" "io" "net/http" "path/filepath" "strings" ) var ( TemplateCache map[string]*template.Template ) func Init(viewFS embed.FS, viewMap map[string][]string, funcMap map[string]any) error { var err error TemplateCache, err = initTemplates(viewFS, viewMap, funcMap) if err != nil { return fmt.Errorf("failed to initialize templates: %v", err) } return nil } func initTemplates(viewFS embed.FS, viewMap map[string][]string, funcMap map[string]any) (map[string]*template.Template, error) { cache := make(map[string]*template.Template) tmplFuncMap := template.FuncMap(funcMap) for name, paths := range viewMap { if len(paths) == 0 { continue } rootName := strings.TrimSuffix(filepath.Base(paths[0]), filepath.Ext(paths[0])) tmpl := template.New(rootName).Funcs(tmplFuncMap) var combined []byte for _, path := range paths { content, err := viewFS.ReadFile(path) if err != nil { return nil, fmt.Errorf("reading %s: %w", path, err) } combined = append(combined, content...) combined = append(combined, '\n') } parsed, err := tmpl.Parse(string(combined)) if err != nil { return nil, fmt.Errorf("parsing template %s: %w", name, err) } cache[name] = parsed } return cache, nil } func RenderHTML(w http.ResponseWriter, name string, data any) error { tmpl, ok := TemplateCache[name] if !ok { http.Error(w, "template not found: "+name, http.StatusNotFound) return fmt.Errorf("template %q not found", name) } w.Header().Set("Content-Type", "text/html; charset=utf-8") var buf bytes.Buffer if err := tmpl.ExecuteTemplate(&buf, tmpl.Name(), data); err != nil { return fmt.Errorf("failed to execute template %q: %w", name, err) } _, err := io.Copy(w, &buf) return err }