GOWDK does not compile arbitrary Go or JavaScript for the browser by default. The current browser-facing output slices are:
- Partial form enhancement runtime emitted as
assets/gowdk/gowdk.js. - Generated JavaScript islands for stateful components.
- Component-level WASM island asset emission for components that declare
wasm, withg:island="wasm"still supported as a call-site override.
Framework-owned browser runtime source lives under internal/clientrt/assets/
as ordinary .js files embedded with go:embed. Buildgen consumes those
sources through small template helpers for component names, page IDs, asset
paths, and WASM export names; it should not grow new multi-hundred-line
JavaScript raw strings in Go files.
Partial Runtime
When a page uses a fragment-producing action form with g:target and g:swap,
SPA builds emit the client runtime:
<form g:post={Refresh} g:target="#patients" g:swap="innerHTML">
<input name="query" />
<button>Refresh</button>
</form>
The compiler lowers this to normal form attributes plus data-gowdk-*
metadata and emits a deferred script tag for assets/gowdk/gowdk.js.
The runtime:
- Submits enhanced forms with
X-GOWDK-Partial,X-GOWDK-Target, andX-GOWDK-Swapheaders. - Applies
innerHTMLorouterHTMLswaps. - Reloads the current page when the response carries
X-GOWDK-Reload: 1. - Dispatches
gowdk:before-request,gowdk:after-swap, andgowdk:request-error. Failed enhanced requests include responsestatus,body, andresponsein event detail when available. - Toggles
aria-busyon the submitting form. - Restores focus by matching the active element's
idornamewhen possible. - Calls generated island destroy and mount hooks around replaced island DOM.
JavaScript Islands
Stateful components use generated JavaScript by default:
component Counter
import ui "github.com/acme/app/ui"
state ui.CounterState = ui.NewCounterState()
client {
fn Increment() {
Count++
}
}
view {
<button g:on:click={Increment()}>{Count}</button>
}
The compiler validates a small Go-like client subset and emits browser
JavaScript under assets/gowdk/islands/: one shared island.js runtime plus
small package-scoped component registration stubs.
Supported island syntax is documented in docs/language/syntax.md,
docs/language/markup.md, and docs/language/components.md. The subset
includes scalar handler parameters, scalar locals, field assignment,
increment/decrement, arithmetic, comparisons, boolean logic, conditional
expressions, computed values, lifecycle/effect blocks, refs, simple bindings,
conditionals, keyed list rendering, and compiler-owned list/string/numeric
built-ins.
Unsupported today:
- Arbitrary Go syntax in the browser.
- Arbitrary JavaScript.
- Loops in client handlers.
- Event object reads.
- Broad date/time/browser APIs.
- Recursive helper functions.
- User-defined browser runtime imports.
Component-Level WASM Islands
Components declare WASM at the component level:
component Counter
wasm ./browser/counter
view {
<button>Counter</button>
}
<Counter />
When wasm points to a local package, GOWDK builds that package with
GOOS=js GOARCH=wasm. The package must be browser-safe and cannot import
server/process/network packages such as net/http, os/exec, database/sql,
raw syscall, plugin, or unsafe. Declared Go WASM island packages also
ship assets/gowdk/islands/wasm_exec.js; the generated component loader first
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 with the current func() uint32
signature:
import gowdkwasm "github.com/cssbruno/gowdk/runtime/wasm"
//go:wasmexport GOWDKMountCounter
func GOWDKMountCounter() uint32 {
return gowdkwasm.ReturnResult(gowdkwasm.Result{Patches: []any{}})
}
//go:wasmexport GOWDKHandleCounter
func GOWDKHandleCounter() uint32 { return gowdkwasm.ReturnPatches([]any{}) }
//go:wasmexport GOWDKDestroyCounter
func GOWDKDestroyCounter() uint32 { return gowdkwasm.ReturnPatches([]any{}) }
The generated loader passes a gowdk-wasm-island-v1 bootstrap object containing
component name, state, props, emits, refs, compiler-owned binding metadata, and
the current values of any page stores declared with use. Event and destroy
payloads carry the same ABI version. Go exports can read the current payload and
return JSON through runtime/wasm; the loader accepts either a legacy patch
array or { patches, stores }, writes returned store values back to page stores,
and rejects unsupported patch operations with a console error. Missing required
exports and startup failures are reported to the browser console instead of
silently disabling the island.
Normal calls to a component with wasm use the WASM island runtime. If a
component is called with g:island="wasm" and no wasm package is declared,
GOWDK emits the current placeholder module plus loader shape.
See examples/components/wasm/ for a runnable component-level WASM ABI example
that emits the component .wasm, host loader, and wasm_exec.js assets.
Production Mode
Build.Mode affects generated island assets:
Build: gowdk.BuildConfig{
Mode: gowdk.Production,
Output: "dist/site",
}
Development mode emits JavaScript island source maps. Production mode omits
.js.map artifacts and sourceMappingURL comments and compacts generated
island JavaScript. Build.ObfuscateAssets or gowdk build --obfuscate-assets
enables stronger deterministic minification/identifier shortening for
compiler-owned generated browser JavaScript in production builds.