Skip to content

perf(pipeline): pre-convert ordered.Map before onContentTransformed hook dispatch #463

Description

@zeroedin

Problem

fireContentTransformedHooks (build.go:1813) passes page.FrontMatter directly into the hook payload at line 1820. When json.Marshal serializes this payload for the QuickJS/WASM bridge, any *ordered.Map values in FrontMatter trigger ordered.Map.MarshalJSON — which is 13.7% of total CPU (2.28s) due to byte-by-byte appendCompact copying.

*ordered.Map values enter FrontMatter when the cascade merges JSON data file values into the page context.

Profiling evidence (from plans/CONTENT_TRANSFORMHOOK_PERF.md)

ordered.Map.MarshalJSON   2.28s   13.7% of CPU
json.Marshal (total)      2.75s   16.6% of CPU
Inter-pass hooks total   11.9s   61.9% of build

Fix

Before building the hook payload, convert *ordered.Map values in page.FrontMatter to plain map[string]interface{} via ToGoMap(). Regular map marshaling is dramatically faster — no custom MarshalJSON, no appendCompact.

// build.go:1815 — before payload construction
fm := convertOrderedMaps(page.FrontMatter)
payload := map[string]interface{}{
    "html":        string(page.RenderedBody),
    "toc":         serializeTOC(page.TOC),
    "path":        page.RelPath,
    "url":         page.URL,
    "frontMatter": fm,  // plain maps, fast marshal
}

convertOrderedMaps recursively walks the map and calls ToGoMap() on any *ordered.Map value. This is a read-only conversion at the hook boundary — page.FrontMatter is untouched. Templates still see the original *ordered.Map values for ordered iteration.

Scope

  • Only affects fireContentTransformedHooks in build.go
  • Only the JSON payload sent to the QuickJS/WASM VM is converted
  • Template engines (Liquid, Go templates) are not involved — they receive page.FrontMatter directly after hooks complete
  • page.FrontMatter is NOT mutated — only the serialization copy is converted
  • Plugins don't need key ordering in front matter — they're processing HTML and metadata

Expected impact

ordered.Map.MarshalJSON drops from 13.7% to 0%. json.Marshal total drops from ~2.75s to ~0.47s. Inter-pass hooks drop from ~12s to ~9s (remaining cost is WASM memory overhead, addressed separately).

Related

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions