Ryan Hamamura b3c2d3ae32
Some checks failed
CI / Build and Test (push) Failing after 35s
CI / Build and Test (pull_request) Failing after 35s
fix: remove context reaper to prevent background tabs from going stale
Background windows stopped updating because the reaper suspended contexts
after ContextSuspendAfter and fully reaped them after ContextTTL. Suspended
contexts had to re-run the page init function from scratch on reconnect,
losing the live-updating experience.

Contexts now live until the browser tab closes (beforeunload beacon) or
the server shuts down. The context map grows indefinitely — no background
reaper.

Removes: startReaper, reapOrphanedContexts, suspend/resume logic,
ContextSuspendAfter/ContextTTL config fields, lastSeenAt/suspended
context fields, and all associated tests.
2026-02-20 09:09:05 -10:00
2025-10-26 00:49:55 +00:00

Via

Real-time engine for building reactive web applications in pure Go.

Why Via?

The web became tangled in layers of JavaScript, build chains, and frameworks stacked on frameworks. Via takes a different path.

Philosophy

  • No templates. No JavaScript. No transpilation. No hydration.
  • Views are pure Go functions. HTML is composed with a type-safe DSL.
  • A single SSE stream carries all reactivity — no WebSocket juggling, no polling.

Batteries included

  • Automatic CSRF protection on every action call
  • Token-bucket rate limiting (global defaults + per-action overrides)
  • Cookie-based sessions backed by SQLite
  • Pub/sub messaging with an embedded NATS backend
  • Structured logging via zerolog
  • Graceful shutdown with context draining
  • Brotli compression out of the box

Example

package main

import (
	"github.com/ryanhamamura/via"
	"github.com/ryanhamamura/via/h"
)

type Counter struct{ Count int }

func main() {
	v := via.New()

	v.Page("/", func(c *via.Context) {
		data := Counter{Count: 0}
		step := c.Signal(1)

		increment := c.Action(func() {
			data.Count += step.Int()
			c.Sync()
		})

		c.View(func() h.H {
			return h.Div(
				h.P(h.Textf("Count: %d", data.Count)),
				h.Label(
					h.Text("Update Step: "),
					h.Input(h.Type("number"), step.Bind()),
				),
				h.Button(h.Text("Increment"), increment.OnClick()),
			)
		})
	})

	v.Start()
}

What's built in

  • Reactive views + signals — bind state to the DOM; changes push over SSE automatically
  • Components — self-contained subcontexts with their own data, actions, and signals
  • Sessions — cookie-based, backed by SQLite via scs
  • Pub/sub — embedded NATS server with JetStream; generic Publish[T] / Subscribe[T] helpers
  • CSRF protection — automatic token generation and validation on every action
  • Rate limiting — token-bucket algorithm, configurable globally and per-action
  • Event handlingOnClick, OnChange, OnSubmit, OnInput, OnFocus, OnBlur, OnMouseEnter, OnMouseLeave, OnScroll, OnDblClick, OnKeyDown, and OnKeyDownMap for multi-key bindings
  • Timed routinesOnInterval auto-starts a ticker goroutine, returns a stop function, tied to context lifecycle
  • RedirectsRedirect, ReplaceURL, and format-string variants
  • Plugin systemfunc(v *V) hooks for integrating CSS/JS libraries
  • Structured logging — zerolog with configurable levels; console output in dev, JSON in production
  • Graceful shutdown — listens for SIGINT/SIGTERM, drains contexts, closes pub/sub
  • Context lifecycle — background reaper cleans up disconnected contexts; configurable TTL
  • HTML DSL — the h package provides type-safe Go-native HTML composition

Examples

The internal/examples/ directory contains 14 runnable examples:

chatroom · counter · countercomp · greeter · keyboard · livereload · nats-chatroom · pathparams · picocss · plugins · pubsub-crud · realtimechart · session · shakespeare

Experimental

Via is maturing — sessions, CSRF, rate limiting, pub/sub, and graceful shutdown are in place — but the API is still evolving. Expect breaking changes before v1.

Contributing

  • Via is intentionally minimal and opinionated — and so is contributing.
  • Fork, branch, build, tinker, submit a pull request.
  • Keep every line purposeful.
  • Share feedback: open an issue or start a discussion.

Credits

Via builds upon the work of these projects:

  • Datastar — the hypermedia framework powering browser reactivity through signals and real-time HTML patches over SSE.
  • Gomponents — Go-native HTML composition that powers the via/h package.
Description
Reactive real-time web engine for Go
Readme MIT 15 MiB
v0.23.0 Latest
2026-02-20 21:38:03 +00:00
Languages
Go 97.6%
CSS 1.2%
JavaScript 0.7%
Shell 0.5%