Reimplement and simplify Hugo's template system

See #13541 for details.

Fixes #13545
Fixes #13515
Closes #7964
Closes #13365
Closes #12988
Closes #4891
This commit is contained in:
Bjørn Erik Pedersen
2025-04-06 19:55:35 +02:00
parent 812ea0b325
commit 83cfdd78ca
138 changed files with 5342 additions and 4396 deletions

View File

@@ -494,17 +494,17 @@ func (s *Site) executeDeferredTemplates(de *deps.DeferredExecutions) error {
defer deferred.Mu.Unlock()
if !deferred.Executed {
tmpl := s.Deps.Tmpl()
templ, found := tmpl.Lookup(deferred.TemplateName)
if !found {
panic(fmt.Sprintf("template %q not found", deferred.TemplateName))
tmpl := s.Deps.GetTemplateStore()
ti := s.TemplateStore.LookupByPath(deferred.TemplatePath)
if ti == nil {
panic(fmt.Sprintf("template %q not found", deferred.TemplatePath))
}
if err := func() error {
buf := bufferpool.GetBuffer()
defer bufferpool.PutBuffer(buf)
err = tmpl.ExecuteWithContext(deferred.Ctx, templ, buf, deferred.Data)
err = tmpl.ExecuteWithContext(deferred.Ctx, ti, buf, deferred.Data)
if err != nil {
return err
}
@@ -577,9 +577,13 @@ func (h *HugoSites) printUnusedTemplatesOnce() error {
h.printUnusedTemplatesInit.Do(func() {
conf := h.Configs.Base
if conf.PrintUnusedTemplates {
unusedTemplates := h.Tmpl().(tpl.UnusedTemplatesProvider).UnusedTemplates()
unusedTemplates := h.GetTemplateStore().UnusedTemplates()
for _, unusedTemplate := range unusedTemplates {
h.Log.Warnf("Template %s is unused, source file %s", unusedTemplate.Name(), unusedTemplate.Filename())
if unusedTemplate.Fi != nil {
h.Log.Warnf("Template %s is unused, source %q", unusedTemplate.PathInfo.Path(), unusedTemplate.Fi.Meta().Filename)
} else {
h.Log.Warnf("Template %s is unused", unusedTemplate.PathInfo.Path())
}
}
}
})
@@ -954,7 +958,7 @@ func (h *HugoSites) processPartialFileEvents(ctx context.Context, l logg.LevelLo
case files.ComponentFolderLayouts:
tmplChanged = true
templatePath := pathInfo.Unnormalized().TrimLeadingSlash().PathNoLang()
if !h.Tmpl().HasTemplate(templatePath) {
if !h.GetTemplateStore().HasTemplate(templatePath) {
tmplAdded = true
}
@@ -974,8 +978,9 @@ func (h *HugoSites) processPartialFileEvents(ctx context.Context, l logg.LevelLo
}
} else {
logger.Println("Template changed", pathInfo.Path())
if templ, found := h.Tmpl().GetIdentity(templatePath); found {
changes = append(changes, templ)
id := h.GetTemplateStore().GetIdentity(pathInfo.Path())
if id != nil {
changes = append(changes, id)
} else {
changes = append(changes, pathInfo)
}
@@ -1084,7 +1089,6 @@ func (h *HugoSites) processPartialFileEvents(ctx context.Context, l logg.LevelLo
changed := &WhatChanged{
needsPagesAssembly: needsPagesAssemble,
identitySet: make(identity.Identities),
}
changed.Add(changes...)
@@ -1106,17 +1110,39 @@ func (h *HugoSites) processPartialFileEvents(ctx context.Context, l logg.LevelLo
}
}
h.Deps.OnChangeListeners.Notify(changed.Changes()...)
changes2 := changed.Changes()
h.Deps.OnChangeListeners.Notify(changes2...)
if err := h.resolveAndClearStateForIdentities(ctx, l, cacheBusterOr, changed.Drain()); err != nil {
return err
}
if tmplChanged || i18nChanged {
if tmplChanged {
if err := loggers.TimeTrackfn(func() (logg.LevelLogger, error) {
// TODO(bep) this could probably be optimized to somehow
// only load the changed templates and its dependencies, but that is non-trivial.
depsFinder := identity.NewFinder(identity.FinderConfig{})
ll := l.WithField("substep", "rebuild templates")
s := h.Sites[0]
if err := s.Deps.TemplateStore.RefreshFiles(func(fi hugofs.FileMetaInfo) bool {
pi := fi.Meta().PathInfo
for _, id := range changes2 {
if depsFinder.Contains(pi, id, -1) > 0 {
return true
}
}
return false
}); err != nil {
return ll, err
}
return ll, nil
}); err != nil {
return err
}
}
if i18nChanged {
if err := loggers.TimeTrackfn(func() (logg.LevelLogger, error) {
ll := l.WithField("substep", "rebuild i18n")
var prototype *deps.Deps
for i, s := range h.Sites {
if err := s.Deps.Compile(prototype); err != nil {