diff --git a/hugolib/page.go b/hugolib/page.go index 2ed828df6bd..73ed518760d 100644 --- a/hugolib/page.go +++ b/hugolib/page.go @@ -360,40 +360,44 @@ func (p *pageState) setPages(pages page.Pages) { p.pages = pages } -func (p *pageState) renderResources() error { - var toBeDeleted []int - - for i, r := range p.Resources() { - if _, ok := r.(page.Page); ok { - // Pages gets rendered with the owning page but we count them here. - p.s.PathSpec.ProcessingStats.Incr(&p.s.PathSpec.ProcessingStats.Pages) - continue - } +func (p *pageState) renderResources() (err error) { + p.resourcesPublishInit.Do(func() { + var toBeDeleted []int + + for i, r := range p.Resources() { + if _, ok := r.(page.Page); ok { + // Pages gets rendered with the owning page but we count them here. + p.s.PathSpec.ProcessingStats.Incr(&p.s.PathSpec.ProcessingStats.Pages) + continue + } - src, ok := r.(resource.Source) - if !ok { - return errors.Errorf("Resource %T does not support resource.Source", src) - } + src, ok := r.(resource.Source) + if !ok { + err = errors.Errorf("Resource %T does not support resource.Source", src) + return + } - if err := src.Publish(); err != nil { - if os.IsNotExist(err) { - // The resource has been deleted from the file system. - // This should be extremely rare, but can happen on live reload in server - // mode when the same resource is member of different page bundles. - toBeDeleted = append(toBeDeleted, i) + if err := src.Publish(); err != nil { + if os.IsNotExist(err) { + // The resource has been deleted from the file system. + // This should be extremely rare, but can happen on live reload in server + // mode when the same resource is member of different page bundles. + toBeDeleted = append(toBeDeleted, i) + } else { + p.s.Log.ERROR.Printf("Failed to publish Resource for page %q: %s", p.pathOrTitle(), err) + } } else { - p.s.Log.ERROR.Printf("Failed to publish Resource for page %q: %s", p.pathOrTitle(), err) + p.s.PathSpec.ProcessingStats.Incr(&p.s.PathSpec.ProcessingStats.Files) } - } else { - p.s.PathSpec.ProcessingStats.Incr(&p.s.PathSpec.ProcessingStats.Files) } - } - for _, i := range toBeDeleted { - p.deleteResource(i) - } + for _, i := range toBeDeleted { + p.deleteResource(i) + } - return nil + }) + + return } func (p *pageState) deleteResource(i int) { diff --git a/hugolib/page__common.go b/hugolib/page__common.go index 5bd7223cc2d..01280bb407c 100644 --- a/hugolib/page__common.go +++ b/hugolib/page__common.go @@ -91,8 +91,9 @@ type pageCommon struct { pagesInit sync.Once // Any bundled resources - resources resource.Resources - resourcesInit sync.Once + resources resource.Resources + resourcesInit sync.Once + resourcesPublishInit sync.Once translations page.Pages allTranslations page.Pages diff --git a/hugolib/pagebundler_test.go b/hugolib/pagebundler_test.go index 870ea3de9a7..06bd641542f 100644 --- a/hugolib/pagebundler_test.go +++ b/hugolib/pagebundler_test.go @@ -896,3 +896,37 @@ TheContent. return ps, clean, workDir } + +// https://github.com/gohugoio/hugo/issues/5858 +func TestBundledResourcesWhenMultipleOutputFormats(t *testing.T) { + t.Parallel() + + b := newTestSitesBuilder(t).Running().WithConfigFile("toml", ` +baseURL = "https://example.org" +[outputs] + # This looks odd, but it triggers the behaviour in #5858 + # The total output formats list gets sorted, so CSS before HTML. + home = [ "CSS" ] + +`) + b.WithContent("mybundle/index.md", ` +--- +title: Page +date: 2017-01-15 +--- +`, + "mybundle/data.json", "MyData", + ) + + b.CreateSites().Build(BuildCfg{}) + + b.AssertFileContent("public/mybundle/data.json", "MyData") + + // Change the bundled JSON file and make sure it gets republished. + b.EditFiles("content/mybundle/data.json", "My changed data") + + b.Build(BuildCfg{}) + + b.AssertFileContent("public/mybundle/data.json", "My changed data") + +} diff --git a/hugolib/shortcode_test.go b/hugolib/shortcode_test.go index 3320e642c44..dd01eb5c504 100644 --- a/hugolib/shortcode_test.go +++ b/hugolib/shortcode_test.go @@ -903,6 +903,7 @@ func TestShortcodeParentResourcesOnRebuild(t *testing.T) { b.WithTemplatesAdded( "index.html", ` {{ $b := .Site.GetPage "b1" }} +b1 Content: {{ $b.Content }} {{$p := $b.Resources.GetMatch "p1*" }} Content: {{ $p.Content }} {{ $article := .Site.GetPage "blog/article" }} @@ -933,20 +934,23 @@ SHORTCODE: {{< c >}} b.Build(BuildCfg{}) - assert := func() { - b.AssertFileContent("public/index.html", - "Parent resource: logo.png: /b1/logo.png", + assert := func(matchers ...string) { + allMatchers := append(matchers, "Parent resource: logo.png: /b1/logo.png", "Article Content:

SHORTCODE: \n\n* Parent resource: logo-article.png: /blog/logo-article.png", ) + + b.AssertFileContent("public/index.html", + allMatchers..., + ) } assert() - b.EditFiles("b1/index.md", pageContent+" Edit.") + b.EditFiles("content/b1/index.md", pageContent+" Edit.") b.Build(BuildCfg{}) - assert() + assert("Edit.") } diff --git a/hugolib/site_render.go b/hugolib/site_render.go index 407061b6778..9ade951df1a 100644 --- a/hugolib/site_render.go +++ b/hugolib/site_render.go @@ -35,6 +35,7 @@ type siteRenderContext struct { sitesOutIdx int // Zero based index of the output formats configured within a Site. + // Note that these outputs are sorted, so CSS will come before HTML. outIdx int multihost bool @@ -130,11 +131,9 @@ func pageRenderer( continue } - if ctx.outIdx == 0 { - if err := p.renderResources(); err != nil { - s.SendError(p.errorf(err, "failed to render page resources")) - continue - } + if err := p.renderResources(); err != nil { + s.SendError(p.errorf(err, "failed to render page resources")) + continue } layouts, err := p.getLayouts()