infogulch / xtemplate

A html/template-based hypertext preprocessor and rapid application development web server written in Go.
Apache License 2.0
73 stars 1 forks source link
go golang html html-template hypermedia webserver

xtemplate

xtemplate is a html/template-based hypertext preprocessor and rapid application development web server written in Go. It streamlines construction of hypermedia-exchange-oriented web sites by efficiently handling basic server tasks, enabling authors to focus on defining routes and responding to them using templates and configurable data sources.

🎯 Goal

After bulding some sites with htmx and Go, I wished that everything would just get out of the way of the fundamentals:

πŸŽ‡ The idea of xtemplate is that templates can be the nexus of these fundamentals.

🚫 Anti-goals `xtemplate` needs to implement some of the things that are required to make a good web server in a way that avoids common issues with existing web server designs, otherwise they'll be in the way of the fundamentals: * **Rigid template behavior**: Most designs relegate templates to be dumb string concatenators with just enough dynamic behavior to walk over some fixed data structure. * **Inefficient template loading**: Some designs read template files from disk and parse them on every request. This seems wasteful when the web server definition is typically static. * **Constant rebuilds**: On the other end of the spectrum, some designs require rebuilding the entire server from source when any little thing changes. This seems wasteful and makes graceful restarts more difficult than necessary when all you're doing is changing a button name. * **Repetitive route definitions**: Why should you have to name a http handler and add it to a central registry (or maintain a pile of code that plumbs these together for you) when new routes are often only relevant to the local html? * **Default unsafe**: Some designs require authors to vigilantly escape user inputs, risking XSS attacks that could have been avoided with less effort. * **Inefficient asset serving**: Some designs compress static assets at request time, instead of serving pre-compressed content with sendfile(2) and negotiated content encoding. Most designs don't give templates access to the hash of asset files, depriving clients of enough information to optimize caching behavior and check resource integrity.

✨ Features

Click a feature to expand and show details:

⚑ Efficient design > All template files are read and parsed *once*, at startup, and kept in memory > during the life of an xtemplate *instance*. Requests are routed to a handler > that immediately starts executing a template reference in response. No slow > cascading disk accesses or parsing overhead before you even begin crafting the > response.
πŸ”„ Live reload > Template files are loaded into a new instance and validated milliseconds after > they are modified, no need to restart the server. If an error occurs during > load the previous instance remains intact and continues to serve while the > loading error is printed to the logs. A successful reload atomically swaps the > handler so new requests are served by the new instance; pending requests are > allowed to complete gracefully. > > Add this template definition and one-line script to your page, then > clients will automatically reload when the server does: > > ```html > {{- define "SSE /reload"}}{{.WaitForServerStop}}data: reload{{printf "\n\n"}}{{end}} > > > ```
πŸ—ƒοΈ Simple file-based routing > `GET` requests are handled by invoking a matching template file at that path. > (Hidden files that start with `.` are loaded but not routed by default.) > > ``` > File path: HTTP path: > . > β”œβ”€β”€ index.html GET / > β”œβ”€β”€ todos.html GET /todos > β”œβ”€β”€ admin > β”‚ └── settings.html GET /admin/settings > └── shared > └── .head.html (not routed because it starts with '.') > ```
πŸ”± Add custom routes to handle any method and path pattern > Handle any [Go 1.22 ServeMux][servemux] pattern by **defining a template with > that pattern as its name**. Path placeholders are available during template > execution with the `.Req.PathValue` method. > > ```html > > {{define "GET /contact/{id}"}} > {{$contact := .QueryRow `SELECT name,phone FROM contacts WHERE id=?` (.Req.PathValue "id")}} >
> Name: {{$contact.name}} > Phone: {{$contact.phone}} >
> {{end}} > > > {{define "DELETE /contact/{id}"}} > {{$_ := .Exec `DELETE from contacts WHERE id=?` (.Req.PathValue "id")}} > {{.RespStatus 204}} > {{end}} > ``` [servemux]: https://tip.golang.org/doc/go1.22#enhanced_routing_patterns
πŸ‘¨β€πŸ’» Define and invoke custom templates > All html files under the template root directory are available to invoke by > their full path relative to the template root dir starting with `/`: > > ```html > > Home > > {{template "/shared/.head.html" .}} > > > > {{template "navbar" .}} > ... > > > ```
πŸ›‘οΈ XSS safe by default > The html/template library automatically escapes user content, so you can rest > easy from basic XSS attacks. The defacto standard html sanitizer for Go, > BlueMonday, is available for cases where you need finer grained control. > > If you have some html string that you do trust, it's easy to inject if that's > your intention with the `trustHtml` func.
🎨 Customize the context to provide selected data sources > Configure xtemplate to get access to built-in and custom data sources like > running SQL queries against a database, sending and receiving messages using a > message streaming client like NATS, read and list files from a local > directory, reading static config from a key-value store, **or perform any > action you can define by writing a Go API**, like the common "repository" > design pattern for example. > > Modify `Config` to add built-in or custom `ContextProvider` implementations, > and they will be made available in the dot context. > > Some built-in context providers are listed next:
πŸ’½ Database context provider: Execute queries > Add the built-in Database Context Provider to run queries using the configured > Go driver and connection string for your database. (Supports the `sqlite3` > driver by default, compile with your desired driver to use it.) > > ```html >
    > {{range .Tx.Query `SELECT id,name FROM contacts`}} >
  • {{.name}}
  • > {{end}} >
> ```
πŸ—„οΈ Filesystem context provider: List and read local files > Add the built-in Filesystem Context Provider to List and read > files from the configured directory. > > ```html >

Here are the files: >

    > {{range .ListFiles "dir/"}} >
  1. {{.Name}}
  2. > {{end}} >
> ```
πŸ’¬ NATS context provider: Send and receive messages > Add and configure the NATS Context Provider to send messages, use the > Request-Response pattern, and even send live updates to a client. > > ```html > > ```
πŸ“€ Optimal asset serving > Non-template files in the templates directory are served directly from disk > with appropriate caching responses, negotiating with the client to serve > compressed versions. Efficient access to the content hash is available to > templates for efficient SRI and perfect cache behavior. > > If a static file also has .gz, .br, .zip, or .zst copies, they are decoded and > hashed for consistency on startup, and use the `Accept-Encoding` header to > negotiate an appropriate `Content-Encoding` with the client and served > directly from disk. > > Templates can efficiently access the static file's precalculated content hash > to build a ` Githubissues.
  • Githubissues is a development platform for aggregating issues.