{"id":16133222,"url":"https://github.com/infogulch/xtemplate","last_synced_at":"2025-03-31T09:04:10.852Z","repository":{"id":183551599,"uuid":"670288798","full_name":"infogulch/xtemplate","owner":"infogulch","description":"A html/template-based hypertext preprocessor and rapid application development web server written in Go.","archived":false,"fork":false,"pushed_at":"2024-10-10T04:25:22.000Z","size":422,"stargazers_count":74,"open_issues_count":6,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-10-10T22:37:48.414Z","etag":null,"topics":["go","golang","html","html-template","hypermedia","webserver"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/infogulch.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-07-24T17:57:11.000Z","updated_at":"2024-10-10T02:55:25.000Z","dependencies_parsed_at":"2023-10-20T08:40:38.118Z","dependency_job_id":"0d1ae1d6-3182-42f5-bfba-525f314a4492","html_url":"https://github.com/infogulch/xtemplate","commit_stats":null,"previous_names":["infogulch/caddy-xtemplates","infogulch/caddy-xtemplate","infogulch/xtemplate"],"tags_count":29,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/infogulch%2Fxtemplate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/infogulch%2Fxtemplate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/infogulch%2Fxtemplate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/infogulch%2Fxtemplate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/infogulch","download_url":"https://codeload.github.com/infogulch/xtemplate/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246443536,"owners_count":20778248,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","golang","html","html-template","hypermedia","webserver"],"created_at":"2024-10-09T22:38:10.950Z","updated_at":"2025-03-31T09:04:10.836Z","avatar_url":"https://github.com/infogulch.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# xtemplate\n\n`xtemplate` is a html/template-based hypertext preprocessor and rapid\napplication development web server written in Go. It streamlines construction of\nhypermedia-exchange-oriented web sites by efficiently handling basic server\ntasks, enabling authors to focus on defining routes and responding to them using\ntemplates and configurable data sources.\n\n## 🎯 Goal\n\nAfter bulding some sites with [htmx](https://htmx.org) and Go, I wished that\neverything would just get out of the way of the fundamentals:\n\n- URLs and path patterns\n- Access to a backing data source\n- Executing a template to return HTML\n\n🎇 **The idea of `xtemplate` is that *templates* can be the nexus of these\nfundamentals.**\n\n\u003cdetails\u003e\u003csummary\u003e🚫 Anti-goals\u003c/summary\u003e\n\n`xtemplate` needs to implement some of the things that are required to make a\ngood web server in a way that avoids common issues with existing web server\ndesigns, otherwise they'll be in the way of the fundamentals:\n\n* **Rigid template behavior**: Most designs relegate templates to be dumb string\n  concatenators with just enough dynamic behavior to walk over some fixed data\n  structure.\n* **Inefficient template loading**: Some designs read template files from disk\n  and parse them on every request. This seems wasteful when the web server\n  definition is typically static.\n* **Constant rebuilds**: On the other end of the spectrum, some designs require\n  rebuilding the entire server from source when any little thing changes. This\n  seems wasteful and makes graceful restarts more difficult than necessary when\n  all you're doing is changing a button name.\n* **Repetitive route definitions**: Why should you have to name a http handler\n  and add it to a central registry (or maintain a pile of code that plumbs these\n  together for you) when new routes are often only relevant to the local html?\n* **Default unsafe**: Some designs require authors to vigilantly escape user\n  inputs, risking XSS attacks that could have been avoided with less effort.\n* **Inefficient asset serving**: Some designs compress static assets at request\n  time, instead of serving pre-compressed content with sendfile(2) and\n  negotiated content encoding. Most designs don't give templates access to the\n  hash of asset files, depriving clients of enough information to optimize\n  caching behavior and check resource integrity.\n\n\u003c/details\u003e\n\n## ✨ Features\n\n*Click a feature to expand and show details:*\n\n\u003cdetails open\u003e\u003csummary\u003e\u003cstrong\u003e⚡ Efficient design\u003c/strong\u003e\u003c/summary\u003e\n\n\u003e All template files are read and parsed *once*, at startup, and kept in memory\n\u003e during the life of an xtemplate *instance*. Requests are routed to a handler\n\u003e that immediately starts executing a template reference in response. No slow\n\u003e cascading disk accesses or parsing overhead before you even begin crafting the\n\u003e response.\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003e🔄 Live reload\u003c/strong\u003e\u003c/summary\u003e\n\n\u003e Template files are loaded into a new instance and validated milliseconds after\n\u003e they are modified, no need to restart the server. If an error occurs during\n\u003e load the previous instance remains intact and continues to serve while the\n\u003e loading error is printed to the logs. A successful reload atomically swaps the\n\u003e handler so new requests are served by the new instance; pending requests are\n\u003e allowed to complete gracefully.\n\u003e\n\u003e Add this template definition and one-line script to your page, then\n\u003e clients will automatically reload when the server does:\n\u003e\n\u003e ```html\n\u003e {{- define \"SSE /reload\"}}{{.WaitForServerStop}}data: reload{{printf \"\\n\\n\"}}{{end}}\n\u003e \u003cscript\u003enew EventSource(\"/reload\").onmessage = () =\u003e location.reload()\u003c/script\u003e\n\u003e \u003c!-- Maybe not a great idea for production, but you do you. --\u003e\n\u003e ```\n\u003c/details\u003e\n\n\u003cdetails open\u003e\u003csummary\u003e\u003cstrong\u003e🗃️ Simple file-based routing\u003c/strong\u003e\u003c/summary\u003e\n\n\u003e `GET` requests are handled by invoking a matching template file at that path.\n\u003e (Hidden files that start with `.` are loaded but not routed by default.)\n\u003e\n\u003e ```\n\u003e File path:              HTTP path:\n\u003e .\n\u003e ├── index.html          GET /\n\u003e ├── todos.html          GET /todos\n\u003e ├── admin\n\u003e │   └── settings.html   GET /admin/settings\n\u003e └── shared\n\u003e     └── .head.html      (not routed because it starts with '.')\n\u003e ```\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003e🔱 Add custom routes to handle any method and path pattern\u003c/strong\u003e\u003c/summary\u003e\n\n\u003e Handle any [Go 1.22 ServeMux][servemux] pattern by **defining a template with\n\u003e that pattern as its name**. Path placeholders are available during template\n\u003e execution with the `.Req.PathValue` method.\n\u003e\n\u003e ```html\n\u003e \u003c!-- match on path parameters --\u003e\n\u003e {{define \"GET /contact/{id}\"}}\n\u003e {{$contact := .QueryRow `SELECT name,phone FROM contacts WHERE id=?` (.Req.PathValue \"id\")}}\n\u003e \u003cdiv\u003e\n\u003e   \u003cspan\u003eName: {{$contact.name}}\u003c/span\u003e\n\u003e   \u003cspan\u003ePhone: {{$contact.phone}}\u003c/span\u003e\n\u003e \u003c/div\u003e\n\u003e {{end}}\n\u003e\n\u003e \u003c!-- match on any http method --\u003e\n\u003e {{define \"DELETE /contact/{id}\"}}\n\u003e {{$_ := .Exec `DELETE from contacts WHERE id=?` (.Req.PathValue \"id\")}}\n\u003e {{.RespStatus 204}}\n\u003e {{end}}\n\u003e ```\n\n[servemux]: https://tip.golang.org/doc/go1.22#enhanced_routing_patterns\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003e👨‍💻 Define and invoke custom templates\u003c/strong\u003e\u003c/summary\u003e\n\n\u003e All html files under the template root directory are available to invoke by\n\u003e their full path relative to the template root dir starting with `/`:\n\u003e\n\u003e ```html\n\u003e \u003chtml\u003e\n\u003e   \u003ctitle\u003eHome\u003c/title\u003e\n\u003e   \u003c!-- import the contents of another file --\u003e\n\u003e   {{template \"/shared/.head.html\" .}}\n\u003e\n\u003e   \u003cbody\u003e\n\u003e     \u003c!-- invoke a custom named template defined anywhere --\u003e\n\u003e     {{template \"navbar\" .}}\n\u003e     ...\n\u003e   \u003c/body\u003e\n\u003e \u003c/html\u003e\n\u003e ```\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003e🛡️ XSS safe by default\u003c/strong\u003e\u003c/summary\u003e\n\n\u003e The html/template library automatically escapes user content, so you can rest\n\u003e easy from basic XSS attacks. The defacto standard html sanitizer for Go,\n\u003e BlueMonday, is available for cases where you need finer grained control.\n\u003e\n\u003e If you have some html string that you do trust, it's easy to inject if that's\n\u003e your intention with the `trustHtml` func.\n\u003c/details\u003e\n\n\u003cdetails open\u003e\u003csummary\u003e\u003cstrong\u003e🎨 Customize the context to provide selected data sources\u003c/strong\u003e\u003c/summary\u003e\n\n\u003e Configure xtemplate to get access to built-in and custom data sources like\n\u003e running SQL queries against a database, sending and receiving messages using a\n\u003e message streaming client like NATS, read and list files from a local\n\u003e directory, reading static config from a key-value store, **or perform any\n\u003e action you can define by writing a Go API**, like the common \"repository\"\n\u003e design pattern for example.\n\u003e\n\u003e Modify `Config` to add built-in or custom `ContextProvider` implementations,\n\u003e and they will be made available in the dot context.\n\u003e\n\u003e Some built-in context providers are listed next:\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003e💽 Database context provider: Execute queries\u003c/strong\u003e\u003c/summary\u003e\n\n\u003e Add the built-in Database Context Provider to run queries using the configured\n\u003e Go driver and connection string for your database. (Supports the `sqlite3`\n\u003e driver by default, compile with your desired driver to use it.)\n\u003e\n\u003e ```html\n\u003e \u003cul\u003e\n\u003e   {{range .DB.Query `SELECT id,name FROM contacts`}}\n\u003e   \u003cli\u003e\u003ca href=\"/contact/{{.id}}\"\u003e{{.name}}\u003c/a\u003e\u003c/li\u003e\n\u003e   {{end}}\n\u003e \u003c/ul\u003e\n\u003e ```\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003e🗄️ Filesystem context provider: List and read local files\u003c/strong\u003e\u003c/summary\u003e\n\n\u003e Add the built-in Filesystem Context Provider to List and read\n\u003e files from the configured directory.\n\u003e\n\u003e ```html\n\u003e \u003cp\u003eHere are the files:\n\u003e \u003col\u003e\n\u003e {{range .ListFiles \"dir/\"}}\n\u003e   \u003cli\u003e{{.Name}}\u003c/li\u003e\n\u003e {{end}}\n\u003e \u003c/ol\u003e\n\u003e ```\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003e💬 NATS context provider: Send and receive messages\u003c/strong\u003e\u003c/summary\u003e\n\n\u003e Add and configure the NATS Context Provider to send messages, use the\n\u003e Request-Response pattern, and even send live updates to a client.\n\u003e\n\u003e ```html\n\u003e \u003cexample\u003e\u003c/example\u003e\n\u003e ```\n\u003c/details\u003e\n\n\u003cdetails open\u003e\u003csummary\u003e\u003cstrong\u003e📤 Optimal asset serving\u003c/strong\u003e\u003c/summary\u003e\n\n\u003e Non-template files in the templates directory are served directly from disk\n\u003e with appropriate caching responses, negotiating with the client to serve\n\u003e compressed versions. Efficient access to the content hash is available to\n\u003e templates for efficient SRI and perfect cache behavior.\n\u003e\n\u003e If a static file also has .gz, .br, .zip, or .zst copies, they are decoded and\n\u003e hashed for consistency on startup, and use the `Accept-Encoding` header to\n\u003e negotiate an appropriate `Content-Encoding` with the client and served\n\u003e directly from disk.\n\u003e\n\u003e Templates can efficiently access the static file's precalculated content hash\n\u003e to build a `\u003cscript\u003e` or `\u003clink\u003e` integrity attribute, instructing clients to\n\u003e check the integrity of the content if they are served through a CDN. See:\n\u003e [Subresource Integrity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity)\n\u003e\n\u003e Add the content hash as a query parameter and responses will automatically add\n\u003e a 1 year long `Cache-Control` header so clients can safely cache as long as\n\u003e possible. If the file changes, its hash and thus query parameter will change\n\u003e so the client will immediately request a new version, **entirely eliminating\n\u003e stale cache issues**.\n\u003e\n\u003e ```html\n\u003e {{- with $hash := .X.StaticFileHash `/assets/reset.css`}}\n\u003e \u003clink rel=\"stylesheet\" href=\"/reset.css?hash={{$hash}}\" integrity=\"{{$hash}}\"\u003e\n\u003e {{- end}}\n\u003e ```\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003e📬 Live updates with Server Sent Events (SSE)\u003c/strong\u003e\u003c/summary\u003e\n\n\u003e Define a template with a name that starts with SSE, like `SSE /url/path`, and\n\u003e SSE requests will be handled by invoking the template. Individual messages can\n\u003e be sent by using `.Flush`, and the template can be paused to wait on messages\n\u003e sent over Go channels or can block on server shutdown.\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003e🐜 Small footprint and easy deployment\u003c/strong\u003e\u003c/summary\u003e\n\n\u003e Compiles to a ~30MB binary. Easily add your own custom functions and choice of\n\u003e database driver on top. Deploy next to your templates and static files or\n\u003e [embed](https://pkg.go.dev/embed) them into the binary for single binary\n\u003e deployments.\n\u003c/details\u003e\n\n## 📦 How to run\n\n### 1. 📦 As a Caddy plugin\n\nThe `xtemplate-caddy` plugin offers all `xtemplate` features integrated into\n[Caddy](https://caddyserver.com), a fast and extensible multi-platform\nHTTP/1-2-3 web server with automatic HTTPS.\n\nDownload Caddy with `xtemplate-caddy` middleware plugin built-in:\n\nhttps://caddyserver.com/download?package=github.com%2Finfogulch%2Fxtemplate-caddy\n\nThis is the simplest Caddyfile that uses the `xtemplate-caddy` plugin:\n\n```Caddyfile\nroutes {\n  xtemplate\n}\n```\n\nAlternatively, build with the `xcaddy` CLI tool.\n\n### 2. 📦 As the default CLI application\n\nDownload from the [Releases page](https://github.com/infogulch/xtemplate/releases) or build the binary in [`./cmd`](./cmd/).\n\nCustom builds can include your chosen db drivers, make Go functions available to\nthe template definitions, and even embed templates for true single binary\ndeployments. The [`./cmd` package](./cmd/) is the reference CLI application,\nconsider starting your customization there.\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003e🎏 CLI flags and examples: (click to show)\u003c/strong\u003e\u003c/summary\u003e\n\n```shell\n$ ./xtemplate -h\nv0.8.2\nUsage: xtemplate [--template-dir TEMPLATE-DIR] [--template-ext TEMPLATE-EXT] [--minify] [--ldelim LDELIM] [--rdelim RDELIM] [--watch WATCH] [--watchtemplates] [--listen LISTEN] [--loglevel LOGLEVEL] [--config CONFIG] [--config-file CONFIG-FILE]\n\nOptions:\n  --template-dir TEMPLATE-DIR, -t TEMPLATE-DIR [default: templates]\n  --template-ext TEMPLATE-EXT [default: .html]\n  --minify, -m [default: true]\n  --ldelim LDELIM [default: {{]\n  --rdelim RDELIM [default: }}]\n  --watch WATCH\n  --watchtemplates [default: true]\n  --listen LISTEN, -l LISTEN [default: 0.0.0.0:8080]\n  --loglevel LOGLEVEL [default: -2]\n  --config CONFIG, -c CONFIG\n  --config-file CONFIG-FILE, -f CONFIG-FILE\n  --help, -h             display this help and exit\n  --version              display version and exit\n\nExamples:\n    Listen on port 80:\n    $ ./xtemplate --listen :80\n\n    Specify a context directory and reload when it changes:\n    $ ./xtemplate --template-dir public --watch-templates\n\n    Parse template files matching a custom extension and minify them:\n    $ ./xtemplate --template-ext \".go.html\" --minify\n```\n\u003c/details\u003e\n\n### 3. 📦 As a Go library\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/infogulch/xtemplate.svg)](https://pkg.go.dev/github.com/infogulch/xtemplate)\n\nxtemplate's public Go API starts with a [`xtemplate.Config`](./config.go),\nfrom which you can get either an [`xtemplate.Instance`](./instance.go) interface\nor a [`xtemplate.Server`](./server.go) interface, with the methods\n`config.Instance()` and `config.Server()`, respectively.\n\nAn `xtemplate.Instance` is an immutable `http.Handler` that can handle requests,\nand exposes some metadata about the files loaded as well as the ServeMux\npatterns and associated handlers for individual routes. An `xtemplate.Server`\nalso handles http requests by forwarding requests to an internal Instance, but\nthe `Server` can be reloaded by calling `server.Reload()`, which creates a new\nInstance with the previous config and atomically switches the handler to direct\nnew requests to the new Instance.\n\nUse an Instance if you have no interest in reloading, or if you want to use\nxtemplate handlers in your own mux. Use a Server if you want an easy way to\nsmoothly reload and replace the xtemplate Instance behind a http.Handler at\nruntime.\n\n## 👨‍🏭 How to use\n\n### 🧰 Template semantics\n\n`xtemplate` templates are based on Go's `html/template` package, with some\nadditional features and enhancements. Here are the key things to keep in mind:\n\n- All template files are loaded recursively from the specified root directory,\n  and they are parsed and cached in memory at startup.\n- Each template file is associated with a specific route based on its file path.\n  For example, `index.html` in the root directory will handle requests to the\n  `/` path, while `admin/settings.html` will handle requests to\n  `/admin/settings`.\n- You can define custom routes by defining a template with a special name in\n  your template files. For example, `{{define \"GET /custom-route\"}}...{{end}}`\n  will create a new route that handles GET requests to `/custom-route`. Names\n  also support path parameters as defined by [http.ServeMux][servemux].\n- Template files can be invoked from within other templates using either their\n  full path relative to the template root or by using its defined template name.\n- Templates are executed with a uniform context object, which provides access to\n  request data, database connections, and other useful dynamic functionality.\n- Templates can also call functions set at startup.\n\n\u003e [!note]\n\u003e\n\u003e Custom dot fields and functions are similar in that they both add\n\u003e functionality to the templates, but dot fields are distinguished in that they\n\u003e are initialized on every request with access to request-scoped details\n\u003e including the underlying `http.Request` and `http.ResponseWriter` objects, the\n\u003e request-scoped logger, and the server context.\n\u003e\n\u003e Thus FuncMap functions are recommended for adding simple computational\n\u003e functionality (like parsing, escaping, data structure manipulation, etc),\n\u003e whereas dot fields are recommended for more complicated tasks like accessing\n\u003e network resources, running database queries, accessing the file system, etc.\n\n### 📝 Context\n\nThe dot context `{{.}}` set on each template invocation provides access to\nrequest-specific data and response control methods, and can be modified to add\ncustom fields with your own methods.\n\n#### ✏️ Built-in dot fields\n\nThese fields are always present in relevant template invocations:\n\n* Access instance data with the `.X` field. See [DotX]\n* Access request details with the `.Req` field. See [DotReq]\n* Control the HTTP response in buffered template handlers with the `.Resp`\n  field. See [DotResp]\n* Control flushing behavior for flushing template handlers (i.e. SSE) with the\n  `.Flush` field. See [DotFlush]\n\n[DotX]: https://pkg.go.dev/github.com/infogulch/xtemplate#DotX\n[DotReq]: https://pkg.go.dev/github.com/infogulch/xtemplate#DotReq\n[DotResp]: https://pkg.go.dev/github.com/infogulch/xtemplate#DotResp\n[DotFlush]: https://pkg.go.dev/github.com/infogulch/xtemplate#DotFlush\n\n#### ✏️ Optional dot fields\n\nThese optional value providers can be configured with any field name, and can be\nconfigured multiple times with different configurations.\n\n* Read and list files. See [DotFS]\n* Query and execute SQL statements. See [DotDB]\n* Read template-level key-value map. See [DotKV]\n\n[DotFS]: https://pkg.go.dev/github.com/infogulch/xtemplate/providers#DotFS\n[DotDB]: https://pkg.go.dev/github.com/infogulch/xtemplate/providers#DotDB\n[DotKV]: https://pkg.go.dev/github.com/infogulch/xtemplate/providers#DotKV\n\n#### ✏️ Custom dot fields\n\nYou can create custom dot fields that expose arbitrary Go functionality to your\ntemplates. See [👩‍⚕️ Writing a custom `DotProvider`](#-writing-a-custom-dotprovider).\n\n### 📐 Functions\n\nThese are built-in functions that are available to all invocations and don't\ndepend on request context or mutate state. There are three sets by default:\nfunctions that come by default in the go template library, functions from the\nsprig library, and custom functions added by xtemplate.\n\nYou can custom FuncMaps by configuring the `Config.FuncMaps` field.\n\n* 📏 `xtemplate` includes funcs to render markdown, sanitize html, convert\n  values to human-readable forms, and to try to call a function to handle an\n  error within the template. See the free functions named [`FuncXYZ(...)` in\n  xtemplate's Go docs][funcgodoc] for details.\n* 📏 Sprig publishes a library of useful template funcs that enable templates to\n  manipulate strings, integers, floating point numbers, and dates, as well as\n  perform encoding tasks, manipulate lists and dicts, converting types,\n  and manipulate file paths See [Sprig Function Documentation][sprig].\n* 📏 Go's built in functions add logic and basic printing functionality.\n  See: [text/template#Functions][gofuncs].\n\n[funcgodoc]: https://pkg.go.dev/github.com/infogulch/xtemplate#FuncHumanize\n[sprig]: https://masterminds.github.io/sprig/\n[gofuncs]: https://pkg.go.dev/text/template#hdr-Functions\n\n## 🏆 Users\n\n* [PixyBlue/lazy-lob-web](https://github.com/PixyBlue/lazy-lob-web), a fullstack web lob framework.\n* [infogulch/xrss](https://github.com/infogulch/xrss), an rss feed reader built with htmx and inline css.\n* [infogulch/todos](https://github.com/infogulch/todos), a demo todomvc application.\n\n## 👷‍♀️ Development\n\n### 🗺️ Repository structure\n\nxtemplate is split into the following packages:\n\n* `github.com/infogulch/xtemplate`, a library that loads template files and\n  implements an `http.Handler` that routes requests to templates and serves\n  static files.\n* `github.com/infogulch/xtemplate/providers`, contains optional dot provider\n  implementations for common functionality.\n* `github.com/infogulch/xtemplate/cmd`, a simple binary that configures\n  `xtemplate` with CLI args and serves http requests with it.\n* [`github.com/infogulch/xtemplate-caddy`](https://github.com/infogulch/xtemplate-caddy),\n  uses xtemplate's Go library API to integrate xtemplate into Caddy server as a\n  Caddy module.\n\n\u003e [!TIP]\n\u003e\n\u003e To understand how the xtemplate package works, it may be helpful to skim\n\u003e through the files in this order: [`config.go`](./config.go),\n\u003e [`server.go`](./server.go) [`instance.go`](./instance.go),\n\u003e [`build.go`](./build.go), [`handlers.go`](./handlers.go).\n\n### Testing\n\nxtemplate is tested by running [`./test/test.go`](./test/test.go) which runs\nxtemplate configured to use `test/templates` as the templates dir and\n`test/context` as the FS dot provider, and runs hurl files from the `test/tests`\ndirectory.\n\n### 👩‍⚕️ Writing a custom `DotProvider`\n\nImplement the `xtemplate.RegisteredDotProvider` interface on your type and\nregister it with `xtemplate.Register()`. Optionally implement\n`encoding.TextMarshaller` and `encoding.TextUnmarshaller` to round-trip\nconfiguration from cli flags.\n\nOn startup xtemplate will create a struct that includes your value as a field.\nFor every request your DotProvider.Value method is called with request details\nand its return value is assigned onto the struct which is passed to\n`html/template` as the dot value `{{.}}`.\n\n## ✅ Project history and license\n\nThe idea for this project started as [infogulch/go-htmx][go-htmx] (now\narchived), which included the first implementations of template-name-based\nrouting, exposing sql db functions to templates, and a persistent templates\ninstance shared across requests and reloaded when template files changed.\n\ngo-htmx was refactored and rebased on top of the [templates module from the\nCaddy server][caddyhttp-templates] to create `caddy-xtemplate` to add some extra\nfeatures including reading files directly and built-in funcs for markdown\nconversion, and to get a jump start on supporting the broad array of web server\nfeatures without having to implement them from scratch.\n\nxtemplate has since been refactored to be usable independently from Caddy.\nInstead, [xtemplate-caddy](https://github.com/infogulch/xtemplate-caddy) is\npublished as a separate module that depends on the xtemplate Go API and\nintegrates xtemplate into Caddy as a Caddy http middleware.\n\n`xtemplate` is licensed under the Apache 2.0 license. See [LICENSE](./LICENSE)\n\n[go-htmx]: https://github.com/infogulch/go-htmx\n[caddyhttp-templates]: https://github.com/caddyserver/caddy/tree/master/modules/caddyhttp/templates\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finfogulch%2Fxtemplate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Finfogulch%2Fxtemplate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finfogulch%2Fxtemplate/lists"}