Skip to content
10 changes: 6 additions & 4 deletions docs/compiler/browser-compiler.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ tries a direct WASM instantiate path and falls back to Go runtime imports when a
compiled Go module needs them.

Declared browser-side Go packages must produce a browser WASM module and export
the component-scoped ABI entrypoints:
the component-scoped ABI entrypoints with the current `func() uint32`
signature:

```go
//go:wasmexport GOWDKMountCounter
Expand All @@ -118,9 +119,10 @@ func GOWDKHandleCounter() uint32 { return 0 }
func GOWDKDestroyCounter() uint32 { return 0 }
```

The generated loader passes a bootstrap object containing component name, state,
props, emits, refs, and compiler-owned binding metadata. Returned patch lists
may use `setText`, `setAttr`, `removeAttr`, `toggleClass`, `setStyle`,
The generated loader passes a `gowdk-wasm-island-v1` bootstrap object containing
component name, state, props, emits, refs, and compiler-owned binding metadata.
Event and destroy payloads carry the same ABI version. Returned patch lists may
use `setText`, `setAttr`, `removeAttr`, `toggleClass`, `setStyle`,
`setHidden`, `replaceList`, and `emit`; unsupported patch operations are
rejected with a console error. Missing required exports and startup failures are
reported to the browser console instead of silently disabling the island.
Expand Down
10 changes: 10 additions & 0 deletions docs/compiler/build-report.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ Current stages are:
- `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_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.

## CLI Debug Output

`gowdk build --debug` prints a readable version of this report to stderr while
Expand Down
24 changes: 15 additions & 9 deletions docs/compiler/generated-output.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,12 @@ Implemented today:
exports fails the build. Components without `wasm` keep the minimal
placeholder module for the loader-shape slice and do not ship `wasm_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.
object from ABI version `gowdk-wasm-island-v1`, 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. The
build report records the Go toolchain version used for generated
`wasm_exec.js` runtime 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
Expand Down Expand Up @@ -336,6 +338,9 @@ as `/blog/hello-gowdk`.
"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"
Expand All @@ -345,11 +350,12 @@ as `/blog/hello-gowdk`.

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
generated assets, `sizes` records generated asset byte counts, 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, 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
Expand Down
14 changes: 10 additions & 4 deletions docs/compiler/manifest.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,16 +147,22 @@ page-level cache policies:
"files": {
"assets/app.css": "assets/app.7ada5a1234b1.css",
"assets/gowdk/islands/Counter.js": "assets/gowdk/islands/Counter.js"
},
"sizes": {
"assets/app.css": 1204,
"assets/gowdk/islands/Counter.js": 4096
}
}
```

Keys are stable logical asset names and values are emitted slash-separated paths
relative to the selected output directory. Generated CSS values include a
content hash in the filename after minification. The `cache` map may also
include route HTML paths such as `index.html`; those route entries do not need
to appear in `files`. Configured stylesheet links are not included unless GOWDK
emits the referenced file.
content hash in the filename after minification. The optional `hashes`,
`cache`, and `sizes` maps record content hashes, generated cache policy, and
byte size for emitted assets. The `cache` map may also include route HTML paths
such as `index.html`; those route entries do not need to appear in `files`.
Configured stylesheet links are not included unless GOWDK emits the referenced
file.

## Planned Manifest Work

Expand Down
19 changes: 14 additions & 5 deletions docs/engineering/decisions/0004-production-wasm-island-abi.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,17 @@ Entrypoint naming:
- The generated loader looks for exported functions named
`GOWDKMount<Component>`, `GOWDKHandle<Component>`, and
`GOWDKDestroy<Component>`.
- Each required export must currently have the WASM signature produced by Go
`func() uint32`: no parameters and one `i32` result.
- Exported names are component-scoped to avoid a registry in the first slice.
- Missing required exports are compile or load diagnostics, not silent no-ops.

Bootstrap ABI:

- The loader passes one JSON object to `GOWDKMount<Component>`.
- The object contains `component`, `state`, `props`, `emits`, `refs`, and
`bindings`.
- The object contains `abiVersion`, `component`, `state`, `props`, `emits`,
`refs`, and `bindings`.
- The current `abiVersion` is `gowdk-wasm-island-v1`.
- `state` is the same JSON object used by JS islands.
- `props` contains initial prop values and reactive prop expression names.
- `bindings` is the compiler-owned table of text, attribute, class, style,
Expand All @@ -47,7 +50,8 @@ Bootstrap ABI:
Event ABI:

- DOM events are captured by the JS host.
- The host calls `GOWDKHandle<Component>` with `{ event, binding, detail }`.
- The host calls `GOWDKHandle<Component>` with
`{ abiVersion, component, event, binding, detail }`.
- `event` is the DOM event name or component event name.
- `binding` is the compiler-assigned binding ID.
- `detail` contains scalar event payload fields.
Expand All @@ -66,14 +70,17 @@ Lifecycle ABI:

- The host calls `GOWDKMount<Component>` once per island root.
- The host calls `GOWDKDestroy<Component>` when the island root is removed or on
pagehide before unload.
pagehide before unload, with `{ abiVersion, component, state }`.
- Future effect cleanup uses explicit patch/lifecycle return values rather than
ambient goroutines.

Asset strategy:

- Component WASM stays at `assets/gowdk/islands/<Component>.wasm`.
- The loader stays at `assets/gowdk/islands/<Component>.wasm.js`.
- Declared Go WASM packages ship `assets/gowdk/islands/wasm_exec.js` from the
Go toolchain used for the build; the build report records that Go version on
the `asset_size` event for the runtime asset.
- Multiple component instances share the same WASM module asset but receive
separate bootstrap objects.
- JS and WASM islands may coexist on the same page.
Expand Down Expand Up @@ -116,9 +123,11 @@ Asset strategy:
## Implementation

- GOWDK builds declared `wasm` packages with `GOOS=js GOARCH=wasm`.
- Generated loader payloads use ABI version `gowdk-wasm-island-v1`.
- Built WASM artifacts are rejected unless they export
`GOWDKMount<Component>`, `GOWDKHandle<Component>`, and
`GOWDKDestroy<Component>`.
`GOWDKDestroy<Component>` with the required no-parameter, `uint32` result
signature.
- The generated loader passes the bootstrap object, applies the defined patch
operations, rejects unknown patch operations through a console error, and
supports JS/WASM island coexistence on the same page.
Expand Down
62 changes: 62 additions & 0 deletions docs/engineering/m8-components-client-language.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# M8 Components / Client Language Audit

This audit records the M8 closure criteria for component contracts, the bounded
client language, SPA navigation, and WASM islands. It separates implemented
behavior from explicit deferrals so future work does not depend on issue-body
status.

## Implemented Slices

- Component props: scalar literal props, imported Go struct props, scalar
defaults, same-named `{...props}` forwarding, `target:source` prop renaming,
collision diagnostics, and generated render tests cover #17, #93, #94, and
#368.
- Slots: default, named, and scoped slots are the supported reusable-markup
primitive; first-class snippet/render values remain deferred. This covers #16
and #95.
- Events and exports: typed child-to-parent emits and typed component exports
are generated client contracts with teardown behavior, covering #96 and #369.
- Bindable child state: component `g:bind:<ExportedState>={ParentState}`
requires an exported child state field, syncs parent-to-child through reactive
props, syncs child-to-parent through typed exports, avoids prop/export echo
loops, and has generated-output plus browser coverage. This covers #365.
- Client reactivity: component state, computed values, dependency ordering,
cycle diagnostics, lifecycle/effect cleanup, safe refs, form bindings,
`g:if`, `g:for`, keyed list updates, list built-ins, and bounded async helpers
cover #18, #30, #97, #98, #99, #100, and #101.
- Shared state: page-scoped stores, explicit component `use`, local/session
persistence, shape invalidation, and SPA-navigation hydration cover #19.
- SPA navigation: internal-link interception, route shell fetch/swap, prefetch,
scroll/focus restoration, loading/error events, and asset-size reporting cover
#370.
- Generated form validation: direct literal action inputs receive derivable
numeric HTML attributes and partial form POSTs run browser pre-validation
before network submission, covering #174. Server validation remains
authoritative.
- WASM islands: component-level WASM stays opt-in, uses ABI version
`gowdk-wasm-island-v1`, validates required export names and signatures,
rejects browser-unsafe imports, records `wasm_exec.js` Go version in build
reports, and has loader/browser coverage for mount, event, patch, emit, and
cleanup. This covers #29, #64, and #371 for the production ABI slice.

## Explicit Deferrals

- Component recursion is rejected, including direct and transitive cycles, to
avoid unbounded build-time rendering. This closes #366 as an intentional
policy.
- Dynamic component selection is rejected; component calls must name a compiler
known component directly or through an explicit `use` alias. This closes #367
as an intentional policy.

## Verification Surface

Run the full repository gates before release:

```sh
go test ./...
go build ./cmd/gowdk
scripts/test-go-modules.sh
```

Focused M8 checks live primarily in `internal/view`, `internal/clientlang`,
`internal/clientrt`, `internal/buildgen`, and `internal/appgen`.
2 changes: 1 addition & 1 deletion docs/engineering/release-plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,7 @@ Every 0.x minor release must have:
struct prop support as contracts become stable.
- [ ] Add prop validation diagnostics.
- [ ] Add named slots and scoped slots only when syntax is stable.
- [ ] Add child-to-parent events, typed event payloads, bindable state, mount,
- [x] Add child-to-parent events, typed event payloads, bindable state, mount,
update, cleanup, real `g:if`, `g:for`, keyed `g:for`, keyed DOM updates,
recursion policy, and dynamic component policy.
- [ ] Add component snapshot and browser behavior tests.
Expand Down
8 changes: 4 additions & 4 deletions docs/language/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ interpolation in views, Go-typed component props/state contracts, first-slice
generated JavaScript islands for stateful components, component-level `wasm`
island asset emission, formatting, diagnostics, manifest output, build output
for simple SPA pages/components, generated partial fragment responses for
embedded apps, and LSP/editor integration. It does not yet parse non-string
inline props, full typed action semantics, API request/response bodies, broad
local client-side reactivity, or full semantic/type analysis outside the
component contract and inline package-go-block slices.
embedded apps, and LSP/editor integration. It does not yet implement full typed
action semantics, API request/response
bodies, broad local client-side reactivity, or full semantic/type analysis
outside the component contract and inline package-go-block slices.

## Current Files

Expand Down
5 changes: 5 additions & 0 deletions docs/language/actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,11 @@ Current form behavior is intentionally narrow and literal-analysis driven:
route.
- Field inference reads direct `input`, `textarea`, `select`, and named submit
controls with literal `name` attributes.
- When bound Go action input metadata is available, direct literal numeric
`<input name="...">` controls can receive missing browser attributes derived
from integer field types: `type="number"`, `inputmode="numeric"`, unsigned
`min="0"`, and sized integer `min`/`max` bounds. Existing author attributes
are preserved.
- Named submit controls such as `<button name="intent" value="save">` and
`<input type="submit" name="intent">` are treated as explicit submit-intent
fields before unknown-field rejection. Non-submitting controls such as
Expand Down
Loading