Generated output currently covers app-shell HTML, selected browser runtime assets,
generated embedded app source, and optional local binary or Go js/wasm
artifacts for the implemented compiler slice.
Implemented today:
gowdk build [--out <dir>] [files...]writes route-derived HTML files for simplespaandactionpages..cmp.gwdkfiles can be passed to build or discovered by default and expanded from self-closing component calls.gowdk-routes.jsonrecords the app route, page ID, and relative output path for emitted pages.gowdk-assets.jsonrecords generated app assets such as CSS files emitted by CSS processors, generated page CSS files, the partial-update client runtime when needed, and route HTML cache metadata.gowdk-build-report.jsonrecords build-output generator validation, planning, write, manifest, cleanup, and completion events for every successful disk build.- Page
@title,@description,@canonical,@image, app-levelBuild.Head, configured stylesheets, and CSS processor stylesheet links are emitted in page<head>elements.Build.Headenables favicon, Open Graph, and Twitter card tags without a post-build patcher. - CSS processors can emit CSS asset files under the output directory.
- Discovered page CSS inputs selected by implicit
default pageor explicit@cssannotations are concatenated into generated page CSS files. Pagestyle {}CSS is appended to the same generated page CSS asset. - Page
js "./file.js"declarations are copied underassets/gowdk/pages/<page>/and linked only from that page as module scripts. Pagejs "./file.ts"declarations are transformed to.jsfiles in the same directory. Inline pagejs {}blocks emit deterministic files such asinline-gowdk.js. - Component
@cssfiles are emitted as scoped CSS assets, linked from generated pages, content-hashed, recorded ingowdk-assets.json, and served with immutable cache headers by generated binaries. Componentstyle {}CSS is emitted through the same scoped CSS path. - Component
js "./file.js"declarations are copied underassets/gowdk/components/<package>/<component>/and linked only from pages that use the component. Componentjs "./file.ts"declarations are transformed to.jsfiles in the same directory. Inline componentjs {}blocks emit deterministic files such asinline-gowdk.js. This first slice does not bundle JavaScript or follow import graphs. - Layout
style {}CSS is emitted as generated CSS and linked by pages that declare the layout. - Dynamic app routes with literal
paths {}declarations are expanded bygowdk build. - Literal dynamic route params can render in the current literal
view {}interpolation subset. - Literal
build {}data can render in the current literalview {}interpolation subset. - SPA page output composes declared layouts by replacing each applied
layout's single
<slot />placeholder before rendering the combined view source once. gowdk build --app <dir>writes a generated Go module that embeds the SPA output under<dir>/SPA.gowdk build --bin <file>requires--appand compiles that generated app into one local binary.- Generated apps include POST endpoint handlers for the first supported action subset on concrete SPA page paths.
- Generated apps pass one backend hook into
runtime/app.Handler; generated action and API dispatch are internal details behind that hook. - Generated app creation auto-detects supported action endpoints and supported
SSR routes from the parsed manifest used by
gowdk build --app, so the CLI does not need to manually register those handler hooks. - Generated apps include form input decoder functions that
preserve repeated values and reject unexpected fields inferred from direct
literal controls in same-page
g:postforms. - Named submit controls discovered in literal
g:postforms are included in the allowlist as submit-intent fields before unknown-field rejection; localtype="button"and reset controls are not included. - Generated action handlers cap request bodies before form parsing and return HTTP 413 for oversized submissions.
- Generated apps return HTTP 422 for missing or empty direct SPA
requiredfields when the action declaresvalid(input)?. - Generated build output emits
assets/gowdk/gowdk.jsonly for pages that use partial form metadata with fragment-producing actions. - Generated build output emits
assets/gowdk/islands/<Component>.jsfor stateful component instances that use the default generated JavaScript island runtime. Island roots carry compiler-owneddata-gowdk-islandmarkers, and generated island assets register idempotent browser mount hooks for initial load and partial-swap remounts plus destroy hooks for islands removed by partial swaps. The generated JavaScript is scoped to matching<gowdk-island>roots rather than hydrating the full page. Generated island assets carry a compact binding descriptor table and update collected bindings through per-binding functions for text, form values, checked state, classes, styles, attributes, conditionals, and lists; keyed list updates reuse existing DOM nodes byg:keyand remove stale keyed nodes. - In the default development build mode, generated JavaScript island assets are
accompanied by
assets/gowdk/islands/<Component>.js.mapsource map files that reference the component.gwdksource, are recorded ingowdk-assets.json, include first-slice component/client/view source span anchors, and are linked from the JS withsourceMappingURL.Build.Mode: gowdk.Productionomits those debug source map artifacts and comments and compacts generated island JavaScript by trimming formatting-only whitespace. - Generated build output emits
assets/gowdk/islands/<Component>.wasmplusassets/gowdk/islands/<Component>.wasm.jsfor normal calls to components that declare@wasm <package>, and for explicit call-site overrides that setg:island="wasm". When the component declares@wasm <package>, GOWDK runsGOOS=js GOARCH=wasm go buildfor that package and writes the compiled browser WASM module to the component asset path plusassets/gowdk/islands/wasm_exec.jsfor Go's browser runtime imports. Local packages are checked for browser-safe imports before build; server, process, and network packages such asnet/http,os/exec, anddatabase/sqlare rejected. A package that does not produce a WASM module or omits required ABI exports fails the build. Components without@wasmkeep the minimal placeholder module for the loader-shape slice and do not shipwasm_exec.js. The loader discovers matching island roots, builds the ADR-defined bootstrap object from state, props, emits, refs, and binding metadata, calls component-scoped WASM exports when present, captures host DOM events, and applies the supported validated patch commands for text, visibility, attribute, class, style, and emitted-event updates. - Generated apps can serve concrete and dynamic SSR pages in the supported
generated request-time slice. Dynamic route params are substituted into
generated SSR placeholders with request-time HTML escaping. Declared
load { => { field } }pages call same-package Go load functions namedLoad<PageID>withssr.LoadContextand replace declared load placeholders with escaped returned values. Load errors that wrapssr.RedirectErrorbecome no-store local redirects; other load failures use generated error-page output. - Generated embedded apps load optional
404.htmland500.htmlfrom the embedded build output and use those pages for not-found responses and generated SSR load failures. SSR routes can also declare@error "/errors/page.html"to use a generated route-local HTML error page for load failures, generated render failures, and route panics before falling back to500.html. - Generated SSR, action, and API request-time lanes recover panics before
response headers are written as no-store HTTP 500 responses without exposing
panic values. SSR route panics use a declared route-local
@errorpage when one is available. Action and API declarations can also use endpoint-local@error "/errors/name.html"pages for generated panic boundaries. - Generated apps can return partial fragment responses from
action handlers for
X-GOWDK-Partialrequests and standalonefragment Name GET "/path" "#target" { ... }routes. Standalone fragment bodies can expand known components at app generation time. If the source package exportsfunc Name(context.Context) (response.Response, error), the generated fragment handler calls that request-time hook instead of the static fallback. - Generated app action endpoint extraction rejects direct file inputs and
multipart
g:postforms. Uploads belong in user-owned API/server handlers. internal/gotypesresolves component prop/state structs through Go module import paths usinggo list,go/parser, andgo/types.runtime/responsedefines fragment responses with target and swap metadata for generated and future partial handlers./maps toindex.html./patientsmaps topatients/index.html.- Current asset names are stable and deterministic.
gowdk-assets.jsonrecords content hashes and cache policy for generated CSS/runtime assets and component-level@assetfiles. Generated CSS is minified and emitted with content-hashed filenames. Component@assetfiles are emitted with content-hashed filenames underassets/gowdk/components/. - Generated embedded apps skip local environment files, source maps, source files, VCS/dependency directories, and common temporary artifacts when copying build output into the embedded app.
- Generated embedded apps load
gowdk-assets.jsonfrom the embedded filesystem when present and expose the loaded asset count through/_gowdk/health.
Not implemented yet:
- Route params passed into imported Go
build {}functions. - Full page-aware third-party CSS processor selection beyond the current processor stylesheet and generated CSS asset support.
- Non-string props in inline
props {}blocks. - Arbitrary build-time statements beyond literal expression records and imported/same-package no-argument build data functions.
- Broader user Go type resolution beyond typed action decoders, user action logic, API handlers, and general fragment routes.
- Generated handlers beyond the supported action, API, fragment, and SSR load
signatures. Strict production builds diagnose missing or unsupported
action/API bindings with
backend_binding_required; migration builds must opt into--allow-missing-backendorBuild.AllowMissingBackendto emit explicit HTTP 501 stubs.
Compatibility Notes
Generated output is still pre-1.0. Public releases must document generated-output changes that can affect checked-in deploy recipes, generated app imports, route manifests, asset manifests, cache headers, or generated binary behavior.
The stable compatibility surface for v0.1 is intentionally narrow:
gowdk-routes.json,gowdk-assets.json, andgowdk-build-report.jsoninclude explicitversionfields.- Generated app entrypoints expose standard
net/httphandlers throughgowdkapp.Handler()andgowdkapp.ServeMux(). - Generated binaries serve selected embedded output and request-time routes from
the same build metadata used by
gowdk build --out. - Generated asset logical paths resolve through
gowdk-assets.json; consumers should not hard-code content-hashed filenames.
Generated source layout, helper function names, private package internals, and intermediate files under selected app/output directories may change between pre-1.0 releases unless a reference doc explicitly names them as public.
Target Artifacts
The target output can include:
- App-shell HTML for
spaandactionpages. - Route manifest JSON.
- Generated Go app/runtime adapter code.
- Generated action handlers and typed form decoders.
- Generated API handlers.
- Generated server fragment handlers.
- Optional SSR route handlers.
- CSS/plugin artifacts.
- Embedded asset manifest.
- A generated Go command for one-binary app serving.
Current Generated App
gowdk build --out dist --app .gowdk/app writes:
.gowdk/app/
go.mod
gowdkapp/
app.go
SPA/
index.html
gowdk-routes.json
gowdk-assets.json
gowdk-build-report.json
cmd/
server/
main.go
gowdk build --out dist --app .gowdk/app --bin dist/site then runs go build
for .gowdk/app/cmd/server and writes dist/site.
The generated gowdkapp package exposes Handler() (http.Handler, error) and
ServeMux() (*http.ServeMux, error) for net/http, Chi, Echo, Gin, and other
router integrations. The generated cmd/server entrypoint uses that same
handler, reads GOWDK_ADDR, defaults to 127.0.0.1:8080, serves GET and HEAD
requests, maps extensionless routes to nested index.html files, and does not
list directories. It exposes /_gowdk/health and adds
X-GOWDK-App, X-GOWDK-Module, and X-GOWDK-Instance-ID headers to responses.
Request-time action/API dispatch registers generated backend routes with
runtime/app.BackendRouter and passes the router hook into runtime/app;
older separate action/API hook fields remain a compatibility path for existing
generated apps.
It loads gowdk-assets.json, 404.html, 500.html, and route-local SSR
@error pages from the embedded build output filesystem when present.
Identity comes from GOWDK_APP_ID, GOWDK_MODULE_NAME, and
GOWDK_INSTANCE_ID; if no instance ID is provided, the app creates one at
process start from the module name, hostname, and a random token. It can also
serve auto-detected POST redirect handlers for the first supported action
subset and supported SSR/hybrid pages with or without declared load {}
identifier or dotted paths. SSR load functions can return safe local redirects with
ssr.RedirectTo/ssr.Redirect, and generated SSR load failures render the
route-local @error page when declared or the optional 500.html when
present.
Action handlers decode allowlisted form fields into named input wrappers,
cap request bodies before parsing, preserve repeated values, return HTTP 413
for oversized submissions, return HTTP 400 for unexpected fields, and return
HTTP 422 for generated required-field validation failures. Direct file inputs
and multipart action forms are rejected before generated app output because
uploads are user-owned API/server behavior. For
partial requests, generated handlers can return the first parsed action
fragment matching X-GOWDK-Target and expose fragment target/swap metadata in
headers. Feature-bound generated action handlers can call no-input,
form.Values, typed value, and typed pointer same-package Go handlers; typed
handlers decode through generated normal Go functions built from Go AST input
struct metadata. When Build.CSRF.Enabled is true, generated apps read a
signing secret from Build.CSRF.SecretEnv or GOWDK_CSRF_SECRET, inject hidden
CSRF token fields into served HTML POST forms, validate action POSTs before
generated decoding or user handlers run, and return HTTP 403
invalid csrf token with Cache-Control: no-store for invalid tokens. The
generated app does not run user-defined validation beyond handler logic,
handle uploads, stream hybrid responses, refresh hybrid server data in place, or
perform non-HTTP revalidation today.
Generated app source is an output artifact and sits downstream of feature
packages. Feature packages may import stable public GOWDK runtime/addon
packages, but must not import generated gowdkapp packages, generated
cmd/server packages, build output directories, or any path under the selected
generated app directory. This keeps the dependency direction one-way: generated
adapters import user feature packages and call exported handlers.
Current SPA Route Manifest
gowdk build writes gowdk-routes.json at the output root:
{
"version": 1,
"routes": [
{
"page": "home",
"route": "/",
"path": "index.html"
}
]
}
The path field is slash-separated and relative to the selected output
directory. Dynamic app routes are recorded once for each generated concrete
route, for example /blog/{slug} with => { slug: "hello-gowdk" } is recorded
as /blog/hello-gowdk.
Current App Asset Manifest
gowdk build writes gowdk-assets.json at the output root:
{
"version": 1,
"files": {
"assets/app.css": "assets/app.7ada5a1234b1.css"
},
"hashes": {
"assets/app.css": "sha256:..."
},
"cache": {
"assets/app.css": "public, max-age=31536000, immutable",
"index.html": "public, max-age=120"
}
}
The files map resolves logical asset names to slash-separated paths relative
to the selected output directory. hashes records SHA-256 content hashes for
generated assets, and cache records the HTTP cache policy generated binaries
should apply when serving generated assets or route HTML files. The current
implementation records CSS files emitted by CSS processors, generated page CSS
files, partial runtime assets, generated island runtime assets, generated island
source maps, and page-level @cache policies for generated SPA HTML. It does
not record configured stylesheet URLs that were not written by the build.
Current Build Report
gowdk build writes gowdk-build-report.json at the output root:
{
"version": 1,
"mode": "build",
"outputDir": "dist/site",
"events": [
{
"level": "info",
"stage": "complete",
"kind": "build_complete",
"message": "SPA build completed"
}
]
}
The report records build-output generator stages even when the CLI is not run with
--debug. Debug mode only mirrors the structured events to stderr for humans.
Planned Server Defaults
Generated servers must include HTTP timeouts, header/body limits, method handling, safe app asset serving, and logs that do not expose secrets or sensitive form values.
Ownership And Licensing
Generated output ownership and license policy are documented in ../../LICENSE
and ../engineering/generated-code-policy.md.