Compiler

Build Report

Every app generation entrypoint creates a structured build report. Disk builds write it to gowdk-build-report.json at the selected output root; in-memory builds return the same file in MemoryResult.Files; failed builds wrap the original error in buildgen.BuildError so callers can inspect the partial report while preserving the original error text. Callers without a real output root can use BuildMemoryWithOptions or BuildMemoryFromIRWithOptions; an empty OutputBase uses . for deterministic relative path metadata and does not create files or report directories.

Every app generation entrypoint creates a structured build report. Disk builds write it to gowdk-build-report.json at the selected output root; in-memory builds return the same file in MemoryResult.Files; failed builds wrap the original error in buildgen.BuildError so callers can inspect the partial report while preserving the original error text. Callers without a real output root can use BuildMemoryWithOptions or BuildMemoryFromIRWithOptions; an empty OutputBase uses . for deterministic relative path metadata and does not create files or report directories.

The report is mandatory for compiler-facing build APIs. It is deterministic: it does not include timestamps or durations, so unchanged builds can still skip rewriting identical generated files.

Build timings are opt-in and separate. gowdk build --timings writes gowdk-build-timings.json at the output root, and gowdk build --timings=<file> writes the same versioned JSON shape to a custom file. Timing data is not printed to stdout and is not added to gowdk-build-report.json.

Schema

{
  "version": 1,
  "mode": "build",
  "outputDir": "dist/site",
  "events": [
    {
      "level": "info",
      "stage": "validate",
      "kind": "ir_valid",
      "message": "compiler IR validation completed"
    }
  ]
}

mode is build, memory, or incremental. Events use debug, info, or error levels and record the compiler stage, a stable event kind, a message, and optional page, route, path, and string data fields.

Current stages are:

  • start: compiler IR counts at build entry.
  • validate: compiler IR and compiler contract validation.
  • plan: SPA page, CSS, and runtime asset planning.
  • write: page, CSS, and runtime asset writes or memory collection.
  • manifest: route and asset manifest reads/writes.
  • seo: optional sitemap/robots output and sitemap route exclusions.
  • cleanup: stale changed-page output removal during incremental builds.
  • complete: successful build summary.
  • report: build report serialization or write failure.

Current report events include:

  • cache_policy: summarizes generated page, CSS, asset, and request-time cache policies.
  • asset_obfuscation: summarizes whether production generated-asset obfuscation was enabled and how many compiler-owned browser assets were transformed.
  • asset_obfuscated: one event per compiler-owned generated browser asset transformed by Build.ObfuscateAssets or gowdk build --obfuscate-assets, including before/after hashes, byte counts, and whether the payload changed.
  • asset_size: one event per generated runtime asset, including JavaScript, source maps, WASM modules, and loaders. data.kind is javascript, wasm, sourcemap, css, or asset; data.bytes is the generated byte count. For assets/gowdk/islands/wasm_exec.js, data.wasmExecGoVersion records the Go toolchain version that supplied the runtime file.
  • contract_reference: one event per linked or unlinked g:command/g:query reference, including owner, source, status, route metadata, roles, and handler/register metadata when known.
  • realtime_subscription: one event per g:subscribe reference, including query, presentation event, owner, source, status, roles, and handler/register metadata when known.
  • query_invalidation: one event per validated domain-event to query invalidation edge used by bound g:query regions, including query, event, owner, source, status, and guard metadata when known.
  • sitemap_written / robots_written: emitted when addons/seo writes sitemap.xml and robots.txt.
  • seo_route_excluded: emitted when addons/seo excludes a page from the build-time sitemap, with data.reason and render mode. Reasons include request-time rendering, missing dynamic paths {}, and guardless routes that the generated app denies by default.

CLI Debug Output

gowdk build --debug prints a readable version of this report to stderr while normal generated artifact paths remain on stdout. gowdk dev forwards --debug as a build flag, including incremental SPA rebuilds.

Example:

gowdk build --debug --out dist/site src/pages/home.page.gwdk

Generated file paths are still scriptable from stdout; report details are only printed to stderr when --debug is present. The JSON report file is generated for every successful disk build even without --debug.

CLI Timing Output

gowdk build --timings records elapsed phase durations and simple counters in a separate sidecar:

{
  "version": 1,
  "mode": "build",
  "outputDir": "dist/site",
  "phases": [
    {
      "name": "parse_lower",
      "durationMs": 1.25
    }
  ],
  "counters": {
    "source_files": 1,
    "files_written": 4,
    "identical_writes_skipped": 0
  }
}

Current phases include config_load, source_discovery, parse_lower, ir_assembly, go_binding, ir_validation, contract_validation, output_plan_writes, app_generation, binary_build, wasm_build, backend_app_generation, and backend_binary_build when those paths run.

gowdk dev incremental SPA rebuilds reuse the same sidecar when --timings is forwarded in the build flags. Incremental counters include incremental_input_changes, incremental_page_changes, incremental_component_changes, incremental_layout_changes, incremental_affected_pages, files_written, and identical_writes_skipped.

Benchmarks

Use Go's benchmark runner for repeatable compiler regression tracking:

go test ./internal/parser ./internal/gwdkanalysis ./internal/compiler ./internal/buildgen -run '^$' -bench 'Benchmark(ParseLowerPage|IRAssembly|ValidateProgram|GeneratedOutputFromValidatedIR|IncrementalRebuildChangedPage)$' -benchmem -count=5

Stable benchmark names:

  • BenchmarkParseLowerPage: parses and lowers one representative page source.
  • BenchmarkIRAssembly: assembles pages/components into gwdkir.Program.
  • BenchmarkValidateProgram: runs compiler validation on assembled IR.
  • BenchmarkGeneratedOutputFromValidatedIR: writes SPA output from validated IR.
  • BenchmarkIncrementalRebuildChangedPage: rewrites the changed-page incremental build path.

Capture local baselines with the command above and compare with benchstat. CI should run benchmarks for trend data only; do not gate merges on fixed duration thresholds because hardware and filesystem variance are expected.