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.sitemap.xmlandrobots.txtare emitted only whenaddons/seois enabled. The sitemap includes public static andpaths {}-expanded SPA routes plus configured extra URLs; request-time and guardless default-denied pages are excluded and listed in the build report.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 explicitcssmetadata declarations 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 pages whose composed view recursively calls the component, 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. - Imported and same-package Go build functions can return
Tor(T, error); dynamicpaths {}output can pass route params through onegowdk.BuildParamsargument. - 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 embedded and backend-only app packages expose
RegisterMiddleware(runtime/app.Middleware). Registered middleware wraps the full generated app handler chain in registration order before static serving, health checks, generated headers, and request-time route dispatch. - When
auth.Addon(auth.Options{...})is configured, generated embedded and backend-only app startup configuresaddons/authsessions, registers the defaultauth.requiredguard, and wires the session provider for nativerole:/permission:guards. App login/logout handlers can useauth.DefaultSessions()to issue or clear the same signed session cookie. - Generated embedded and backend-only app packages expose
App() (*runtime/app.Application, error)for full generated-binary startup.App()shares one generated identity across the web handler and lifecycle service context, collects configured lifecycle services, and exposes the generated mux to serviceMounthooks. gowdk inspect go-bindingsreports Go binding status for actions, APIs, fragments, SSR load functions, build-time Go calls, and web command/query references.gowdk generate stubscan write missing action/API handler stubs as normal Go code beside the owning source package.- Query-owned realtime subscription regions render
data-gowdk-query,data-gowdk-subscribe, and validateddata-gowdk-subscribe-typemarkers afterg:subscribevalidation. Generated apps mount/_gowdk/realtime/events, exposeRealtimeEventsPathandRegisterRealtimeFanout, and dispatch command-emitted presentation events to subscription-filtered SSE fanout. Generatedgowdk.jsconnects subscribed pages to the stream and applies explicitreplaceHTMLpatches to the matching query-owned region. - 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. - Framework-owned browser runtime sources are authored as
.jsfiles underinternal/clientrt/assets/and embedded withgo:embed; generated output helpers only perform narrow placeholder substitution for component names, page IDs, asset paths, and WASM export names. - Generated build output emits one shared JavaScript island runtime at
assets/gowdk/islands/island.jsplus small package-scoped registration stubs such asassets/gowdk/islands/<package>/<Component>.jsfor stateful component instances that use the default generated JavaScript island runtime. Island roots carry compiler-owneddata-gowdk-islandmarkers plus a package-qualified component id, and the shared runtime registers 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. The shared runtime carries a compact binding descriptor table and updates 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:key, remove stale keyed nodes, and toggle compiler-ownedgowdk-transition-*/gowdk-animate-*classes wheng:transitionorg:animateare present. - Page store seed JSON embedded in compiler-owned
<script type="application/json">tags escapes literal<as\u003c, so store data cannot terminate the script element or enter HTML escaped-script parser states. - In the default development build mode, generated JavaScript island stubs are
accompanied by
assets/gowdk/islands/<package>/<Component>.js.mapsource map files that reference the component.gwdksource, are recorded ingowdk-assets.json, include the component registration source span, and are linked from the stub JS withsourceMappingURL.Build.Mode: gowdk.Productionomits those debug source map artifacts and comments and compacts generated island JavaScript.Build.ObfuscateAssetsorgowdk build --obfuscate-assetsenables stronger deterministic minification/identifier shortening for compiler-owned generated browser JavaScript in production builds. - Generated build output emits package-scoped island assets:
assets/gowdk/islands/<package>/<Component>.jsstubs for generated JavaScript islands, andassets/gowdk/islands/<package>/<Component>.wasmplusassets/gowdk/islands/<package>/<Component>.wasm.jsfor normal calls to components that declarewasm <package>or explicit call-site overrides that setg:island="wasm". When the component declareswasm <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 withoutwasmkeep 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 ABI versiongowdk-wasm-island-v1, state, props, emits, refs, binding metadata, and current page-store values, calls component-scoped WASM exports when present, decodes Go-styleuint32JSON result pointers, captures host DOM events, writes returned store values back to page stores, and applies the supported validated patch commands for text, visibility, attribute, class, style, and emitted-event updates. The build report records the Go toolchain version used for generatedwasm_exec.jsruntime assets. - 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
server { => { 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. - Request-time SSR and hybrid pages compose declared layouts before rendering the generated response, and load placeholders are shared across page and layout markup. Generated route metadata records the layout stack.
- 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 declareerror "/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-localerror "/errors/name.html"pages for generated panic boundaries. - Generated action, API, fragment, contract, SSR load, and addon 5xx error
responses hide ordinary returned error details from clients. Apps can expose
an intentional client message by returning
response.HandlerErrorwith an explicitMessage; generated 4xx handler errors keep their application message contract. - Generated apps can return partial fragment responses from
action handlers for
X-GOWDK-Partialrequests and standalonefragment Name GET "/path" "#target" { ... }routes. Standalone fragment routes can be concrete or dynamic; dynamic fragment route params are matched withruntime/routeand exposed to hooks throughruntime/app.Params(ctx)andruntime/app.TypedParams(ctx). 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/compilerresolves same-package action, API, fragment, and SSR load handlers throughgo/packagesandgo/types, so build tags, renamed imports, type aliases, and package load errors follow ordinary Go package semantics.internal/gotypesresolves component prop/state structs through Go module import paths usinggo list,go/parser, andgo/types.addons/partialexposes generated fragment and swap helpers. The underlyingruntime/responseenvelope carries 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-levelassetfiles. Generated CSS is minified and emitted with content-hashed filenames. Componentassetfiles are emitted with content-hashed filenames underassets/gowdk/components/. - CSS link order is deterministic: configured global links, processor global links, processor page-specific links, generated page CSS, layout CSS, then scoped component CSS for components used by the page.
- 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:
- 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 build data functions returning
Tor(T, error). - 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 full process startup through
gowdkapp.App()plus standard request-onlynet/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 processor addon 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
sitemap.xml # only with addons/seo
robots.txt # only with addons/seo
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 App() (*runtime/app.Application, error) for generated binary startup plus Handler() (http.Handler, error) and
ServeMux() (*http.ServeMux, error) for request-only net/http, Chi, Echo,
Gin, and other router integrations. It also exposes RegisterMiddleware for
app-owned net/http middleware that should be installed before Handler() or
ServeMux() constructs the generated handler. The generated cmd/server
entrypoint calls App(), reads GOWDK_ADDR, defaults to 127.0.0.1:8080,
serves GET and HEAD requests, applies http.Server defaults of
ReadHeaderTimeout: 5s, ReadTimeout: 10s, WriteTimeout: 30s,
IdleTimeout: 60s, and MaxHeaderBytes: 1 MiB, and hands the server to
runtime/app.Run for service supervision, SIGINT/SIGTERM handling, and
graceful shutdown. It 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.
When Build.SecurityHeaders.Enabled is true, generated apps also pass the
configured header map into runtime/app so every response path emits those
headers.
Request-time action/API/fragment dispatch registers generated backend routes with
runtime/app.BackendRouter and passes the router hook into runtime/app.
Generated action/API body caps default to 1 MiB and use Build.BodyLimits
overrides when configured. 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 server {}
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. Generated action and web-command POST handlers enable CSRF by
default: 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 POSTs before generated decoding or user handlers run, and
return HTTP 403 invalid csrf token with Cache-Control: no-store for invalid
tokens. Set Build.CSRF.Disabled only for an intentional opt-out. 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"
}
],
"endpoints": [
{
"kind": "action",
"directive": "act",
"method": "POST",
"route": "/login",
"page": "login",
"symbol": "Login",
"handler": "actions.LoginLogin",
"guards": ["public"],
"csrf": true
}
]
}
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. The optional endpoints array records generated
request-time action, API, fragment, command, and query adapter routes; it does
not point at static files. Dynamic endpoint routes also include
dynamicParams and typed routeParams when route parameters are declared.
Current App Asset Manifest
gowdk build writes gowdk-assets.json at the output root:
{
"version": 2,
"files": {
"assets/app.css": "assets/app.7ada5a1234b1.css"
},
"hashes": {
"assets/app.css": "sha256:..."
},
"sizes": {
"assets/app.css": 1204
},
"cache": {
"assets/app.css": "public, max-age=31536000, immutable",
"index.html": "public, max-age=120"
},
"obfuscated": {
"assets/gowdk/gowdk.js": true
}
}
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, sizes records generated asset byte counts, cache records
the HTTP cache policy generated binaries should apply when serving generated
assets or route HTML files, and obfuscated marks compiler-owned generated
browser assets transformed by production asset obfuscation. 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, WASM island assets, 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.