Code

Wire it up + serve assets — static, handlers, router, main

Four files as tabs, in dependency order: static/embed.gohandlers.gorouter.gomain.go — embed the assets, render the template, serve /static, wire it in main. The last three are modifications of your lesson-1 files: the diff shows only the changed lines, everything else is carried forward.

1. static/embed.go (new) — makes the assets part of the binary:

//go:embed assets
var FS embed.FS

The CSS and vendored htmx live under static/assets/css/style.css and static/assets/js/htmx.min.js. Those two are provided assets — this course teaches Go and HTML, so the stylesheet ships with the starter (like a design system you'd be handed at work); you're welcome to edit it. //go:embed bakes them into the compiled binary, so there's no separate asset folder to deploy.

2. internal/handlers/handlers.go (modify) — Home now renders the template. The one changed function:

func (h *Handlers) Home(w http.ResponseWriter, r *http.Request) {
	render(w, r, http.StatusOK, web.Home())
}

The raw-string fmt.Fprint is gone; the fmt import with it, and web is imported instead. Health and the struct are unchanged.

3. internal/handlers/router.go (modify) — one new route and one new parameter:

func (h *Handlers) Router(staticFS fs.FS) http.Handler {   // ← now takes the asset FS
	// ... the same middleware ...
	r.Handle("/static/*", http.StripPrefix("/static/", http.FileServer(http.FS(staticFS))))
	// ... / and /healthz unchanged ...
}

4. cmd/signflow/main.go (modify) — derive the sub-FS and hand it to the router:

staticFS, err := fs.Sub(static.FS, "assets")   // expose static/assets at /static
if err != nil {
	return err
}
// ...
Handler: h.Router(staticFS),

Verify. Regenerate the templates, then run:

templ generate
go run ./cmd/signflow

Open http://localhost:8080. Same content as lesson 1 — but now it's a real, styled page: the SignFlow header, the hero, the "Skeleton status" card, all wearing the stylesheet. View source and you'll see the full HTML the layout produced. And:

$ curl -s -o /dev/null -w "%{http_code}\n" localhost:8080/static/css/style.css
200

The CSS is served from inside the binary.

Gotcha (recap — the stale template). Change home.templ, reload, see no change? You skipped templ generate. The binary renders the committed _templ.go, not your edited .templ. Generate, rebuild, reload.