I've improved Lissic to the point that I think it's worth sharing with the community. A quick overview of the features:
- Renders near twice as fast as the fastest major .NET templating engine (see below) - Zero allocation with default settings, when rendering to a buffer (e.g. to HttpResponse.BodyWriter) - 100% AOT compatible without any restrictions (no use of Reflection or dynamic) - Simple but powerful tagging system that keeps a clear division between layout and logic - Compile-time safety with source-generated Data Transfer Objects that automatically adjust to each template's text - Define templates directly in code with text or import them from template files - Transformation pipeline that allows using Formatters to modify how values are converted to text and Filters to modify text before insertion - Hot reload for file-based templates in debug mode - Thorough AI-friendly documentation (I gave only the documentation to QWEN3.8-27B, and it was able to make a simple task-management web app)
A full BenchmarkDotNet chart is in the GitHub README, but here's a quick rendering comparison:
Lissic (RenderToString) - 8.814 us / 18072 B
Lissic (RenderToBuffer) - 8.482 us / 0 B
Fluid - 15.593 us / 37128 B
Fluid (SourceGenerated) - 24.045 us / 49128 B
Scriban - 70.985 us / 144025 B
Handlebars - 21.944 us / 122176 B
It uses tags that look similar to many other templating engines. It has tag types to insert direct values ("variables"), other templates ("parts"), and lists of templates ("loops"). It also has branching logic that works a lot like a switch statement (i.e. define keys, and the text and/or code that goes with each key).
Very simple example:
---------------------------------------------
[TemplateText("Hello {{ name <upper> }}!")]
public partial class LissicExample {}
// Automatically transforms the partial class into a DTO, with a property for each tag
LissicExample myTemplate = new() { name = "John" };
// LissicProcessor retrieved from Dependency Injection
lissicProcessor.RenderToBuffer(myTemplate, HttpResponse.BodyWriter);
// Writes "Hello JOHN!" to the HTTP response body
---------------------------------------------The main tradeoff at this time is that all templates are defined at startup (other than the debugging-only hot reload option), so it's not really a general purpose user-provided template engine. This leaves it comparable to libraries like Fluid or Scriban in some ways, but comparable to Razor Pages in others. It works really well for my purpose and preferences though.
I'd appreciate any feedback anyone has. I'd like to keeping building this for the long haul. If nothing else, I'll be updating it for work in my own project.
In particular, I'd like to support using literal text in loop tags, but that doesn't work cleanly with my current auto-generated DTO setup. I've considered auto-generating DTOs with predictable names (and providing a name override option via attributes). I've also considered supporting duck-typing for those, which would essentially be a new feature set, which is maybe useful or maybe over complicating it? I'd appreciate thoughts on this in particular. :)
Shout out to Andrew Lock and his Creating a Source Generator series!
The code is at https://github.com/gendeg/Lissic, and it's on NuGet (package name: Lissic)
ggende•57m ago
There were a lot of "I have these requirements, what are my options? ... But what about this consideration? Can I account for that too? ... What if I changed this other part of my architecture, how does that change things?"-type conversations. More often than not, it was with an AI that didn't see the code at all. One of AI's biggest strengths is knowing the domain of what exists out there, but I see its biggest weakness being iterating for the sake of making a product better. Some of that can happen by observing the end product, but some of it can only happen during the development process itself. For example, there were a handful of changes I made while writing the first draft of the documentation when I thought, "wait... is this really what I want?" while writing it down.