docs: document attribute forwarding (attrs, twJoin/twMerge, WithClassMerger)
Documents the attribute-forwarding feature: a Forwarding attributes section in components.md (gastro.Attrs, the attrs func, escaping/bypass, bool attrs, class merge, WithClassMerger, the typo-becomes-attribute tradeoff), an Attribute Forwarding section in helpers.md covering attrs/twJoin/twMerge, and WithClassMerger in the README option list. Refs #37.
docs: document attribute forwarding (attrs, twJoin/twMerge, WithClassMerger)
Documents the attribute-forwarding feature: a Forwarding attributes section in components.md (gastro.Attrs, the attrs func, escaping/bypass, bool attrs, class merge, WithClassMerger, the typo-becomes-attribute tradeoff), an Attribute Forwarding section in helpers.md covering attrs/twJoin/twMerge, and WithClassMerger in the README option list. Refs #37.
docs: surface New(), WithDeps, WithOverride, gastro check across docs
The README, sse, helpers, compression, and architecture docs still
showed gastro.Routes() as the primary entry point. Updated them to
prefer gastro.New(opts...).Handler() while noting Routes() remains as
a deprecated shim.
Specific changes:
- README.md: 'Custom helpers' example uses gastro.New(); short
explanation of New() / WithDeps / WithOverride with cross-links.
- docs/sse.md: 'Wiring It Up' main.go uses gastro.New() and includes
a one-paragraph note on why New() is preferred over Routes().
- docs/helpers.md: WithFuncs example uses gastro.New().
- docs/compression.md: GzipMiddleware and gzhttp examples wrap
router.Handler() and the dev-mode-composition note matches.
- docs/architecture.md: '*Router type, New() constructor, methods on
Router' replaces the old 'Routes() function' description of
routes.go.
The website (examples/gastro) renders these markdown files directly
via the {{ markdown }} helper, so it picks up the changes without any
.gastro file edits. Smoke-tested by running the site locally and
curling each affected page.
The original Design Document (docs/design.md) is left as-is per its
historical-record purpose.
feat(cli): --asset CMD on gastro watch (reload-aware build chain)
Adds a `--asset CMD` (alias `-a`) flag to `gastro watch` for
content-derived asset generators that need to re-run on every change,
not just restart-class changes. Closes the gap that made Tailwind
silently miss new utility classes on template-body edits.
Why it matters
--------------
A template-body edit (e.g. adding `class="size-12"` to a div) is
RELOAD-class per `internal/watcher/watcher.go`: the running binary
keeps serving and devloop fires `OnReload` to refresh the browser.
The existing `--build` chain runs only in the `OnRestart` path,
so a Tailwind step placed in `--build` is silently skipped on every
body-only edit. Browser refreshes with stale CSS; new class does
nothing. Touching frontmatter or restarting the dev server were the
only workarounds.
What changed
------------
internal/devloop/devloop.go
- New `Config.PreReload func(ctx) error` hook. Runs between
`Generate` and `OnReload` on reload-class changes only. Returning
a non-nil error suppresses the OnReload signal for that cycle so
the browser doesn't refresh onto a half-rebuilt asset state.
- Three new tests: ordering (pre-reload precedes on-reload),
error-suppresses-reload, nil-preserves-behaviour.
cmd/gastro/watch.go
- New `--asset CMD` / `-a CMD` flag (repeatable, mirrors --build).
- Extract build-execution into a shared `runChain(ctx, label, cmds)`
helper so --build and --asset have identical failure semantics
and the same `.gastro/.build-error` writeback.
- On RESTART-class: asset chain runs first, then build chain, then
the app restarts.
- On RELOAD-class: asset chain runs via PreReload, then the reload
signal fires.
- Output-collision warning at L323 extended to --asset.
- `gastro dev` flag-rejection message updated to mention --asset.
- --help text documents both flags side-by-side with a NOTE on the
RESTART-only semantics of --build.
- 5 new parser tests + 2 new integration tests.
scripts/dev/example-website
- Migrate `tailwindcss` from --build to --asset. Comment expanded
to explain why (RELOAD-class miss is the bug we're fixing).
docs/dev-mode.md
- New "Asset chain vs build chain" subsection with a two-row
decision table and a worked Tailwind example.
DECISIONS.md
- Per-commit decision entry covering the bug, alternatives weighed,
and what is/isn't in scope.
What this is not
----------------
- Not a Tailwind integration; --asset is generic over any shell
command.
- Not a change to ClassifyChange; body edits stay RELOAD-class so
the optimization that makes them feel instant is preserved.
- Not a `gastro dev` feature; the zero-config dev path stays
zero-config. Users who need asset pipelines reach for
`gastro watch`, which is the documented escape hatch.
Tests
-----
All `go test -race ./...` green. 10 new tests total:
3 devloop unit, 5 cli parser, 2 cli integration.
docs: document attribute forwarding (attrs, twJoin/twMerge, WithClassMerger)
Documents the attribute-forwarding feature: a Forwarding attributes section in components.md (gastro.Attrs, the attrs func, escaping/bypass, bool attrs, class merge, WithClassMerger, the typo-becomes-attribute tradeoff), an Attribute Forwarding section in helpers.md covering attrs/twJoin/twMerge, and WithClassMerger in the README option list. Refs #37.
docs: full WithRequestFuncs documentation pass + DECISIONS entry
Phase 5d (remaining). Completes the docs surface for the
WithRequestFuncs feature now that all three example apps are in
place.
- docs/i18n.md (new, ~280 lines): full recipe walking through the
examples/i18n/ app step-by-step. Covers library choice, embed
layout, locale-detection middleware shapes (path / cookie /
Accept-Language / fallback), the WithRequestFuncs binder, template
usage, the xgettext translation workflow, CLDR plural rules (and
when to reach for gotext), and the per-page-frontmatter
alternative for content-light pages.
- docs/sse.md: new "Request-aware helpers in SSE patches" subsection
documenting Render.With(r) as the SSE-handler counterpart to the
request-aware page render path. Calls out the
reusable-within-a-request lifetime contract (D4).
- docs/helpers.md: "Known limitation: components called from
templates" section replaced with "Components, slots, and wrap
blocks" \u2014 the limitation is no longer a limitation (nested
propagation shipped in the previous commit). The "Worked example"
section now points at all three examples/ apps with a comparison
table of the axes each one stresses.
- README.md: WithRequestFuncs called out in the options list next
to WithFuncs / WithDeps / WithMiddleware / WithErrorHandler with
a forward-link to docs/helpers.md.
- DECISIONS.md: comprehensive entry recording the eight resolved
decisions (D1\u2013D8 from tmp/withrequestfuncs-plan.md \u00a710), the
rejected alternatives (pkg/gastro/i18n, pkg/gastro/csrf,
pkg/gastro/csp helper packages; gastro i18n extract CLI;
markdownLocalized directive; langPath framework helper; per-locale
pre-parse), and a phase-by-phase implementation summary across
both PRs.
Refs: tmp/withrequestfuncs-plan.md \u00a75d.
docs: full WithRequestFuncs documentation pass + DECISIONS entry
Phase 5d (remaining). Completes the docs surface for the
WithRequestFuncs feature now that all three example apps are in
place.
- docs/i18n.md (new, ~280 lines): full recipe walking through the
examples/i18n/ app step-by-step. Covers library choice, embed
layout, locale-detection middleware shapes (path / cookie /
Accept-Language / fallback), the WithRequestFuncs binder, template
usage, the xgettext translation workflow, CLDR plural rules (and
when to reach for gotext), and the per-page-frontmatter
alternative for content-light pages.
- docs/sse.md: new "Request-aware helpers in SSE patches" subsection
documenting Render.With(r) as the SSE-handler counterpart to the
request-aware page render path. Calls out the
reusable-within-a-request lifetime contract (D4).
- docs/helpers.md: "Known limitation: components called from
templates" section replaced with "Components, slots, and wrap
blocks" \u2014 the limitation is no longer a limitation (nested
propagation shipped in the previous commit). The "Worked example"
section now points at all three examples/ apps with a comparison
table of the axes each one stresses.
- README.md: WithRequestFuncs called out in the options list next
to WithFuncs / WithDeps / WithMiddleware / WithErrorHandler with
a forward-link to docs/helpers.md.
- DECISIONS.md: comprehensive entry recording the eight resolved
decisions (D1\u2013D8 from tmp/withrequestfuncs-plan.md \u00a710), the
rejected alternatives (pkg/gastro/i18n, pkg/gastro/csrf,
pkg/gastro/csp helper packages; gastro i18n extract CLI;
markdownLocalized directive; langPath framework helper; per-locale
pre-parse), and a phase-by-phase implementation summary across
both PRs.
Refs: tmp/withrequestfuncs-plan.md \u00a75d.