diff --git a/hugolib/hugo_sites.go b/hugolib/hugo_sites.go index 7eec98329..6a71fd97b 100644 --- a/hugolib/hugo_sites.go +++ b/hugolib/hugo_sites.go @@ -559,37 +559,82 @@ func (h *HugoSites) setupTranslations() { } } -func (s *Site) preparePagesForRender(cfg *BuildCfg) { - - pageChan := make(chan *Page) - wg := &sync.WaitGroup{} +type pagesRenderPreparer struct { + numWorkers int + s *Site + cfg *BuildCfg + wg *sync.WaitGroup + pages chan *Page +} +func newStartedRenderPreparator(s *Site, cfg *BuildCfg) *pagesRenderPreparer { numWorkers := getGoMaxProcs() * 4 + pp := &pagesRenderPreparer{ + s: s, + cfg: cfg, + numWorkers: numWorkers, + wg: &sync.WaitGroup{}, + pages: make(chan *Page), + } - for i := 0; i < numWorkers; i++ { - wg.Add(1) - go func(pages <-chan *Page, wg *sync.WaitGroup) { - defer wg.Done() - for p := range pages { - if err := p.prepareForRender(cfg); err != nil { - s.Log.ERROR.Printf("Failed to prepare page %q for render: %s", p.BaseFileName(), err) + pp.start() + return pp +} + +func (pp *pagesRenderPreparer) start() { + for i := 0; i < pp.numWorkers; i++ { + pp.wg.Add(1) + go func() { + defer pp.wg.Done() + for p := range pp.pages { + if err := p.prepareForRender(pp.cfg); err != nil { + pp.s.Log.ERROR.Printf("Failed to prepare page %q for render: %s", p.BaseFileName(), err) } } - }(pageChan, wg) + }() } +} - for _, p := range s.Pages { - pageChan <- p - } +func (pp *pagesRenderPreparer) add(p *Page) { + pp.pages <- p +} +func (pp *pagesRenderPreparer) done() { + close(pp.pages) + pp.wg.Wait() +} + +func (s *Site) preparePagesForRender(cfg *BuildCfg) { + + // For the content from other pages in shortcodes there are some chicken and + // egg dependencies that is hard to get around. But we can improve on this + // by preparing the pages in a certain order. + // So the headless pages goes first. These are typically collection of + // pages and images etc. used by others. + batch := newStartedRenderPreparator(s, cfg) for _, p := range s.headlessPages { - pageChan <- p + batch.add(p) } - close(pageChan) + batch.done() - wg.Wait() + // Then the rest in the following order: + order := []bundleDirType{bundleLeaf, bundleNot, bundleBranch} + + for _, tp := range order { + batch = newStartedRenderPreparator(s, cfg) + for _, p := range s.Pages { + // sanity check + if p.bundleType < 0 || p.bundleType > bundleBranch { + panic("unknown bundle type") + } + if p.bundleType == tp { + batch.add(p) + } + } + batch.done() + } } diff --git a/hugolib/hugo_sites_build.go b/hugolib/hugo_sites_build.go index 1c4ee7b63..dcff4b3b2 100644 --- a/hugolib/hugo_sites_build.go +++ b/hugolib/hugo_sites_build.go @@ -224,6 +224,7 @@ func (h *HugoSites) render(config *BuildCfg) error { s.initRenderFormats() for i, rf := range s.renderFormats { s.rc = &siteRenderingContext{Format: rf} + s.preparePagesForRender(config) if !config.SkipRender { diff --git a/hugolib/page.go b/hugolib/page.go index ebd7a3a2a..d0951bff7 100644 --- a/hugolib/page.go +++ b/hugolib/page.go @@ -243,6 +243,8 @@ type Page struct { // 3. But you can get it via .Site.GetPage headless bool + bundleType bundleDirType + layoutDescriptor output.LayoutDescriptor scratch *Scratch diff --git a/hugolib/page_bundler_handlers.go b/hugolib/page_bundler_handlers.go index c22b719d1..b38a3c35a 100644 --- a/hugolib/page_bundler_handlers.go +++ b/hugolib/page_bundler_handlers.go @@ -218,6 +218,8 @@ func (c *contentHandlers) parsePage(h contentHandler) contentHandler { ctx.currentPage = p if ctx.bundle != nil { + p.bundleType = ctx.bundle.tp + // Add the bundled files for _, fi := range ctx.bundle.resources { childCtx := ctx.childCtx(fi) diff --git a/hugolib/site.go b/hugolib/site.go index 262bf2d4d..820a2c829 100644 --- a/hugolib/site.go +++ b/hugolib/site.go @@ -1865,14 +1865,15 @@ func getGoMaxProcs() int { func (s *Site) newNodePage(typ string, sections ...string) *Page { p := &Page{ - language: s.Language, - pageInit: &pageInit{}, - Kind: typ, - Source: Source{File: &source.FileInfo{}}, - Data: make(map[string]interface{}), - Site: &s.Info, - sections: sections, - s: s} + bundleType: bundleBranch, + language: s.Language, + pageInit: &pageInit{}, + Kind: typ, + Source: Source{File: &source.FileInfo{}}, + Data: make(map[string]interface{}), + Site: &s.Info, + sections: sections, + s: s} p.outputFormats = p.s.outputFormats[p.Kind]