xtemplate

package module
v0.11.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 28, 2026 License: Apache-2.0 Imports: 51 Imported by: 6

README

xtemplate

Hypermedia web apps from a directory of Go templates.

xtemplate is a Go server that treats templates as handlers: file-based routing, a request-scoped dot context, and first-class static files; no separate application layer.

<!-- contacts.html  →  GET /contacts (SQL provider configured as .DB) -->
<ul>
  {{range .DB.QueryRows `SELECT id, name FROM contacts`}}
  <li><a href="/contacts/{{.id}}">{{.name}}</a></li>
  {{end}}
</ul>
<!-- contacts/{id}.html  →  GET /contacts/{id} -->
{{$id := .Req.PathValue `id`}}
{{$c := .DB.QueryRow `SELECT id, name, phone, email FROM contacts WHERE id = ?` $id}}
<form method="POST">
  <input name="name"  value="{{$c.name}}">
  <input name="phone" value="{{$c.phone}}">
  <input name="email" value="{{$c.email}}">
  <button>Update</button>
</form>

{{define "POST /contacts/{id}"}}
{{$_ := .DB.Exec `UPDATE contacts SET name=?, phone=?, email=? WHERE id = ?`
    (.Req.FormValue `name`) (.Req.FormValue `phone`)
    (.Req.FormValue `email`) (.Req.PathValue `id`)}}
{{template `/contacts/{id}.html` .}}
{{end}}

No route table, no handler functions. One file for the index. One file for the form and the update. Path parameters, form values, and SQL all hang off the dot context.

Philosophy

Deal with the first-class citizens of the web: paths, requests, HTML responses, and backing data. Templates are expressive enough to be the app. More details in Design.

Highlights

  • File-based routing - admin/settings.html serves GET /admin/settings; index.html serves the directory. Template semantics
  • Any method and pattern - {{define "DELETE /contact/{id}"}} is a route. Instance loading
  • Loads once, reloads live - parse at startup; swap an immutable instance on change. Design
  • Dot context - .Req, .Resp, .DB, .FS, … per request. Dot context
  • Safe by default - html/template escaping; optional sanitize / trust helpers. Functions
  • Optimal static files - hashes, SRI, precompressed encodings, long cache. Instance loading
  • SSE - {{define "SSE /path"}} for live updates. Dot context → Flush
  • Embeddable - CLI, Docker, Caddy plugin, or http.Handler library. Deployment modes

Some more patterns:

{{- with $hash := .X.StaticFileHash `/assets/reset.css`}}
<link rel="stylesheet" href="/assets/reset.css?hash={{$hash}}" integrity="{{$hash}}">
{{- end}}
{{- define "SSE /reload"}}{{.Flush.WaitForServerStop}}data: reload{{printf "\n\n"}}{{end}}
<script>new EventSource("/reload").onmessage = () => location.reload()</script>

More complete apps: examples/.

Quick start

If you want… Start here
Step-by-step first app Getting started tutorial
Zero setup container Docker
Local templates + live reload CLI · CLI flags
Templates from a Git remote CLI --controller-type git
Automatic HTTPS, auth, proxy Caddy module
Embed in your Go program Go library
# CLI (live reload)
go install github.com/infogulch/xtemplate/cmd/xtemplate@latest
mkdir -p templates && echo '<h1>{{.Req.URL.Path}}</h1>' > templates/index.html
xtemplate --listen :8080
# open http://localhost:8080
# Docker
docker run --rm -p 8080:80 \
  -v "$PWD/templates:/app/templates:ro" \
  infogulch/xtemplate:latest
# Caddy
:8080
route {
	xtemplate
}

Full integration map and configs: docs/reference/deployment-modes.md.

All documentation (tutorial, how-tos, reference, design): docs/.

Users

Contributing

Development setup, repo map, and tests: CONTRIBUTING.md (same as docs/contributing.md).

History and license

Evolved from go-htmx and a Caddy-centric prototype into a standalone library with an optional Caddy module. Narrative: Project history. Releases: CHANGELOG.md.

Licensed under the Apache 2.0 license. See LICENSE.

Documentation

Overview

xtemplate extends Go's html/template to be capable enough to define an entire server-side application with a directory of Go templates.

Index

Constants

This section is empty.

Variables

View Source
var DefaultControllerType = "os"

DefaultControllerType is used when no controller or TemplateFS is configured. Core default is "os". Binaries may reassign (e.g. cmd/xtemplate sets "watchfs").

Functions

func AddBlueMondayPolicy added in v0.5.0

func AddBlueMondayPolicy(name string, policy *bluemonday.Policy)

AddBlueMondayPolicy adds a bluemonday policy to the global policy list available to all xtemplate instances.

func AddMarkdownConfig added in v0.9.0

func AddMarkdownConfig(name string, md goldmark.Markdown)

AddMarkdownConfig adds a custom markdown configuration to xtemplate's markdown config map, shared by all xtemplate instances.

func CheckLegacyTemplateKeys added in v0.11.0

func CheckLegacyTemplateKeys(data []byte) error

CheckLegacyTemplateKeys returns a migrate error if banned top-level keys are present.

func ControllerTypeFromRaw added in v0.11.0

func ControllerTypeFromRaw(raw json.RawMessage) (string, error)

ControllerTypeFromRaw peeks the "type" field of a controller JSON object. Empty raw returns ("", nil).

func FuncFailf added in v0.7.0

func FuncFailf(format string, args ...any) (string, error)

func FuncHumanize added in v0.5.0

func FuncHumanize(formatType, data string) (string, error)

humanize transforms size and time inputs to a human readable format using the go-humanize library.

Call with two parameters: format type and value to format. Supported format types are:

"size" which turns an integer amount of bytes into a string like "2.3 MB", for example:

{{humanize "size" "2048000"}}

"time" which turns a time string into a relative time string like "2 weeks ago", for example:

{{humanize "time" "Fri, 05 May 2022 15:04:05 +0200"}}

func FuncIdx added in v0.5.0

func FuncIdx(idx int, arr any) (any, error)

idx gets an item from a list, similar to the built-in index, but with reversed args: index first, then array. This is useful to use index in a pipeline, for example:

{{generate-list | idx 5}}

Returns an error if the value is not indexable or the index is out of range.

func FuncReturn added in v0.5.0

func FuncReturn() (string, error)

return causes the template to exit early with a success status.

func FuncSanitizeHtml added in v0.5.0

func FuncSanitizeHtml(policyName string, html string) (template.HTML, error)

sanitizeHtml Uses the BlueMonday library to sanitize strings with html content. First parameter is the name of the chosen sanitization policy.

func FuncTrustAttr added in v0.5.0

func FuncTrustAttr(s string) template.HTMLAttr

trustAttr marks the string s as safe and does not escape its contents in html attribute context.

func FuncTrustHtml added in v0.5.0

func FuncTrustHtml(s string) template.HTML

trustHtml marks the string s as safe and does not escape its contents in html node context.

func FuncTrustJS added in v0.5.0

func FuncTrustJS(s string) template.JS

trustJS marks the string s as safe and does not escape its contents in script tag context.

func FuncTrustJSStr added in v0.5.0

func FuncTrustJSStr(s string) template.JSStr

trustJSStr marks the string s as safe and does not escape its contents in script expression context.

func FuncTrustSrcSet added in v0.5.0

func FuncTrustSrcSet(s string) template.Srcset

trustSrcSet marks the string s as safe and does not escape its contents in script tag context.

func FuncTry added in v0.5.0

func FuncTry(fn any, args ...any) (*result, error)

The try template func accepts a fallible function object and calls it with the provided args. If the function and args are valid, try returns the result wrapped in a result object that exposes the return value and error to templates. Useful if you want to call a function and handle its error in a template. If the function value is invalid or the args cannot be used to call it then try raises an error that stops template execution.

func GetLogger added in v0.6.0

func GetLogger(ctx context.Context) *slog.Logger

func GetRequestId added in v0.6.0

func GetRequestId(ctx context.Context) string

func RegisterController added in v0.11.0

func RegisterController(name string, ctor func() ServerController)

RegisterController makes a controller type available to ResolveController. Call from init(). Panics on duplicate registration.

func RegisterProvider added in v0.11.0

func RegisterProvider(name string, ctor ProviderFactory)

RegisterProvider makes a provider type available to resolveProviders. Call from init(). Panics on duplicate registration (names the type in the message; the registering package is identified by the runtime's stack trace).

func RegisteredControllerTypes added in v0.11.0

func RegisteredControllerTypes() []string

RegisteredControllerTypes returns sorted registered controller type names.

Types

type Closer added in v0.11.0

type Closer interface {
	Close() error
}

Closer is an optional capability for releasing instance-scoped resources when the instance is retired (reload or stop). Prefer Close over relying solely on context cancellation when the provider owns connections or similar handles.

type Config added in v0.3.0

type Config struct {
	// Controller is the optional ServerController (JSON key "controller").
	// Resolved from ControllerRaw by [Config.MaterializeController] (LoadConfig /
	// Server.construct). Instance requires TemplateFS instead and rejects
	// Controller / ControllerRaw.
	Controller ServerController `json:"-" arg:"-"`

	// ControllerRaw is the JSON "controller" object until MaterializeController.
	ControllerRaw json.RawMessage `json:"controller,omitempty" arg:"-"`

	// TemplateFS is the private build-root FS (not JSON). Sticky after controller
	// Init or WithTemplateFS/Dir; also the per-Reload root when set via options.
	TemplateFS afero.Fs `json:"-" arg:"-"`

	// File extension to search for to find template files. Default `.html`.
	TemplateExtension string `json:"template_extension,omitempty" arg:"--template-ext" default:".html"`

	// Whether html templates are minified at load time. Default `true`.
	//
	// This is a *bool to distinguish unset (nil) from set false.
	Minify *bool `json:"minify,omitempty" arg:"-m,--minify" default:"true"`

	CrossOrigin CrossOriginConfig `json:"crossorigin" arg:"-"`

	ProvidersRaw []json.RawMessage `json:"providers,omitempty" arg:"-"`
	// Providers holds factories that produce a fresh [Provider] per Instance
	// build / Reload (same isolation as JSON ProvidersRaw → resolveProviders).
	Providers []ProviderFactory `json:"-" arg:"-"`

	// Encodings to pre-compress static files into at load time. Supported values:
	// "gzip", "zstd", "br". Default empty (no pre-compression).
	Precompress []string `json:"precompress,omitempty" arg:"--precompress,separate"`

	// Left template action delimiter. Default `{{`.
	LDelim string `json:"left,omitempty" arg:"--ldelim" default:"{{"`

	// Right template action delimiter. Default `}}`.
	RDelim string `json:"right,omitempty" arg:"--rdelim" default:"}}"`

	// Additional functions to add to the template execution context.
	FuncMaps []template.FuncMap `json:"-" arg:"-"`

	// Peer HTTP handlers registered on the instance ServeMux next to template
	// and static routes. Use this to embed existing handlers (APIs, webhooks,
	// health checks) under the same ServeMux as the template app. Errors if the
	// pattern conflicts with another route registered by the template root.
	//
	// Each entry is a sibling route on the mux (net/http.ServeMux pattern).
	// Re-registered when a new instance is built, so they survive reloads.
	Handlers []HandlerRoute `json:"-" arg:"-"`

	// The instance context that is threaded through dot providers and can
	// cancel the server. Defaults to `context.Background()`.
	Ctx context.Context `json:"-" arg:"-"`

	// The default logger. Defaults to `slog.Default()`.
	Logger *slog.Logger `json:"-" arg:"-"`
	// contains filtered or unexported fields
}

func New added in v0.1.4

func New() (c *Config)

func (Config) Instance added in v0.4.0

func (config Config) Instance() (_ *Instance, err error)

Instance creates a new *Instance from the given config. Requires a resolved template FS (WithTemplateFS / WithTemplateDir). Controller and ControllerRaw must be nil. Owned slices are cloned.

func (*Config) MaterializeController added in v0.11.0

func (c *Config) MaterializeController(preferType string) (string, error)

MaterializeController ensures c.Controller is set and c.ControllerRaw is nil. The returned string is the selected type name when known (from Raw, preferType, or DefaultControllerType). Empty when Controller was already set (name unknown).

If Controller is already non-nil, only clears ControllerRaw. If ControllerRaw is set:

  • When preferType is empty (library/Server), always decode Raw.
  • When preferType is non-empty (CLI effective type), decode Raw only if its type is empty or equals preferType; otherwise discard Raw (CLI type wins). An empty raw type still attempts decode so ResolveController reports "missing type".

If still no Controller, creates NewController(preferType), or DefaultControllerType when preferType is empty.

func (*Config) Options added in v0.6.5

func (c *Config) Options(options ...Option) (*Config, error)

Options applies the given options to the Config, returning the updated Config or the first error.

func (Config) Server added in v0.4.0

func (config Config) Server() (*Server, error)

Server creates a Server from Config. Apply Options on the Config first; this method does not take Option args. Owned slices are cloned so the caller's Config is not mutated by sticky Options or later Reloads.

func (*Config) SetDefaults added in v0.9.0

func (config *Config) SetDefaults() *Config

SetDefaults fills unset fields. Does not choose a Controller or clone slices.

func (*Config) UnmarshalJSON added in v0.11.0

func (c *Config) UnmarshalJSON(data []byte) error

UnmarshalJSON applies the ban-list then unmarshals into Config.

type CrossOriginConfig added in v0.9.0

type CrossOriginConfig struct {
	Disabled               bool     `json:"disabled" arg:"--disable-cors" default:"false"`
	TrustedOrigins         []string `json:"trusted_origins" arg:"--trusted-origin,separate"`
	InsecureBypassPatterns []string `json:"insecure_bypass_patterns" arg:"--insecure-bypass-pattern,separate"`
}

type DotFlush added in v0.5.0

type DotFlush struct {
	// contains filtered or unexported fields
}

DotFlush is used as the .Flush field for flushing template handlers (SSE).

func (*DotFlush) Flush added in v0.5.0

func (f *DotFlush) Flush() string

Flush flushes any content waiting to be written to the client.

func (*DotFlush) Repeat added in v0.5.0

func (f *DotFlush) Repeat(max_ ...int) <-chan int

Repeat generates numbers up to max, using math.MaxInt64 if no max is provided.

func (*DotFlush) SendSSE added in v0.6.0

func (f *DotFlush) SendSSE(args ...string) error

SendSSE sends an sse message by formatting the provided args as an sse event:

Requires 1-4 args: event, data, id, retry

func (*DotFlush) Sleep added in v0.5.0

func (f *DotFlush) Sleep(ms int) (string, error)

Sleep sleeps for ms milliseconds. Template execution is aborted if the request is canceled or the server receives a stop signal.

func (*DotFlush) WaitForServerStop added in v0.5.0

func (f *DotFlush) WaitForServerStop() (string, error)

WaitForServerStop blocks template execution until the server receives a stop signal, then continues to allow sending a final response before the request is closed. Template execution is aborted if the client cancels the request.

type DotReq added in v0.5.0

type DotReq struct {
	*http.Request
}

DotReq is used as the .Req field for template invocations with an associated request, and contains the current HTTP request struct which can be used to read request data. See http.Request for detailed documentation. Some notable methods and fields:

http.Request.Method, http.Request.PathValue, http.Request.URL, [http.Request.URL.Query], http.Request.Cookie, http.Request.Header, [http.Request.Header.Get].

Note that http.Request.ParseForm must be called before using http.Request.Form, http.Request.PostForm, and http.Request.PostValue.

type DotResp added in v0.5.0

type DotResp struct {
	http.Header
	// contains filtered or unexported fields
}

DotResp is used as the .Resp field in buffered template invocations.

func (*DotResp) AddHeader added in v0.5.0

func (h *DotResp) AddHeader(field, val string) string

AddHeader adds a header field value, appending val to existing values for that field. It returns an empty string.

func (*DotResp) DelHeader added in v0.5.0

func (h *DotResp) DelHeader(field string) string

DelHeader deletes a header field. It returns an empty string.

func (*DotResp) ReturnStatus added in v0.5.0

func (h *DotResp) ReturnStatus(status int) (string, error)

ReturnStatus sets the HTTP response status and exits template rendering immediately.

func (*DotResp) ServeContent added in v0.5.0

func (d *DotResp) ServeContent(path_ string, modtime time.Time, content any) (string, error)

ServeContent aborts execution of the template and instead responds to the request with content with any headers set by AddHeader and SetHeader so far but ignoring SetStatus. content must be a string, []byte, or io.ReadSeeker.

func (*DotResp) SetHeader added in v0.5.0

func (h *DotResp) SetHeader(field, val string) string

SetHeader sets a header field value, overwriting any other values for that field. It returns an empty string.

func (*DotResp) SetStatus added in v0.5.0

func (h *DotResp) SetStatus(status int) string

SetStatus sets the HTTP response status. It returns an empty string.

type DotX added in v0.5.0

type DotX struct {
	// contains filtered or unexported fields
}

DotX is used as the field at .X in all template invocations.

func (DotX) Func added in v0.5.0

func (c DotX) Func(name string) any

Func returns a function by name to call manually. Can be used in combination with the call and try funcs.

func (DotX) StaticFileHash added in v0.5.0

func (d DotX) StaticFileHash(urlpath string) (string, error)

StaticFileHash returns the sha-384 hash of the named asset file to be used for integrity or caching behavior.

func (DotX) Template added in v0.5.0

func (c DotX) Template(name string, dot any) (template.HTML, error)

Template invokes the template name with the given dot value, returning the result as a html string.

type Duration added in v0.11.0

type Duration time.Duration

Duration is a time.Duration that marshals to/from human-friendly strings (e.g. "30s", "1m30s") in JSON and text.

It implements encoding.TextUnmarshaler and encoding.TextMarshaler so go-arg CLI flags parse duration strings the same way.

func (Duration) Duration added in v0.11.0

func (d Duration) Duration() time.Duration

Duration returns the underlying time.Duration.

func (Duration) MarshalJSON added in v0.11.0

func (d Duration) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler. Zero encodes as "0s".

func (Duration) MarshalText added in v0.11.0

func (d Duration) MarshalText() ([]byte, error)

MarshalText implements encoding.TextMarshaler.

func (Duration) String added in v0.11.0

func (d Duration) String() string

String formats d using time.Duration.String.

func (*Duration) UnmarshalJSON added in v0.11.0

func (d *Duration) UnmarshalJSON(data []byte) error

UnmarshalJSON implements json.Unmarshaler. Accepts a duration string ("30s") or JSON null.

func (*Duration) UnmarshalText added in v0.11.0

func (d *Duration) UnmarshalText(text []byte) error

UnmarshalText implements encoding.TextUnmarshaler.

type ErrorStatus added in v0.6.0

type ErrorStatus int

func (ErrorStatus) Error added in v0.6.0

func (e ErrorStatus) Error() string

type Finalizer added in v0.11.0

type Finalizer interface {
	Finalize(value any, err error) error
}

Finalizer is an optional capability for work after template execution (commit/rollback, close request-scoped handles, write buffered response headers/status). value is what Value returned for the request; err is the template/construction error so far. The returned error replaces err for subsequent finalizers and the handler.

type HandlerRoute added in v0.9.0

type HandlerRoute struct {
	// Pattern uses net/http.ServeMux syntax (e.g. "POST /foo/{bar}").
	Pattern string
	Handler http.Handler
}

HandlerRoute pairs a ServeMux pattern with an http.Handler.

type Initializer added in v0.11.0

type Initializer interface {
	Init(context.Context) error
}

Initializer is an optional capability for instance-scoped setup (open DB, connect, validate config, etc.). Init runs once per instance load with the instance context (cancelled on reload/stop). Providers that need that context at request time should retain it on the provider value.

type Instance added in v0.4.0

type Instance struct {
	// contains filtered or unexported fields
}

Instance is a configured, immutable, xtemplate request handler ready to execute templates and serve static files in response to http requests.

The only way to create a valid Instance is to call the Config.Instance method. Configuration of an Instance is intended to be immutable. Instead of mutating a running Instance, build a new Instance from a modified Config and swap them.

See also Server which manages instances and enables reloading them.

func (*Instance) Close added in v0.11.0

func (x *Instance) Close() error

Close releases instance-scoped provider resources (Closer), then runs WithOnClose callbacks. Invocations after the first return a memoized result and do not call Closer.Close or WithOnClose callbacks again.

If requests are still in flight (grace period expired or Stop skipped drain), Close logs this as a warning.

func (*Instance) Id added in v0.4.0

func (x *Instance) Id() int64

Id returns the id of this instance which is unique in the current process. This differentiates multiple instances, as the instance id is attached to all logs generated by the instance with the attribute name `xtemplate.instance`.

func (*Instance) Routes added in v0.4.0

func (x *Instance) Routes() []InstanceRoute

Routes returns a copy of all the routes registered with this instance.

func (*Instance) ServeHTTP added in v0.5.0

func (instance *Instance) ServeHTTP(w http.ResponseWriter, r *http.Request)

func (*Instance) Stats added in v0.4.0

func (x *Instance) Stats() InstanceStats

Stats returns the instance build stats.

type InstanceRoute added in v0.4.0

type InstanceRoute struct {
	Pattern string
	Handler http.Handler
}

type InstanceStats added in v0.4.0

type InstanceStats struct {
	Routes                        int
	TemplateFiles                 int
	TemplateDefinitions           int
	InitializationTemplates       int
	StaticFiles                   int
	StaticFilesAlternateEncodings int
}

type MarkdownDoc added in v0.9.2

type MarkdownDoc struct {
	Meta map[string]any `json:"meta,omitempty"`
	Body template.HTML  `json:"body,omitempty"`
}

MarkdownDoc is the result of rendering Markdown: the decoded front matter metadata and the rendered HTML body.

func FuncMarkdown added in v0.5.0

func FuncMarkdown(input any, configName ...string) (MarkdownDoc, error)

markdown parses front matter out of the input and renders the remaining Markdown to HTML in a single pass, returning both .Meta and .Body. input may be a string, []byte, or io.Reader. This uses the Goldmark library, which is CommonMark compliant. If an alternative markdown policy is not named, it uses the default policy which has these extensions enabled: YAML/TOML front matter, Github Flavored Markdown, Footnote, and syntax highlighting provided by Chroma.

type Option added in v0.6.0

type Option func(*Config) error

func WithContext added in v0.11.0

func WithContext(ctx context.Context) Option

func WithController added in v0.11.0

func WithController(s ServerController) Option

WithController sets the ServerController. Rejected when building an Instance / Reload.

func WithFuncMaps added in v0.3.0

func WithFuncMaps(fm ...template.FuncMap) Option

func WithHandler added in v0.9.0

func WithHandler(pattern string, h http.Handler) Option

WithHandler mounts h at pattern on the instance ServeMux (net/http.ServeMux syntax, e.g. "POST /api/{id}" or "GET /healthz"). Appends to Config.Handlers.

Intended for embedding foreign handlers (API, webhooks, probes) as peer routes beside templates and static files.

func WithLogger added in v0.3.0

func WithLogger(logger *slog.Logger) Option

func WithMinify added in v0.11.0

func WithMinify(minify bool) Option

func WithOnClose added in v0.11.0

func WithOnClose(fn func() error) Option

WithOnClose registers fn to run when the Instance built with this option is [Instance.Close]d (reload retire or stop). Multiple callbacks append; they run after provider [Closer]s, reverse registration order. Nil fns ignored.

Per instance, not once per Server: on the sticky base, fn runs for every retired instance. Use sync.Once for process-wide cleanup, or pass WithOnClose only on the Reload that owns a per-build resource (e.g. a temp clone dir).

func WithProvider added in v0.5.0

func WithProvider(f ProviderFactory) Option

WithProvider appends a factory that produces a provider on each Instance build. The factory must not return nil. Rejects a nil factory.

func WithTemplateDir added in v0.11.0

func WithTemplateDir(dir string) Option

WithTemplateDir sets the private build-root FS to an OS directory.

func WithTemplateFS added in v0.3.3

func WithTemplateFS(fs afero.Fs) Option

WithTemplateFS sets the private build-root FS for the next Instance.

type OsFsController added in v0.11.0

type OsFsController struct {
	// Path is the templates directory. Default "templates".
	Path string `json:"path,omitempty" arg:"-t,--template-dir,--templates-dir" default:"templates"`
}

OsFsController serves templates from a local directory (JSON type "os").

func (*OsFsController) Init added in v0.11.0

func (s *OsFsController) Init(_ context.Context, _ *slog.Logger) ([]Option, error)

Init returns a sticky BasePathFs rooted at Path (default "templates").

func (*OsFsController) Start added in v0.11.0

func (s *OsFsController) Start(_ *Server) error

type Provider added in v0.11.0

type Provider interface {
	// FieldName is the exported struct field on the dot (e.g. "Shop" → {{.Shop}}).
	FieldName() string
	// Prototype returns a non-nil value of the field type. It is called once
	// when building the instance solely to infer the type via reflection; the
	// returned value is discarded. It must not depend on request data.
	Prototype() any
	// Value returns the value to assign to this provider's field for a request.
	// w and r are the HTTP response writer and request (same as http.Handler).
	// Request-scoped context is r.Context(); instance lifetime context should
	// have been saved during [Initializer.Init] if needed.
	Value(w http.ResponseWriter, r *http.Request) (any, error)
}

Provider contributes one named field on the per-request dot context.

Lifecycle:

  • [FieldName] and [Prototype] are used when an instance is built.
  • Optional Initializer.Init runs once per instance load (after config decode, before Prototype is used for type assembly). Save the instance context there if request-time code must observe reload/stop.
  • [Value] runs once per request (and for INIT templates).
  • Optional Finalizer.Finalize runs after template execution.
  • Optional Closer.Close runs when the instance is retired (reload/stop).

Optional hooks are separate capability interfaces (like http.Flusher); they do not embed Provider. Assert them when needed.

type ProviderFactory added in v0.11.0

type ProviderFactory func() Provider

ProviderFactory constructs a fresh Provider value. Sticky Config.Providers hold factories so each Instance / Reload build materializes new providers (matching JSON [resolveProviders] + registry constructors).

type ReturnError

type ReturnError struct{}

ReturnError is a sentinel value that indicates a successful/normal exit but causes template execution to stop immediately. Used by funcs and dot field methods to perform custom actions.

func (ReturnError) Error

func (ReturnError) Error() string

type Server added in v0.4.0

type Server struct {
	// contains filtered or unexported fields
}

Server is a reloadable http.Handler that always routes to the current Instance, or responds 503 when none is loaded or the server has stopped.

Optional ServerController: Init supplies sticky base options, then Start may drive reloads. The sticky base is fixed at construction.

Server.Reload rebuilds from sticky plus ephemeral options. Server.Shutdown / Server.Stop tear down; with Server.Serve, cancelling the server context also drains the local http.Server (not stored on Server).

Create only via Config.Server.

func (*Server) Context added in v0.11.0

func (server *Server) Context() context.Context

Context is cancelled on Stop/Shutdown. Controllers use it to halt background work.

func (*Server) Instance added in v0.4.0

func (server *Server) Instance() *Instance

Instance returns the current Instance. After calling Reload, previous calls to Instance may be stale. When not ready yet or after Stop/Shutdown, returns nil.

func (*Server) Logger added in v0.11.0

func (server *Server) Logger() *slog.Logger

Logger returns the server logger (xtemplate group applied at construction).

func (*Server) Reload added in v0.4.0

func (server *Server) Reload(options ...Option) error

Reload builds a new Instance from the sticky base plus options and swaps it in on success. Previous instance is cancelled, drained up to [defaultGrace], then closed (outside the mutex so concurrent Reload/Shutdown are not blocked). Ephemeral WithTemplateFS/Dir apply only to this build; empty Reload rebuilds from sticky. Fails if the final template root is nil. WithController is rejected.

func (*Server) Serve added in v0.4.0

func (server *Server) Serve(listen_addr string) error

Serve opens a net listener on `listen_addr` and serves requests from it. It returns when the listener fails or when the server context is cancelled (parent Config.Ctx or Server.Shutdown/Server.Stop), in which case the local http.Server is drained (default grace [defaultGrace]), the instance is retired, and Serve returns nil.

func (*Server) ServeHTTP added in v0.10.0

func (server *Server) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP routes the request to the current Instance, or responds 503 if no instance is loaded yet or the server has been stopped.

func (*Server) Shutdown added in v0.11.0

func (server *Server) Shutdown(ctx context.Context) error

Shutdown stops the server gracefully.

  1. Nils the current instance (new requests get 503) and cancels serverCtx (cascades into the instance context so SSE/Flush observe stop).
  2. Waits for in-flight instance requests up to ctx, then Closes providers.

When Server.Serve is running, cancelling serverCtx also causes Serve to drain its local http.Server; Shutdown itself does not own or call into it.

ctx bounds only the in-flight wait; teardown always runs. Safe if Serve never ran (handler-only / Caddy). Idempotent.

func (*Server) Stop added in v0.6.5

func (server *Server) Stop()

Stop is immediate teardown: no drain wait, then the same path as [Shutdown].

type ServerController added in v0.11.0

type ServerController interface {
	Init(ctx context.Context, log *slog.Logger) (sticky []Option, err error)
	Start(server *Server) error
}

ServerController is attached once per Server by Config.Server:

  • Init returns sticky [Option]s for the base config (no Server methods).
  • Start may drive reloads via server.Reload (safe to call synchronously).

Built-in: os. Optional: controllers/watchfs, controllers/git.

func NewController added in v0.11.0

func NewController(name string) (ServerController, error)

NewController returns a new zero-value ServerController for a registered type name.

func ResolveController added in v0.11.0

func ResolveController(raw json.RawMessage) (ServerController, error)

ResolveController decodes raw JSON by peeking its "type" field, looking up the constructor, and re-decoding into the concrete type.

Directories

Path Synopsis
standard
Package standard links the default Caddyfile parsers (providers + controllers), the pure-Go sqlite3 driver, and the xtemplate caddy module.
Package standard links the default Caddyfile parsers (providers + controllers), the pure-Go sqlite3 driver, and the xtemplate caddy module.
cmd module
xtemplate command
Default xtemplate CLI: providers, watchfs, git; default controller is watchfs.
Default xtemplate CLI: providers, watchfs, git; default controller is watchfs.
controllers
git
Package git is a ServerController that serves templates from a git repository via the installed `git` binary.
Package git is a ServerController that serves templates from a git repository via the installed `git` binary.
git/caddyfile
Package caddyfile registers the git controller Caddyfile parser.
Package caddyfile registers the git controller Caddyfile parser.
watchfs
Package watchfs is a ServerController that serves templates from a local directory and reloads when watched paths change.
Package watchfs is a ServerController that serves templates from a local directory and reloads when watched paths change.
watchfs/caddyfile
Package caddyfile registers the watchfs controller Caddyfile parser.
Package caddyfile registers the watchfs controller Caddyfile parser.
examples
dotprovider command
Custom dot provider example: the "repository pattern".
Custom dot provider example: the "repository pattern".
embedded command
Embedded single-binary example: the templates dir is compiled into the binary via //go:embed, so this binary serves its templates with no templates dir on disk at runtime.
Embedded single-binary example: the templates dir is compiled into the binary via //go:embed, so this binary serves its templates with no templates dir on disk at runtime.
internal module
providers
dotbus
Package dotbus implements the bus core dot provider: a process-local multi-producer multi-consumer topic fan-out for templates.
Package dotbus implements the bus core dot provider: a process-local multi-producer multi-consumer topic fan-out for templates.
dotbus/caddyfile
Package caddyfile registers the bus dot-provider for Caddyfile use.
Package caddyfile registers the bus dot-provider for Caddyfile use.
dotflags/caddyfile
Package caddyfile registers the flags dot-provider for Caddyfile use.
Package caddyfile registers the flags dot-provider for Caddyfile use.
dotfs
Package dotfs is the core filesystem xtemplate dot provider (type "fs").
Package dotfs is the core filesystem xtemplate dot provider (type "fs").
dotfs/caddyfile
Package caddyfile registers the fs dot-provider for Caddyfile use.
Package caddyfile registers the fs dot-provider for Caddyfile use.
dotnats/caddyfile
Package caddyfile registers the nats dot-provider for Caddyfile use.
Package caddyfile registers the nats dot-provider for Caddyfile use.
dotsmtp
Package smtp implements the smtp core dot provider, which exposes synchronous send-only SMTP mail delivery to templates via a dot field.
Package smtp implements the smtp core dot provider, which exposes synchronous send-only SMTP mail delivery to templates via a dot field.
dotsmtp/caddyfile
Package caddyfile registers the smtp dot-provider for Caddyfile use.
Package caddyfile registers the smtp dot-provider for Caddyfile use.
dotsql/caddyfile
Package caddyfile registers the sql dot-provider for Caddyfile use.
Package caddyfile registers the sql dot-provider for Caddyfile use.
nats module
register module
test module

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL