Skip to content

Commit 8a3870c

Browse files
committed
doc: Adjust README
1 parent 6f5d1dd commit 8a3870c

File tree

1 file changed

+77
-69
lines changed

1 file changed

+77
-69
lines changed

README.md

Lines changed: 77 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,56 @@
11
# xtemplate
22

33
`xtemplate` is a html/template-based hypertext preprocessor and rapid
4-
application development web server written in Go. It streamlines construction of
5-
hypermedia-exchange-oriented web sites by efficiently handling basic server
6-
tasks, enabling authors to focus on defining routes and responding to them using
7-
templates and configurable data sources.
4+
application development web server written in Go. Its good defaults handle
5+
typical server activity, enabling authors to focus on building
6+
hypermedia-exchange-oriented websites by defining routes and responding to them
7+
with template-generated HTML combined with configurable backing data stores.
88

99
## 🎯 Goal
1010

11-
After bulding some sites with [htmx](https://htmx.org) and Go, I wished that
12-
everything would just get out of the way of the fundamentals:
11+
Frustrated with the status-quo of frameworks that add more abstractions than
12+
they solve problems, I set out to create something that feels more like
13+
wrestling directly with first-class citizens of the web:
1314

14-
- URLs and path patterns
15-
- Access to a backing data source
16-
- Executing a template to return HTML
15+
- HTTP paths and matching server path patterns
16+
- Responding to an HTTP request with a template-generated HTML
17+
- Access to various backing data sources
1718

18-
🎇 **The idea of `xtemplate` is that *templates* can be the nexus of these
19-
fundamentals.**
19+
🎇 **The idea of `xtemplate` is that all of these can be managed with a
20+
directory of Go *template* files.**
2021

2122
<details><summary>🚫 Anti-goals</summary>
2223

23-
`xtemplate` needs to implement some of the things that are required to make a
24-
good web server in a way that avoids common issues with existing web server
25-
designs, otherwise they'll be in the way of the fundamentals:
26-
27-
* **Rigid template behavior**: Most designs relegate templates to be dumb string
28-
concatenators with just enough dynamic behavior to walk over some fixed data
29-
structure.
30-
* **Inefficient template loading**: Some designs read template files from disk
31-
and parse them on every request. This seems wasteful when the web server
32-
definition is typically static.
33-
* **Constant rebuilds**: On the other end of the spectrum, some designs require
34-
rebuilding the entire server from source when any little thing changes. This
35-
seems wasteful and makes graceful restarts more difficult than necessary when
36-
all you're doing is changing a button name.
37-
* **Repetitive route definitions**: Why should you have to name a http handler
38-
and add it to a central registry (or maintain a pile of code that plumbs these
39-
together for you) when new routes are often only relevant to the local html?
40-
* **Default unsafe**: Some designs require authors to vigilantly escape user
41-
inputs, risking XSS attacks that could have been avoided with less effort.
42-
* **Inefficient asset serving**: Some designs compress static assets at request
43-
time, instead of serving pre-compressed content with sendfile(2) and
44-
negotiated content encoding. Most designs don't give templates access to the
45-
hash of asset files, depriving clients of enough information to optimize
46-
caching behavior and check resource integrity.
24+
`xtemplate` implements things that are required to make a good web server in a
25+
way that avoids common pitfalls with existing engines:
26+
27+
- **Rigid template behavior**: Engines typically relegate templates to be dumb
28+
string concatenators with just enough dynamic behavior to walk over some known
29+
fixed data structure.
30+
- **Inefficient template loading**: Many engines often load template files from
31+
disk and parse them on *every request*, which is wasteful when web server
32+
definitions are largely static.
33+
- **Constant rebuilds**: Yet other engines rebuild the entire program from
34+
source when any little thing changes.
35+
- **Unnecessary handler names**: You've already had to name the http path and
36+
write the associated response template, why do you have to come up with a
37+
redundant name for the handler?
38+
- **Default unsafe**: Some engines require authors to vigilantly escape user
39+
inputs, risking XSS attacks that could have been avoided with less effort.
40+
- **Inefficient asset serving**: Many engines don't try to optimize serving
41+
assets at all and compress static assets at request time, instead of serving
42+
pre-compressed content with sendfile(2) and negotiated content encoding. Most
43+
designs don't give templates access to the hash of asset files, depriving
44+
authors of the right information to optimize cache behavior and check resource
45+
integrity.
4746

4847
</details>
4948

5049
## ✨ Features
5150

5251
*Click a feature to expand and show details:*
5352

54-
<details open><summary><strong>⚡ Efficient design</strong></summary>
53+
<details open><summary><strong>⚡ Efficient loading</strong></summary>
5554

5655
> All template files are read and parsed *once*, at startup, and kept in memory
5756
> during the life of an xtemplate *instance*. Requests are routed to a handler
@@ -77,14 +76,15 @@ designs, otherwise they'll be in the way of the fundamentals:
7776
> <script>new EventSource("/reload").onmessage = () => location.reload()</script>
7877
> <!-- Maybe not a great idea for production, but you do you. -->
7978
> ```
79+
>
8080
</details>
8181
8282
<details open><summary><strong>🗃️ Simple file-based routing</strong></summary>
8383
8484
> `GET` requests are handled by invoking a matching template file at that path.
8585
> (Hidden files that start with `.` are loaded but not routed by default.)
8686
>
87-
> ```
87+
> ```ascii
8888
> File path: HTTP path:
8989
> .
9090
> ├── index.html GET /
@@ -94,6 +94,7 @@ designs, otherwise they'll be in the way of the fundamentals:
9494
> └── shared
9595
> └── .head.html (not routed because it starts with '.')
9696
> ```
97+
>
9798
</details>
9899
99100
<details><summary><strong>🔱 Add custom routes to handle any method and path pattern</strong></summary>
@@ -105,7 +106,7 @@ designs, otherwise they'll be in the way of the fundamentals:
105106
> ```html
106107
> <!-- match on path parameters -->
107108
> {{define "GET /contact/{id}"}}
108-
> {{$contact := .QueryRow `SELECT name,phone FROM contacts WHERE id=?` (.Req.PathValue "id")}}
109+
> {{$contact := .DB.QueryRow `SELECT name,phone FROM contacts WHERE id=?` (.Req.PathValue "id")}}
109110
> <div>
110111
> <span>Name: {{$contact.name}}</span>
111112
> <span>Phone: {{$contact.phone}}</span>
@@ -114,7 +115,7 @@ designs, otherwise they'll be in the way of the fundamentals:
114115
>
115116
> <!-- match on any http method -->
116117
> {{define "DELETE /contact/{id}"}}
117-
> {{$_ := .Exec `DELETE from contacts WHERE id=?` (.Req.PathValue "id")}}
118+
> {{$_ := .DB.Exec `DELETE from contacts WHERE id=?` (.Req.PathValue "id")}}
118119
> {{.RespStatus 204}}
119120
> {{end}}
120121
> ```
@@ -141,6 +142,7 @@ designs, otherwise they'll be in the way of the fundamentals:
141142
> </body>
142143
> </html>
143144
> ```
145+
>
144146
</details>
145147
146148
<details><summary><strong>🛡️ XSS safe by default</strong></summary>
@@ -181,6 +183,7 @@ designs, otherwise they'll be in the way of the fundamentals:
181183
> {{end}}
182184
> </ul>
183185
> ```
186+
>
184187
</details>
185188
186189
<details><summary><strong>🗄️ Filesystem context provider: List and read local files</strong></summary>
@@ -191,11 +194,12 @@ designs, otherwise they'll be in the way of the fundamentals:
191194
> ```html
192195
> <p>Here are the files:
193196
> <ol>
194-
> {{range .ListFiles "dir/"}}
197+
> {{range .FS.List "dir/"}}
195198
> <li>{{.Name}}</li>
196199
> {{end}}
197200
> </ol>
198201
> ```
202+
>
199203
</details>
200204
201205
<details><summary><strong>💬 NATS context provider: Send and receive messages</strong></summary>
@@ -206,36 +210,34 @@ designs, otherwise they'll be in the way of the fundamentals:
206210
> ```html
207211
> <example></example>
208212
> ```
213+
>
209214
</details>
210215
211216
<details open><summary><strong>📤 Optimal asset serving</strong></summary>
212217
213218
> Non-template files in the templates directory are served directly from disk
214219
> with appropriate caching responses, negotiating with the client to serve
215-
> compressed versions. Efficient access to the content hash is available to
216-
> templates for efficient SRI and perfect cache behavior.
217-
>
218-
> If a static file also has .gz, .br, .zip, or .zst copies, they are decoded and
219-
> hashed for consistency on startup, and use the `Accept-Encoding` header to
220-
> negotiate an appropriate `Content-Encoding` with the client and served
221-
> directly from disk.
220+
> compressed encodings if corresponding `.zst`, `.zip`, `.gz`, `.br` files are present.
222221
>
223-
> Templates can efficiently access the static file's precalculated content hash
222+
> Templates can efficiently access static files' precalculated content hash
224223
> to build a `<script>` or `<link>` integrity attribute, instructing clients to
225224
> check the integrity of the content if they are served through a CDN. See:
226-
> [Subresource Integrity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity)
225+
> [Subresource Integrity (SRI)](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity)
227226
>
228227
> Add the content hash as a query parameter and responses will automatically add
229228
> a 1 year long `Cache-Control` header so clients can safely cache as long as
230229
> possible. If the file changes, its hash and thus query parameter will change
231-
> so the client will immediately request a new version, **entirely eliminating
230+
> and the client will immediately request a new version, **completely eliminating
232231
> stale cache issues**.
233232
>
233+
> This example uses both SRI and precise 1-year `Cache-Control`:
234+
>
234235
> ```html
235236
> {{- with $hash := .X.StaticFileHash `/assets/reset.css`}}
236237
> <link rel="stylesheet" href="/reset.css?hash={{$hash}}" integrity="{{$hash}}">
237238
> {{- end}}
238239
> ```
240+
>
239241
</details>
240242
241243
<details><summary><strong>📬 Live updates with Server Sent Events (SSE)</strong></summary>
@@ -256,15 +258,20 @@ designs, otherwise they'll be in the way of the fundamentals:
256258
257259
> Deploy next to your templates and static files or [embed](https://pkg.go.dev/embed)
258260
> them for single binary deployments.
259-
>
261+
>
260262
> ```go
261263
> //go:embed all:templates
262264
> var Files embed.FS
263265
> ```
266+
>
264267
</details>
265268
266269
## 📦 How to run
267270
271+
### 0. 📦 As a Docker container
272+
273+
...
274+
268275
### 1. 📦 As a Caddy plugin
269276
270277
The `xtemplate/caddy` plugin offers all `xtemplate` features integrated into
@@ -273,7 +280,7 @@ HTTP/1-2-3 web server with automatic HTTPS.
273280
274281
Download Caddy with `xtemplate/caddy` middleware plugin built-in:
275282
276-
https://caddyserver.com/download?package=github.com%2Finfogulch%2Fxtemplate&package=github.com%2Fncruces%2Fgo-sqlite3
283+
<https://caddyserver.com/download?package=github.com%2Finfogulch%2Fxtemplate&package=github.com%2Fncruces%2Fgo-sqlite3>
277284
278285
This is the simplest Caddyfile that uses the `xtemplate/caddy` plugin:
279286
@@ -326,6 +333,7 @@ Examples:
326333
Parse template files matching a custom extension and minify them:
327334
$ ./xtemplate --template-ext ".go.html" --minify
328335
```
336+
329337
</details>
330338
331339
### 3. 📦 As a Go library
@@ -396,11 +404,11 @@ custom fields with your own methods.
396404
397405
These fields are always present in relevant template invocations:
398406
399-
* Access instance data with the `.X` field. See [DotX]
400-
* Access request details with the `.Req` field. See [DotReq]
401-
* Control the HTTP response in buffered template handlers with the `.Resp`
407+
- Access instance data with the `.X` field. See [DotX]
408+
- Access request details with the `.Req` field. See [DotReq]
409+
- Control the HTTP response in buffered template handlers with the `.Resp`
402410
field. See [DotResp]
403-
* Control flushing behavior for flushing template handlers (i.e. SSE) with the
411+
- Control flushing behavior for flushing template handlers (i.e. SSE) with the
404412
`.Flush` field. See [DotFlush]
405413
406414
[DotX]: https://pkg.go.dev/github.com/infogulch/xtemplate#DotX
@@ -413,9 +421,9 @@ These fields are always present in relevant template invocations:
413421
These optional value providers can be configured with any field name, and can be
414422
configured multiple times with different configurations.
415423
416-
* Read and list files. See [DotFS]
417-
* Query and execute SQL statements. See [DotDB]
418-
* Read template-level key-value map. See [DotKV]
424+
- Read and list files. See [DotFS]
425+
- Query and execute SQL statements. See [DotDB]
426+
- Read template-level key-value map. See [DotKV]
419427
420428
[DotFS]: https://pkg.go.dev/github.com/infogulch/xtemplate/providers#DotFS
421429
[DotDB]: https://pkg.go.dev/github.com/infogulch/xtemplate/providers#DotDB
@@ -435,15 +443,15 @@ sprig library, and custom functions added by xtemplate.
435443
436444
You can custom FuncMaps by configuring the `Config.FuncMaps` field.
437445
438-
* 📏 `xtemplate` includes funcs to render markdown, sanitize html, convert
446+
- 📏 `xtemplate` includes funcs to render markdown, sanitize html, convert
439447
values to human-readable forms, and to try to call a function to handle an
440448
error within the template. See the free functions named [`FuncXYZ(...)` in
441449
xtemplate's Go docs][funcgodoc] for details.
442-
* 📏 Sprig publishes a library of useful template funcs that enable templates to
450+
- 📏 Sprig publishes a library of useful template funcs that enable templates to
443451
manipulate strings, integers, floating point numbers, and dates, as well as
444452
perform encoding tasks, manipulate lists and dicts, converting types,
445453
and manipulate file paths See [Sprig Function Documentation][sprig].
446-
* 📏 Go's built in functions add logic and basic printing functionality.
454+
- 📏 Go's built in functions add logic and basic printing functionality.
447455
See: [text/template#Functions][gofuncs].
448456
449457
[funcgodoc]: https://pkg.go.dev/github.com/infogulch/xtemplate#FuncHumanize
@@ -452,30 +460,30 @@ You can custom FuncMaps by configuring the `Config.FuncMaps` field.
452460
453461
## 🏆 Users
454462
455-
* [PixyBlue/lazy-lob-web](https://github.com/PixyBlue/lazy-lob-web), a fullstack web lob framework.
456-
* [infogulch/xrss](https://github.com/infogulch/xrss), an rss feed reader built with htmx and inline css.
457-
* [infogulch/todos](https://github.com/infogulch/todos), a demo todomvc application.
463+
- [PixyBlue/lazy-lob-web](https://github.com/PixyBlue/lazy-lob-web), a fullstack web lob framework.
464+
- [infogulch/xrss](https://github.com/infogulch/xrss), an rss feed reader built with htmx and inline css.
465+
- [infogulch/todos](https://github.com/infogulch/todos), a demo todomvc application.
458466
459467
## 👷‍♀️ Development
460468
461469
### 🗺️ Repository structure
462470
463471
xtemplate is split into the following packages:
464472
465-
* `github.com/infogulch/xtemplate` is a library that exports the `Instance`
473+
- `github.com/infogulch/xtemplate` is a library that exports the `Instance`
466474
struct which can load template files and implements `http.Handler` that
467475
routes requests to templates and serves static files, the `Server` struct
468476
which can atomically reload an `Instance` on demand, and a number of built-in
469477
providers.
470-
* `./app` is a library that contains an exported `Main` function which
478+
- `./app` is a library that contains an exported `Main` function which
471479
configures and starts xtemplate with CLI args and accepts config override
472480
parameters. This `Main` fucntion can be used as a reference for using the
473481
`xtemplate` API in advanced use-cases.
474-
* `./cmd` is a binary that simply imports a database driver and runs
482+
- `./cmd` is a binary that simply imports a database driver and runs
475483
`xtemplate/app.Main()`. The recommended way to begin customizing
476484
xtemplate is to copy the `./cmd` package to your own repo, then add your
477485
own database driver, provide custom config overrides, etc.
478-
* `./caddy` is a [Caddy module](https://caddyserver.com/docs/extending-caddy)
486+
- `./caddy` is a [Caddy module](https://caddyserver.com/docs/extending-caddy)
479487
package that uses xtemplate's Go library API to integrate xtemplate into Caddy
480488
server.
481489

0 commit comments

Comments
 (0)