build

package
v0.11.21 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 12, 2026 License: MIT Imports: 39 Imported by: 0

Documentation

Overview

Package build defines the Hook capability interface for plugins that participate in the build pipeline. Each hook point maps to a BuildSite stage.

This is a skeleton interface — no concrete Hook implementations ship with huan v1.0. The interface exists so that future plugins (e.g. SEO injector, custom output transformer, external API notifier) can register without requiring changes to the build pipeline.

See docs/adr/0003-unified-plugin-system.md for the capability interface pattern.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BuildEmptyTaxonomyContext

func BuildEmptyTaxonomyContext(siteCtx *tmpl.SiteContext, title, plural string) *tmpl.Context

BuildEmptyTaxonomyContext creates a context for an empty taxonomy listing (e.g., /categories/ when no categories are defined). Hugo generates these by default.

func BuildSitemapContext

func BuildSitemapContext(siteCtx *tmpl.SiteContext, lookup map[*content.Page]*tmpl.Context, site *content.Site, cfg *config.Config) *tmpl.Context

BuildSitemapContext creates a root context for sitemap rendering. The sitemap template iterates .Pages, so we need a context with all pages populated.

func BuildTaxonomyContext

func BuildTaxonomyContext(siteCtx *tmpl.SiteContext, lookup map[*content.Page]*tmpl.Context, site *content.Site, cfg *config.Config) *tmpl.Context

BuildTaxonomyContext creates the context for /tags/ (terms listing).

func BuildTermContext

func BuildTermContext(siteCtx *tmpl.SiteContext, lookup map[*content.Page]*tmpl.Context, site *content.Site, cfg *config.Config, term string, pages tmpl.PageSlice) *tmpl.Context

BuildTermContext creates the context for /tags/{tag}/ (single term page).

func CloneContextForPagination

func CloneContextForPagination(homeCtx *tmpl.Context, allItems tmpl.PageSlice, pageSize, pageNum, totalPages int) *tmpl.Context

CloneContextForPagination creates a shallow copy of homeCtx with a Paginator pointing at page N. The URL stays "/" so meta tags match Hugo's behavior.

func CountWordsInPlain

func CountWordsInPlain(s string) int

CountWordsInPlain counts words in plain text using Hugo's actual algorithm for sites with hasCJKLanguage=true (zhurongshuo sets this).

Source: hugolib/page__content.go (Hugo master):

result.plain = StripHTML(rendered.content)
result.plainWords = strings.Fields(result.plain)
if isCJKLanguage {
    for _, word := range result.plainWords {
        runeCount := utf8.RuneCountInString(word)
        if len(word) == runeCount {  // all-ASCII
            result.wordCount++
        } else {                     // contains multi-byte (CJK etc.)
            result.wordCount += runeCount
        }
    }
}

Effectively: split by whitespace (unicode.IsSpace, which includes the ideographic space U+3000); each whitespace-separated field is 1 word if pure ASCII, otherwise contributes its rune count. Punctuation inside a field is counted as a rune — this matches Hugo's behavior exactly.

Stage 1 limitation: Hugo gates this CJK branch behind `isCJKLanguage` (from `hasCJKLanguage` config). huan unconditionally applies the CJK algorithm, which is correct for zhurongshuo (hasCJKLanguage=true) but would under-count non-CJK sites. Stage 2 should add a config gate when huan is used for other sites.

func DetectThemeName

func DetectThemeName(sourceDir string) string

func FilterMainSections

func FilterMainSections(pages tmpl.PageSlice, mainSections []string) tmpl.PageSlice

FilterMainSections returns pages whose Section is in mainSections.

func FindHomeContext

func FindHomeContext(lookup map[*content.Page]*tmpl.Context, site *content.Site) *tmpl.Context

FindHomeContext returns the home page context, used for search index rendering.

func HasTemplateChanges added in v0.7.0

func HasTemplateChanges(changedFiles []string, sourceDir string) bool

HasTemplateChanges reports whether any changed file invalidates the pipeline cache. Files under layouts/, i18n/, themes/, or the huan.yaml config itself require a full rebuild because they affect the cached templates/i18n/config.

Returns false for content/ and static/ changes (those are handled incrementally).

func IncrementalRender added in v0.7.0

func IncrementalRender(opts Options, cache *PipelineCache, affectedURLs []string) error

IncrementalRender re-renders only the pages whose URLs are in affectedURLs, after a content change. It reuses cached templates/i18n/writer from a prior full build (via cache), but reloads all content + rebuilds contexts to ensure correctness (list pages must see updated page content).

Only pages in affectedURLs are re-rendered and written to OutputDir; other pages are left untouched on disk. This skips the expensive per-page template rendering for the ~95% of unaffected pages.

Use HasTemplateChanges() first: if templates changed, call BuildSite (full build) instead. Pass cache=nil to rebuild everything from scratch (slower, but always correct).

func InjectLiveReload

func InjectLiveReload(html, wsURL string) string

InjectLiveReload inserts the livereload <script> before </head>. Falls back to before </body> if </head> is absent. If neither is present, appends the script at the end.

func JITRenderFast added in v0.7.0

func JITRenderFast(opts Options, cache *PipelineCache, pageURL string) (string, error)

JITRenderFast renders a single page for JIT, skipping the full pipeline. Unlike RenderPageWithCache which reloads ALL content + rebuilds ALL contexts, JITRenderFast loads ONLY the target page, renders ONLY its markdown, and builds ONLY its context. This reduces JIT latency from O(N) to O(1).

Preconditions:

  • cache is non-nil and has been populated by at least one full build
  • cache.ContentCache is non-nil
  • The page exists on disk (caller should verify before calling)

Returns "" with no error when the page should not be rendered (draft/future).

func RenderPage added in v0.7.0

func RenderPage(opts Options, pg *content.Page) (string, error)

RenderPage renders a single page using the provided build options. This is the entry point for daemon's JIT rendering and incremental updates.

It creates a new pipeline, runs stages 1-5 (config, content, markdown, templates, contexts), finds the requested page by RelPath, and renders it.

Experimental: API may change in future versions.

func RenderPageToBytes added in v0.7.0

func RenderPageToBytes(opts Options, pg *content.Page) ([]byte, error)

RenderPageToBytes renders a single page and returns the HTML as a byte slice. Convenience wrapper around RenderPage.

Experimental: API may change in future versions.

func RenderPageWithCache added in v0.7.0

func RenderPageWithCache(opts Options, cache *PipelineCache, pageURL string) (string, error)

RenderPageWithCache renders a single page on demand, reusing the cached rendering infrastructure (templates/i18n/markdown/writer). Unlike IncrementalRender, it returns the HTML without writing to disk, targets exactly one page identified by URL, and forces IncludeDrafts=true (JIT primarily serves draft pages that were skipped at build time).

Used by daemon's JIT fallback when a requested URL is not in the pre-built static output. Content + contexts are always rebuilt (cheap) to keep list-page contexts consistent with the current on-disk content.

When cache is nil or incomplete, falls back to a full pipeline setup (slower but always correct).

func ResolveRSSOutput

func ResolveRSSOutput(p *content.Page) string

ResolveRSSOutput returns the RSS template name for a section/home page.

func ResolveSourceFromURL added in v0.7.0

func ResolveSourceFromURL(pageURL string) string

ResolveSourceFromURL derives the source file path (relative to content/) from a page URL. Used by JIT rendering when the URL is not in the DAG (e.g., a newly-created draft not yet captured by a full build).

URL conventions (match Hugo/huan content layout):

/                          → _index.md            (home)
/posts/                    → posts/_index.md      (section)
/posts/hello/              → posts/hello.md       (regular page)
/posts/2026/new-year/      → posts/2026/new-year.md
/posts/_index/             → posts/_index.md      (explicit)

Exported so the daemon package can compose it with DAG reverse lookup to map a page URL to its source file (see daemon.resolveSourceFile).

Returns "" only if the input cannot be parsed (effectively never for a normalized URL); callers should still verify the file exists on disk.

func ResolveTemplateName

func ResolveTemplateName(tmpls *template.Template, p *content.Page) string

ResolveTemplateName maps a page to its template using Hugo's lookup rules.

func StripHTMLTagsForSummary

func StripHTMLTagsForSummary(s string) string

StripHTMLTagsForSummary strips HTML tags for plain text summary.

func SummarizeMultiSite added in v0.3.0

func SummarizeMultiSite(r *MultiSiteResult) string

SummarizeMultiSite returns a one-line summary string for a MultiSiteResult, suitable for CLI output. Format: "built N languages: zh-cn=X pages en=Y pages (Dduration)".

func SwapBuildDir

func SwapBuildDir(liveDir, nextDir string) error

SwapBuildDir atomically (enough) replaces liveDir's contents with nextDir's.

Usage: build the new site into nextDir, then call SwapBuildDir(liveDir, nextDir). On success, liveDir contains the new build and the old contents are removed. On failure, liveDir is untouched and the caller should clean up nextDir.

Implementation: rename liveDir → liveDir+".old", rename nextDir → liveDir, then RemoveAll(liveDir+".old"). Two renames are not atomic together, so a request hitting liveDir in the microsecond window between them may 404. This is acceptable for a dev server: the LiveReload client retries, and the user editing won't notice.

If the second rename fails (extremely unlikely — typically only if nextDir disappeared between caller creating it and us renaming it), we attempt to restore the original liveDir before returning the error.

func TruncateHTMLByWords

func TruncateHTMLByWords(htmlStr string, n int) string

TruncateHTMLByWords truncates HTML content to the first N words and closes any open tags. Word counting follows the same rules as CountWordsInPlain (strings.Fields + rune count for CJK fields).

Truncation happens at word boundaries: the moment we finish counting the Nth word, we cut immediately (without consuming the trailing separator) and close open tags. This matches Hugo's summary behavior.

func TruncateHTMLToBlockBoundary

func TruncateHTMLToBlockBoundary(htmlStr string, n int) string

TruncateHTMLToBlockBoundary truncates HTML following Hugo's actual summary algorithm (resources/page/page_markup.go:ExtractSummaryFromHTML).

Hugo's algorithm walks paragraph-by-paragraph (using `</p>` as the paragraph-tag terminator for Markdown content), counting words in each segment between consecutive `</p>` boundaries. The segment between two `</p>`s may contain other block elements (e.g. `<h2>`), all of which contribute to that segment's word count.

Hugo's exact source loop (paraphrased):

for j := 0; j < len(input); {
    closingIndex := strings.Index(input[j:], "</p>")
    if closingIndex == -1 { break }
    s := input[j : j+closingIndex]
    var wi int
    for i, r := range s {
        if unicode.IsSpace(r) || (i+utf8.RuneLen(r) == len(s)) {
            word := s[wi:i]   // NOTE: i is the byte offset of the current rune,
                              // so this EXCLUDES the current (last) rune when
                              // the end-of-segment trigger fires.
            count += countWord(word, isCJK)
            wi = i
            if count >= numWords { break }
        }
    }
    if count >= numWords {
        return input[:j+closingIndex+len("</p>")]
    }
    j += closingIndex + len("p") + 2  // advance past </p> (skips "</p>" minus 1 char)
}

Two non-obvious quirks this preserves:

  1. End-of-segment word is s[wi:i] where i is byte offset of the LAST rune, so the last rune of each segment is excluded from its own word. This means each CJK-only paragraph contributes runeCount-1 to the cumulative count (not runeCount).
  2. Between `</p>`s, intermediate block elements (`<h2>`, etc.) contribute their text to the next segment's word count, since the segment spans from the previous `</p>` to the next `</p>`.

Hugo's countWord for CJK strips HTML tags and counts every rune (multi- byte) per whitespace-separated field. HTML-tag-like tokens (matched by `^</?[A-Za-z]+>?$` or `^[A-Za-z]+=...`) count as 0 words.

func URLEscape

func URLEscape(s string) string

URLEscape mirrors Hugo's urlize behavior for tag URLs:

  • lowercase ASCII letters
  • spaces become "-"
  • CJK characters are preserved as-is (NOT URL-encoded)
  • ASCII letters/digits are preserved (after lowercasing)
  • other special chars (parens, etc.) are URL-encoded

Use this for filesystem paths (where CJK must be preserved so the OS can read the file). For URLs that appear in HTML/XML output (RSS <link>, <guid>, <atom:link>, og:url, canonical), use URLEscapeForURL which percent-encodes CJK to match Hugo's permalink behavior.

func URLEscapeForURL

func URLEscapeForURL(s string) string

URLEscapeForURL mirrors Hugo's URL percent-encoding for non-filesystem URLs (permalinks, RSS link/guid, atom:link, og:url). Unlike URLEscape (which preserves CJK for filesystem paths), URLEscapeForURL percent-encodes CJK characters and other non-ASCII / non-URL-safe chars.

Use this for any URL that appears in HTML/XML output. Use URLEscape for filesystem paths.

Types

type BuildDirSwapper added in v0.11.20

type BuildDirSwapper struct {
	// contains filtered or unexported fields
}

BuildDirSwapper publishes complete builds while deleting the old output in the background. Its zero value is ready to use. Call Swap serially and stop calling Swap before the final Wait. Do not copy after use.

func (*BuildDirSwapper) Swap added in v0.11.20

func (s *BuildDirSwapper) Swap(liveDir, nextDir string) error

Swap waits for the previous cleanup before reusing liveDir+".old", then publishes nextDir. A successful swap starts at most one background cleanup. Failed swaps retain the same best-effort rollback as SwapBuildDir.

func (*BuildDirSwapper) Wait added in v0.11.20

func (s *BuildDirSwapper) Wait()

Wait waits for the most recent old-output cleanup to finish.

type Hook added in v0.7.0

type Hook interface {
	plugin.Plugin

	// OnContentLoaded is called after all content files are loaded and parsed
	// (Stage 2 of BuildSite). The plugin receives the full page list and may
	// return a modified list. Returning nil (or the same slice) is a no-op.
	OnContentLoaded(ctx context.Context, pages []*content.Page) ([]*content.Page, error)

	// OnPageRendered is called after each page is rendered to HTML (Stage 5).
	// The plugin may modify the page's Content, Summary, or other fields.
	OnPageRendered(ctx context.Context, page *content.Page) error

	// OnOutputWritten is called after all output files are written but before
	// the build result is finalized (end of Stage 8). Receives the output
	// directory path for post-processing (e.g. copying extra files, generating
	// a manifest, notifying an external service).
	OnOutputWritten(ctx context.Context, outputDir string) error
}

Hook is the capability interface for plugins that participate in the build pipeline. Each method maps to a BuildSite stage.

Every method is optional — a plugin that only needs to run after writing output implements OnOutputWritten and returns nil for the others.

Hook methods are called with collection-not-interruption semantics: a failing hook logs a warning but does not abort the build.

type I18nStaleReport added in v0.3.0

type I18nStaleReport struct {
	// Checked counts .en.md (and other sidecar) files whose frontmatter
	// was successfully parsed and source_hash compared.
	Checked int

	// Stale counts sidecars whose source_hash doesn't match the current
	// source markdown sha256.
	Stale int

	// Missing counts sidecars whose frontmatter lacks source_hash entirely
	// (e.g. hand-created sidecar).
	Missing int

	// StaleFiles lists paths of stale sidecars (for error reporting).
	StaleFiles []string

	// MissingHashFiles lists paths of sidecars without source_hash.
	MissingHashFiles []string
}

I18nStaleReport summarizes stale translation sidecars found during build.

func (*I18nStaleReport) Error added in v0.3.0

func (r *I18nStaleReport) Error() string

Error returns a multi-line error describing all stale sidecars. Implements error interface so report can be returned directly from BuildSite when strict mode fails.

type I18nStrictOptions added in v0.3.0

type I18nStrictOptions struct {
	// Enabled is true when strict mode is on (typically CI builds).
	// When false (default for local builds), mismatches log warnings but
	// don't fail the build.
	Enabled bool

	// TargetLangs is the list of non-default language codes to check.
	// Empty means check all .<lang>.md sidecars found in content/.
	TargetLangs []string
}

I18nStrictOptions controls stale translation detection. When strict mode is enabled, BuildSite fails-fast on .en.md sidecars whose source_hash frontmatter doesn't match the current source markdown.

type LanguageBuildResult added in v0.3.0

type LanguageBuildResult struct {
	Code   string
	Result *Result
}

LanguageBuildResult pairs a language code with its build Result.

type MarkdownCache added in v0.11.20

type MarkdownCache struct {
	// contains filtered or unexported fields
}

MarkdownCache stores immutable rendering results across builds. It is safe to share between pipelines; it never retains pages or shortcode state. The zero value and nonpositive capacities disable storage. Do not copy after use.

func NewMarkdownCache added in v0.11.20

func NewMarkdownCache(maxBytes int64) *MarkdownCache

NewMarkdownCache creates a bounded LRU. A nonpositive limit disables storage.

func NewPersistentMarkdownCache added in v0.11.20

func NewPersistentMarkdownCache(memoryBytes int64, dir, namespace string, diskBytes int64) (*MarkdownCache, error)

NewPersistentMarkdownCache adds an optional best-effort disk tier. namespace must identify the renderer implementation (the CLI hashes its executable). Invalid, missing or unreadable records are misses, never build failures. Only the instance holding the directory's advisory lease writes. Other instances remain read-only. Call Close after all builds have stopped.

func (*MarkdownCache) Clear added in v0.11.20

func (c *MarkdownCache) Clear()

Clear discards all entries while retaining cumulative hit/miss/eviction counts. Call between builds to invalidate results after non-content changes.

func (*MarkdownCache) Close added in v0.11.20

func (c *MarkdownCache) Close() error

Close releases the optional disk writer lease. It is idempotent and nil-safe. The caller must stop all builds before closing; subsequent puts use memory only, while completed disk records remain readable by this or other caches.

func (*MarkdownCache) PruneDisk added in v0.11.20

func (c *MarkdownCache) PruneDisk() error

PruneDisk maintains the writer's indexed budget without rescanning disk. Writes already reserve capacity before creating files. Read-only instances never prune another process's cache; unrelated files are never touched.

func (*MarkdownCache) Stats added in v0.11.20

func (c *MarkdownCache) Stats() MarkdownCacheStats

Stats returns the current budget usage and lifetime counters.

type MarkdownCacheStats added in v0.11.20

type MarkdownCacheStats struct {
	Hits, Misses, Evictions uint64
	DiskHits                uint64
	Entries                 int
	Bytes, MaxBytes         int64
}

MarkdownCacheStats is a consistent snapshot. Bytes counts owned string data plus a conservative fixed allowance for each entry's key and bookkeeping; it is a capacity budget, not a measurement of the Go allocator's heap usage.

type MultiSiteResult added in v0.3.0

type MultiSiteResult struct {
	// PerLanguage holds the build result for each configured language, with
	// the default language first, then the rest in weight-ascending then
	// code-alphabetical order (matches config.SortedLanguages(), with the
	// default hoisted to the front).
	PerLanguage []LanguageBuildResult

	// TotalDuration is the wall-clock time of the entire multi-language build.
	TotalDuration time.Duration
}

MultiSiteResult aggregates per-language build results. Returned by BuildMultiSite when huan.yaml declares more than one language under the `languages:` block (see docs/adr/0007-i18n-build-system.md).

func BuildMultiSite added in v0.3.0

func BuildMultiSite(opts Options) (*MultiSiteResult, error)

BuildMultiSite renders the site once per configured language, outputting each language's files under its baseURL prefix.

Behavior:

  1. Load config + content once (shared across languages).
  2. Build AvailableTranslations map: for each page's RelPath, which languages have actual sidecar files. Used by buildTranslationLinks to filter hreflang output to only existing translations.
  3. For each language (sorted by weight): a. Clone the master cfg. b. Override Title/LanguageCode per `languages.<code>` config. c. Append language baseURL to cfg.BaseURL when non-empty (e.g. /en). d. Append language baseURL to opts.OutputDir when non-empty. e. Set PageFilter: default-lang pages (Language="" or matches default code) go to the default build; sidecar pages (Language="<code>") go to their respective language build. f. Call BuildSite with CfgOverride + PageFilter + AvailableTranslations.

Single-language backward compatibility: when cfg.Languages is empty, callers should use BuildSite directly. BuildMultiSite returns an error in that case (caller bug, not a runtime condition).

type Options

type Options struct {
	Timings *Timings
	// MarkdownCache optionally reuses Markdown results across full builds.
	// Nil keeps rendering uncached. Share one instance for a dev lifecycle.
	MarkdownCache *MarkdownCache
	// ParseCache reuses frontmatter parsed from identical freshly read bytes.
	ParseCache       *content.ParseCache
	SourceDir        string
	OutputDir        string // absolute path
	IncludeDrafts    bool
	IncludeFuture    bool
	IncludeExpired   bool
	InjectLiveReload bool   // serve-only; when true, LiveReloadURL must be set
	LiveReloadURL    string // empty disables injection
	BaseURLOverride  string // serve-only; overrides cfg.BaseURL for dev server
	MinifyOverride   *bool  // nil = use config Minify; non-nil = force this value
	Logf             func(format string, args ...any)

	// CfgOverride skips config.Load(opts.SourceDir) and uses this Config
	// directly. Used internally by BuildMultiSite to build per-language
	// variants without re-reading huan.yaml.
	CfgOverride *config.Config

	// PageFilter, when non-nil, excludes pages where the function returns
	// false. Used internally by BuildMultiSite to build per-language subsets.
	PageFilter func(*content.Page) bool

	// AvailableTranslations, when non-nil, maps each page's language-neutral
	// RelPath to the set of language codes with an actual sidecar file.
	// Used by template context to filter hreflang output to only languages
	// that actually exist for each page (prevents hreflang=en → 404).
	AvailableTranslations map[string]map[string]bool

	// AfterBuild is called after BuildSite completes successfully.
	// It receives the Result and a callback for single-page rendering.
	// Used by daemon to initialize JIT cache with build context.
	// Experimental: API may change in future versions.
	AfterBuild func(*Result, RenderPageFunc) error

	// AfterBuildSite is called after BuildSite completes successfully with
	// the built site. Used by daemon's DAG builder to construct the
	// dependency graph for incremental updates.
	// Experimental: API may change in future versions.
	AfterBuildSite func(*content.Site) error

	// PipelineCache, if non-nil, is populated with reusable build state
	// after BuildSite completes successfully. Used by daemon for
	// incremental builds. Pass a cache created by NewPipelineCache().
	// Experimental: API may change in future versions.
	PipelineCache *PipelineCache

	// PluginRegistry, if non-nil, is used to discover build.Hook plugins
	// that participate in the build pipeline. Hook methods are called with
	// collection-not-interruption semantics — failures log a warning but
	// do not abort the build.
	PluginRegistry *plugin.Registry

	// ThemeManager, if non-nil, is used to discover theme hooks
	// that participate in the build pipeline.
	ThemeManager *theme.Manager

	// StaticExclude / StaticRoot are injected per-language by BuildMultiSite.
	StaticExclude []string
	StaticRoot    string
}

Options controls a single BuildSite invocation.

type PipelineCache added in v0.7.0

type PipelineCache struct {
	// Rendering infrastructure (valid until template/i18n/config changes)
	Templates  *template.Template
	I18nBundle *i18n.Bundle
	SCRegistry *shortcode.Registry
	MDRenderer *markdown.Renderer

	// Site config (valid until huan.yaml changes)
	SiteCfg *config.Config

	// Output writer (valid across builds; writes to the same OutputDir)
	Writer *output.Writer

	// BuiltAt records when this cache was populated (the last full build time).
	BuiltAt time.Time

	// ContentCache caches loaded page content by content-relative path.
	// Populated lazily on first access; invalidated by file mtime changes.
	ContentCache *cache.ContentCache

	// ContextCache caches per-page template contexts, keyed by page pointer
	// and version-gated. Used by buildContexts() to avoid re-creating contexts
	// for pages whose content hasn't changed.
	ContextCache *cache.ContextCache

	// Renderer is the cached template renderer, reused across incremental
	// builds to avoid re-cloning the template tree.
	Renderer *tmpl.Renderer
}

PipelineCache holds reusable build state across incremental builds. Populated after a full build completes. Incremental builds reuse this state to avoid re-parsing templates, reloading i18n bundles, and re-initializing the writer.

DESIGN NOTE: This cache intentionally does NOT hold per-page content or template contexts. Those reference page pointers that change on every content edit, so caching them would produce stale output for list pages. Instead, incremental builds reload content + rebuild contexts (cheap) and reuse only the rendering infrastructure here (expensive to rebuild).

ContentCache is the exception: it caches page content by file path with mtime-based invalidation, so incremental builds and JIT can skip re-reading unchanged files. It is populated lazily (first access loads the file) and is safe to share across builds as long as the source directory is stable.

func NewPipelineCache added in v0.7.0

func NewPipelineCache() *PipelineCache

NewPipelineCache returns an empty PipelineCache with BuiltAt set to now.

type RenderPageFunc added in v0.7.0

type RenderPageFunc func(pg *content.Page) (string, error)

RenderPageFunc is the callback signature for single-page rendering. Experimental: API may change in future versions.

type Result

type Result struct {
	PagesRendered int
	FilesWritten  int
	BytesWritten  int64
	Errors        int
	Duration      time.Duration
}

Result reports what happened during the build.

func BuildSite

func BuildSite(opts Options) (*Result, error)

BuildSite renders the full site from SourceDir into OutputDir, orchestrating 7 stages via the pipeline type (see pipeline.go and pipeline_*.go):

  1. loadConfig (pipeline.go) — cfg + serve overrides + i18n inject
  2. loadContent (pipeline.go) — content/ + data/ + stale-i18n check
  3. renderMarkdownAndTree (pipeline.go)— per-page goldmark + tree + taxonomies
  4. setupTemplatesAndWriter (setup) — templates + i18n bundle + writer
  5. buildContexts (setup) — siteCtx + per-page ctx + links
  6. renderPages (render) — HTML + Markdown mirror + section RSS
  7. renderFeedsAndSpecials (feeds) — taxonomy/pagination/404/sitemap/etc.
  8. copyStaticAndFinalize (write) — static assets + stats

Any stage error aborts the build immediately. Errors during per-page render are accumulated into Result.Errors instead.

type TimingEntry added in v0.11.13

type TimingEntry struct {
	Scope, Stage string
	Duration     time.Duration
	Failed       bool
}

TimingEntry reports wall time for a stage. Child stages overlap their parents.

type Timings added in v0.11.13

type Timings struct {
	// contains filtered or unexported fields
}

Timings collects one build's measurements and is safe for concurrent hooks.

func NewTimings added in v0.11.13

func NewTimings() *Timings

func (*Timings) Entries added in v0.11.13

func (c *Timings) Entries() []TimingEntry

func (*Timings) Measure added in v0.11.13

func (c *Timings) Measure(scope, stage string, fn func() error) error

func (*Timings) Record added in v0.11.13

func (c *Timings) Record(scope, stage string, d time.Duration, failed bool)

func (*Timings) Report added in v0.11.13

func (c *Timings) Report(logf func(string, ...any))

Directories

Path Synopsis
Package cache provides caching utilities for the build pipeline.
Package cache provides caching utilities for the build pipeline.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL