Skip to content

cssbruno/GoWDK

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

682 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

GoWDK logo

GoWDK

CI Release Go Report Card Go Reference

GoWDK is a Go-first full web app platform: write pages and components in .gwdk files that live next to your Go packages, and ship the whole app — static pages, backend endpoints, SSR, typed contracts — as one Go binary.

No JavaScript application stack required. No reflection or template engine at request time. Your logic stays in Go.

Status: experimental 0.x release. Public contracts can still change. Not production-ready.

Website warning: the public project page is not updated yet and is currently only a placeholder. Treat this README and the docs in this repository as the current source of truth.

Install

go install github.com/cssbruno/gowdk/cmd/gowdk@latest

Or use the install script:

curl -fsSL https://raw.githubusercontent.com/cssbruno/GoWDK/main/scripts/install.sh | sh

Pin the current CLI release:

GOWDK_VERSION=v0.6.1 GOWDK_INSTALL_DIR="$HOME/.local/bin" \
  sh -c "$(curl -fsSL https://raw.githubusercontent.com/cssbruno/GoWDK/main/scripts/install.sh)"

Build from source:

git clone https://github.com/cssbruno/GoWDK.git
cd GoWDK
go build ./cmd/gowdk
./gowdk version

Quickstart: Single-Page Server

Create a one-page app, build its generated server, and run the binary:

gowdk init --tests --template site ./hello-gowdk
cd ./hello-gowdk
gowdk build
./bin/site

Open http://127.0.0.1:8080/. A minimal page:

package pages

use widgets "components"

route "/"
guard public

build {
  => { title: "GoWDK ships apps" }
}

view {
  <main>
    <h1>{title}</h1>
    <p>A .gwdk page compiled into an embedded Go server.</p>
    <widgets.Counter />
  </main>
}

Add local reactivity:

// ui/counter.go
package ui

type CounterState struct {
	Count int `json:"count"`
}

func NewCounterState() CounterState {
	return CounterState{Count: 0}
}
// components/counter.cmp.gwdk
package components

import ui "github.com/acme/hello-gowdk/ui"

component Counter

state ui.CounterState = ui.NewCounterState()

client {
  computed Label string {
    if Count == 0 {
      return "Start"
    }
    return string(Count)
  }

  func Increment() {
    Count++
  }

  func Reset() {
    Count = 0
  }
}

view {
  <section>
    <p class:active={Count > 0}>{Label}</p>
    <button g:on:click={Increment()}>Add</button>
    <button g:if={Count > 0} g:on:click={Reset()}>Reset</button>
  </section>
}

Replace github.com/acme/hello-gowdk/ui with your app module path.

CLI at a Glance

"Inspectable" is not just a slogan — the CLI exposes every stage of the pipeline. Run gowdk with no arguments for full flags.

Build and run

Command What it does
gowdk init Scaffold a starter project (--template site|minimal, --tests)
gowdk build Compile .gwdk into static output, a generated Go app, a single binary, optional Docker files, or WASM (--out, --app, --bin, --docker, --wasm, backend variants)
gowdk dev Build, serve, rebuild on change, live-reload browsers, show an error overlay
gowdk preview Build and serve a local deploy preview
gowdk serve Serve already-generated build output

Inspect and debug

Command What it does
gowdk check Parse and validate, with --json and --warnings-as-errors
gowdk fix Apply registered safe fixes for diagnostics (--dry-run, --code)
gowdk explain <code> Explain a diagnostic code and its next steps
gowdk doctor Check local environment and project health
gowdk audit Derive security posture, evaluate baseline/declared policies, and optionally emit/run audit tests (--json for CI)
gowdk inspect ir / tree / endpoint-graph / go-bindings Print validated compiler IR, source-linked node tree, endpoint dispatch graph, or Go binding report JSON
gowdk manifest / routes / sitemap Print validated manifest, route/endpoint metadata, or editor site-map JSON
gowdk tokens Print raw language tokens for a file
gowdk fmt Format .gwdk sources (--write)

Contracts and tooling

Command What it does
gowdk generate stubs Write conservative missing action/API Go handler stubs next to their owning source package
gowdk contracts / graph / trace / list Print contract registration metadata, the command/event graph, a single contract trace, or filtered lists of commands/queries/events/jobs
gowdk add <addon> Wire an optional addon into gowdk.config.go (add --list for addable built-ins, add --list --registry for metadata; add seo requires --base-url)
gowdk lsp Start the language server over stdio

Design

.gwdk sources move through an explicit pipeline: parse → AST → validation → a typed intermediate representation → code generation. Every stage is observable from the CLI (tokens, check, inspect ir, inspect tree, inspect endpoint-graph, manifest), and the generators emit three kinds of output from the same IR: static HTML/CSS/asset bundles, generated Go adapters (net/http routes, form decoders, guards), and browser islands (JS and Go js/wasm, with source maps in development and optional production obfuscation for compiler-owned JS). Diagnostics come from a central registry with stable codes — gowdk explain <code> documents each one, and error output redacts secrets quoted from source.

How responsibility is split, and the opinions behind it:

  • .gwdk files declare pages, components, layouts, routes, views, build data, browser behavior hooks, and endpoint metadata.
  • Normal Go packages own handlers, domain logic, auth, persistence, contracts, jobs, integration events, and production validation.
  • The compiler parses .gwdk, validates contracts, lowers to inspectable IR, and emits HTML, assets, manifests, build reports, and generated Go adapters.
  • Generated Go is runtime wiring: net/http routes, form decoders, response envelopes, CSRF checks, fragments, SSR/load calls, guards, rate limits, and contract web adapters.
  • Build-time SPA/static output is the default page lane. load {} and go ssr {} opt pages into request-time rendering. Actions, APIs, and fragments are request-time endpoints without forcing full-page SSR.
  • Generated browser code is compiler-owned enhancement for SPA navigation, partial form posts, fragments, local islands, and WASM mounts. User JS, TypeScript, npm assets, and framework interop stay explicit and page-scoped.
  • Runtime core stays dependency-light. Framework adapters, Tailwind, Redis, NATS, WebSocket fanout, and similar integrations live in optional addons or nested modules.
  • Unsupported source should fail with diagnostics before generated output gets clever or surprising.

What Works Today

This table describes the current demoable 0.x slice. Status levels:

  • Works — the listed path works end-to-end today.
  • Works, contract unstable — the listed path works end-to-end, but the public contract is still pre-1.0 and the remaining limits are tracked in the hardening backlog.
  • Early — a real but narrower slice works; expect missing cases.
Surface Status Works Today Current Limit Docs Example
Static build output Works gowdk build --out emits HTML, route metadata, asset metadata, build reports, and OpenAPI/AsyncAPI inspection reports for simple build-time pages. Generated output is still pre-1.0. CLI Pages
Dynamic SPA paths Early Dynamic SPA routes can be expanded from the first supported literal paths {} subset. Dynamic SPA routes need paths {} unless the page uses request-time rendering. Routing Blog
Build-time Go data Early Literal build records and supported no-argument Go build functions can feed SPA rendering. Arbitrary build-time Go statements and broader data lifecycles are not stable. Data Go interop
Actions Works, contract unstable Generated apps can serve typed POST action handlers, decode supported form inputs, validate request shape, return redirects/fragments, and opt into CSRF. File uploads, multipart generated forms, and domain validation stay in user-owned Go handlers. Actions Login
APIs Works, contract unstable Feature-bound API handlers can be generated for supported signatures; public helpers cover strict JSON body decoding, typed query values, and JSON response envelopes. Generated typed API signatures and broader examples remain planned. API API
Fragments Works, contract unstable Partial form submissions and standalone fragment routes can return server fragments and remount local islands. Richer fragment rendering and broader local client behavior are still hardening work. Partials Fragments
SSR Works, contract unstable Pages with load {} or go ssr {} can build request-time handlers when the SSR addon is enabled. Typed route-param accessors, lifecycle docs, and error/cache contracts need more hardening. SSR SSR
Hybrid Early Hybrid request-time route metadata and generated request-time pages exist for the supported slice. The public hybrid source contract, streaming, and data refresh policy are not stable. Hybrid Hybrid
Components Works, contract unstable Components support imported contracts, slots, scoped CSS/assets, first local client behavior, and generated island assets. Page stores can opt into localStorage/sessionStorage persistence with persist "local"/persist "session". Non-string props, richer slots/events, real g:if/g:for, lifecycle cleanup, dependency diagnostics, and store persistence for WASM islands are planned. Components Components
WASM islands Early Component-level wasm and page-level go client {} emit Go js/wasm browser assets for supported fixtures; build-time validation checks browser-safe imports and ABI exports, and browser tests cover mount, event, patch, emit, destroy, and invalid patch rejection. User-code runtime validation beyond the current patch contract remains planned. Components WASM example
CSS/assets Works, contract unstable CSS processors, page CSS, scoped component CSS, component assets, asset manifests, content-hashed filenames, optional production obfuscation for compiler-owned JS, and optional Tailwind wrapper exist. CSS processor contracts and optional dependency boundaries need hardening. CSS CSS
One-binary output Works, contract unstable gowdk build --app --bin can generate and compile an embedded Go server for supported SPA/backend/SSR slices, --docker emits a minimal non-root Docker context beside the binary, and CI starts the embed example binary to verify health plus embedded page serving. Runtime operations, richer Docker target config, and split/backend-only deploys are still expanding. Deployment Embed
Generated app WASM Early gowdk build --app --wasm compiles the generated app into a Go js/wasm deploy artifact, and CI verifies the emitted module header. Host runtime/loader integration is deploy-platform owned; this is separate from component-level WASM islands. Deployment Embed
Contracts Works, contract unstable Runtime contracts support typed queries, commands, events, jobs, role filtering, local dispatch, file outbox, broker/fanout adapters, worker replay with dedup/backoff hooks, contract graph/trace/list commands, generated g:command/g:query web adapters, and explicit domain-event to query invalidation metadata. Separate worker/cron binary generators and editor-first contract visualization remain planned platform tooling. Contracts Runtime contracts
Realtime Works, contract unstable FeatureRealtime and addons/realtime provide opt-in presentation-event fanout packaging, dependency-free SSE helpers, nested WebSocket transport docs, compiler-validated g:subscribe metadata, generated subscription-filtered guarded SSE fanout, bounded SSE retry/drop behavior, a bounded generated client patch loop for query-owned regions, generated gowdk.query.invalidate events, and current-document refresh for non-subscribed invalidated query regions. Custom retry/backoff/replay, active session-change stream revocation, richer patch shapes, fragment/API-specific query execution, and route-specific refresh endpoints remain hardening work. Realtime SSE
Observability Early runtime/trace provides dependency-free W3C trace IDs, context spans, sampling, sinks, source refs, traceparent propagation, a local JSON/SSE collector, and a self-contained viewer. addons/observability enables debug-only generated backend/frontend/island tracing, and runtime/trace/otel provides an optional nested OTLP bridge. Durable production storage, hosted analysis, and production sampling policy remain app-owned. Observability Runtime trace
Security audit Early gowdk audit derives an IR-backed posture for routes, endpoints, contracts, and frontend surface risks; evaluates the built-in baseline plus declared *.audit.gwdk policies; exits non-zero on error findings; can emit/run generated audit tests; and gowdk build runs the same baseline, blocking production builds on error findings unless --allow-insecure is set. The audit DSL and generated tests cover the M8 slice; broader auth/session ownership, richer role fixtures, and deeper browser/data-flow analysis remain app-owned or planned. Security Spec
Dev server Works gowdk dev polls inputs, skips no-op rebuilds, serves or runs generated output through a dev-only proxy when runtime mode is needed, live-reloads browsers, shows a browser overlay with diagnostic codes/source spans/changed-file context, and hot-swaps matching JS island component roots. Dev-only runtime panic surfacing, state-preserving/broader HMR, and richer editor integration remain planned. Dev Getting started
Editor/LSP Works The VS Code extension and dependency-free LSP provide diagnostics, formatting, completions, hover, outline, semantic tokens, definitions, references, site-map visualization, project-aware navigation, and editor-visible g:command/g:query binding diagnostics for supported paths. Richer quick fixes and route/endpoint/contract map polish are planned. Language server VS Code

Security note: request-time features are still 0.x, but the core request-time hardening is now in place. Generated handlers apply body-size limits (actions and APIs, configurable through Build.BodyLimits), server read/header/write/idle timeouts, and a per-request handler deadline; recovered panics return a generic no-store 500 and are logged server-side with secret redaction; ordinary returned 5xx errors use generic client messages unless the app sets an explicit response.HandlerError message; generated action and command POSTs enable CSRF by default with a fail-closed secret requirement and a 403 invalid-token contract; redirects are validated against a safe allowlist (local paths only, no protocol-relative or CRLF, same-origin referer); and diagnostics redact secrets quoted from source. Still hardening: full auth/session, multipart uploads, and the broader operations policy.

Known gaps and release hardening work live in the 0.x improvement checklist, with public tracking in the 0.x Hardening project.

Addons

The runtime core stays dependency-light; everything optional is an addon you wire in with gowdk add <addon>. Use gowdk add --list for addable built-ins and gowdk add --list --registry for registry metadata; SEO also needs gowdk add seo --base-url https://example.com:

Addon What it adds
actions Backend form/action handlers
api Request-time API endpoints
auth Batteries-included auth: PBKDF2, signed sessions, RBAC guards (no external deps)
contracts Contract-driven command/event metadata
css Build-time CSS processing
db sqlc + database/sql plumbing helper (no domain, no driver dep)
embed Embed build output into the binary
partial Fragment/partial responses
ratelimit Request-time rate limiting
seo Build-time sitemap.xml and robots.txt output
realtime Browser presentation-event fanout over SSE or WebSocket
ssr Server-side rendering
static Build-time static page output

SSE fanout stays dependency-free in the root module. Heavier integrations (Tailwind, Redis, NATS, WebSocket fanout) live in nested optional modules so the root module's dependency graph stays small. Addon discovery beyond addable built-ins remains metadata-first: gowdk add --list --registry prints the local registry, and external addon installation stays explicit through normal Go module imports. The current policy is in Addons.

Development

Run the full Go test gate, including nested optional adapter modules:

scripts/test-go-modules.sh

Check the root module's direct dependency allowlist and optional adapter split:

scripts/check-root-deps.sh

Run the root module only:

go test ./...
go build ./cmd/gowdk

Run the all-module vulnerability gate before release-style dependency changes:

scripts/vulncheck-go-modules.sh

Generated output is golden-tested: the compiler's HTML, generated Go adapters, island JS/WASM assets, IR, and CLI behavior are all snapshot-checked against committed fixtures, so any change to generated artifacts shows up as a reviewable test diff rather than a silent behavior change.

Docs

About

GOWDK is an experimental Go-first web framework for shipping full-stack web apps as a single deployable binary. It brings together backend logic, routing, reactivity, forms, APIs, static assets, and server-side rendering with fewer moving parts, fewer dependencies, and a smaller supply-chain attack surface.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors