1. that requires parsing the template at compile-time (making it non-overridable at runtime) or the ability to generate executable code at runtime which break in NX-mandatory environment (e.g. appstore applications)
2. the runtime version may be much faster than the compile-time one, e.g. the rust Regex crate has both a runtime Regex structure and a regex! compiler plugin, the latter is currently significantly slower at runtime: https://github.com/rust-lang/regex#usage-regex-compiler-plug...
Yes, "compile/load/execute" can take longer than simply "eval". You have to consider amortized costs: how often do you need to recompile your template (or your regex)? Likewise, are you really going to override the template at runtime or is the variable part of the template already compiled as branches in the resulting code? Whatever needs to be dynamic can be dynamic while compiling as much as possible ahead of time.
Exactly, I used django and jinja templates. Those two are feature rich. Golang template engine is mostly minimal with enough feature to do things.
The problem with Golang, most developers look for performance instead of the features. People who use python or ruby look for better features and ease of development. So, Golang engineers develop applications and libraries which doesn't help anyone.
Go template language has a nice context sensitive escape mechanism. But the syntax is kind of garbage and it's very limited when it comes to features ( no template inheritance, curb-some API for plugins ... ). Like everything in Go it gets you 50% there and but it's PITA to do something complex with it. Go is really bait+switch . You can get started fast but then you run into a vast amount of issues when it's time to deliver a professional product with std lib. It's true for testing,logging,writing web-apps, debugging and even concurrency. I hope the more Google rely on it, the more the maintainers will be pressured withing Google to fix its shortcomings.
I write Go professionally now and it's just not a productive language. The concepts are there, but the execution was frankly quite lazy and inconsistent.
Never panic in an external API, but closing closed channels and random number functions panic in the same way Java throws checked exceptions.
Generics aren't important, except for slices, maps, and channels which are generic.
When a program panics, it's saying that there is a fundamental problem with your logic. Closing closed channels and dividing by zero are both examples of those.
Complex json parsing is kind of bad too in go - and rather surprising for a modern vm/go based language. (I guess they really tried to go for c/c++ with go but why vm/gc)
Google will probably fix these things with time though, or so I hope - at the moment go seems like a conflicted language.
> As the web moves to the front end, this seems like a step backwards
The web isn't really "moving front end". I hate these fulljavascript websites that serves you articles, there is no need to use Javascript for that. Furthermore, isn't server-side rendering a thing even for "front-end frameworks"? server-side templates are still relevant. What is not is abusing Javascript everywhere even when it doesn't make sense.
These are not even milliseconds, the charts are in microseconds and a reduction of 40 to < 10 µs... so basically just noise when compared with the other things most apps will be doing, a 0.04 ms reduction.
I agree it's not worth the focus on fast, they should be focussed on improving the API for the stdlib templates (for example loading templates is not obvious, what I'd like to do is point it at a directory and load all templates under that dir, being able to set layouts and partials would be nice etc). Speed is not a big problem with the existing templating.
It's not noise. The benchmark's result is stable. Maybe the benchmark is too simple. In production the templates are more complex than the benchmarks, so the speed does count! But that doesn't mean that the easy-of-use is not important. I want Hero to be fast, and easy of use too.
> It's not noise. The benchmark's result is stable
All things considered, it absolutely is noise. Unless the only thing your application does is serving templates. Even then, the entire response should be cached, both on the server and the client at first place.
It's very hard to benchmark things which are that fast, and very easy to make mistakes (for example optimising away the thing you think you are measuring because your benchmark does no real work with it and the compiler notices). So on this homepage you have two benchmarks, which give these stats for stdlib:
Time: ~0.04ms
Memory usage: 2Kb
There is no context here and just a link to another benchmark which most aren't going to bother to read. If your selling point is that you're the fastest, you need to tell people why that's important, and what exactly is faster. These graphs give zero details on the work done, and the timings/memory usage suggest trivial work is done in the benchmark, which means it's likely to be wrong. Is it measuring loading or evaluating or both at once? How many templates, what is in them? Are they properly evaluated with lots of keys in them? Do they test functions, methods, built-in functions?
If you're interested in speed, I'd suggest setting up your own real-world benchmark, with separate charts for parse time (typically done once, of little importance) and evaluation time for sets of templates which are 30-100 templates big and include lots of dynamic content and other templates. That's close to real world use and will tell you if your library is a lot faster, it might even give you far more impressive numbers (reduced render time of typical templates from 100ms to 10ms for example).
Personally, like the parent, fastest is about 10th on my priorities list as long as speed is adequate (and 0.04ms per template is adequate), below: Correctness, Contextual escaping (very handy in stdlib, not supported?), Ease of Use, Partials, Layouts, Syntax, Docs, Adding another dependency, etc.
As a third party dependency for a core feature which would require me to impose your library on everyone who uses my library/app, your argument has to be very strong and there have to be multiple reasons to adopt the library and strong guarantees about future development/support. Speed is not enough, even if it was an order of magnitude better on significantly slower results (say 100ms -> 10ms), it would be just one bullet point and far down the list.
Not really because there are several limitations, e.g. you can't have multiple templates with the same name, I like to key them by path and have several index templates for example.
I've been looking for a good template engine that supports compilation, but the goal is not speed. Although you can rely on testing, I'd like to get type-checking for templates at compile time.
The benchmarks in the README show a whole lot of templating engines, but weirdly omit the standard library module: https://golang.org/pkg/text/template
It's unfortunate the post title was "fastest go template engine" since that draws away from how different the API is from the standard lib (think ERB/EJS v Mustache).
While I'm personally in the "logicless" camp, I know a lot of people who'd appreciate this. Even I would when building something quick and dirty.
I'm for templating solutions that don't use a DSL or .html files, like this one[1] I was developing but failed to put up in comparison with the others in the goTemplateBenchmark repo.
The benchmarks look good but if you're that abstracted from HTML I'd rather just go all the way; something Jade-like takes this from being a half measure to a full commitment.
I've seen a few articles from Golang users saying that, after trying to fight the standard library in many ways, they just end up using it since they realise it's the best balance between usable and extensible. Taking how great the Golang templating engine is, I'm not sure this is a step forward.
I don't like Go Templates. My issue is that you can't have small calculations easily. You'd have to add a lot of helper functions or prepare everything before passing to template engine. Now there is too much coupling. And not that fun. This one allowing inline Go code solves that issue.
Disclaimer: I wrote a template engine (https://github.com/eknkc/amber) to make this easier (and I like that Jade syntax)
I always considered the actual template to be the presentation layer relative to the templating context. Having worked on large scale applications it has become apparent to me that performing business logic in the presentation is not the way to go. In my opinion, a templating application should be architectured in such way that your data is transformed to exactly how you want it to be presented prior to it getting to the presentation layer. Up in presentation, you should really only have to worry about checking if a condition is true or false or iterating a collection. From what I have seen of Golang, some (not all) design decisions seem to have been made to make it difficult to make such mistakes easily, so I would not be surprised if making it difficult to do logic in the template was a conscious decision.
While I agree in theory, I can't stand that in practice :).
For example, let's say I want to show a usage stat, I'd pass something like { usage: 100, limit: 1000 } to the template engine. Let's say I want to add a percentage. I believe the calculation should be on the presentation layer. That's how I decide to present this particular data.
Go templates lack that functionality for no good reason. And if I'm gonna calculate that on the backend, why exactly am I using a template engine? I'd concatenate strings.
Actually you can do function calls on Go templates [1], and indeed this is what is done in practice. Libraries got written to do this, and badly integrated [2].
You will quickly find if you use this that it's in fact worse: go templates have LISP syntax. A set of atoms, specified in reverse Polish notation, doing function application to all but the first atom.
Yeah this is the reason I went ahead and wrote the template engine I mentioned in the parent comment. It compiles down to go templates. I inject generic math functions [1] and convert an expression like 4 + 5 * 3 to go template function calls. It's ugly but the compiler generates it so whatever :)
Another day, another string-based template engine that will lead to invalid output and injection attacks. You don't need a new language specifically for templates, you need to use a real programming language with real data structures that represent the HTML/XML nodes.
54 comments
[ 4.7 ms ] story [ 131 ms ] threadWhat I know, most web apps need template parsing only at the beginning. Once initial startup is done, delivery of content is mostly constant.
For low traffic efficacy doesn't matter, for high traffic you should always cache the templates.
1. that requires parsing the template at compile-time (making it non-overridable at runtime) or the ability to generate executable code at runtime which break in NX-mandatory environment (e.g. appstore applications)
2. the runtime version may be much faster than the compile-time one, e.g. the rust Regex crate has both a runtime Regex structure and a regex! compiler plugin, the latter is currently significantly slower at runtime: https://github.com/rust-lang/regex#usage-regex-compiler-plug...
The problem with Golang, most developers look for performance instead of the features. People who use python or ruby look for better features and ease of development. So, Golang engineers develop applications and libraries which doesn't help anyone.
I write Go professionally now and it's just not a productive language. The concepts are there, but the execution was frankly quite lazy and inconsistent.
Never panic in an external API, but closing closed channels and random number functions panic in the same way Java throws checked exceptions.
Generics aren't important, except for slices, maps, and channels which are generic.
Really minor things like this add up
Google will probably fix these things with time though, or so I hope - at the moment go seems like a conflicted language.
How exactly are designers supposed to easily update? Why reinvent the wheel when far more matured templating engines exist?
As the web moves to the front end, this seems like a step backwards
Not in any way that counts.
Many web sites are perfectly fine with pure HTML/CSS.
The web isn't really "moving front end". I hate these fulljavascript websites that serves you articles, there is no need to use Javascript for that. Furthermore, isn't server-side rendering a thing even for "front-end frameworks"? server-side templates are still relevant. What is not is abusing Javascript everywhere even when it doesn't make sense.
I think its more important, to choose a good template language thats easy, and doesnt mix code with template content.
So while the raw version is a bit too easy for my tastes (and the first to be listed) the escaped version is still easier/shorter than raw.
All the usual bad stuff that comes with dependencies: will it be maintained? Will it have breaking changes? Will it leftpad?
And everyone knows the standard library template format, all the editors support it, if another coder joins the team they'll know it.
Meh, maybe I'm just not the target market for this...
I agree it's not worth the focus on fast, they should be focussed on improving the API for the stdlib templates (for example loading templates is not obvious, what I'd like to do is point it at a directory and load all templates under that dir, being able to set layouts and partials would be nice etc). Speed is not a big problem with the existing templating.
All things considered, it absolutely is noise. Unless the only thing your application does is serving templates. Even then, the entire response should be cached, both on the server and the client at first place.
Time: ~0.04ms
Memory usage: 2Kb
There is no context here and just a link to another benchmark which most aren't going to bother to read. If your selling point is that you're the fastest, you need to tell people why that's important, and what exactly is faster. These graphs give zero details on the work done, and the timings/memory usage suggest trivial work is done in the benchmark, which means it's likely to be wrong. Is it measuring loading or evaluating or both at once? How many templates, what is in them? Are they properly evaluated with lots of keys in them? Do they test functions, methods, built-in functions?
If you're interested in speed, I'd suggest setting up your own real-world benchmark, with separate charts for parse time (typically done once, of little importance) and evaluation time for sets of templates which are 30-100 templates big and include lots of dynamic content and other templates. That's close to real world use and will tell you if your library is a lot faster, it might even give you far more impressive numbers (reduced render time of typical templates from 100ms to 10ms for example).
Personally, like the parent, fastest is about 10th on my priorities list as long as speed is adequate (and 0.04ms per template is adequate), below: Correctness, Contextual escaping (very handy in stdlib, not supported?), Ease of Use, Partials, Layouts, Syntax, Docs, Adding another dependency, etc.
As a third party dependency for a core feature which would require me to impose your library on everyone who uses my library/app, your argument has to be very strong and there have to be multiple reasons to adopt the library and strong guarantees about future development/support. Speed is not enough, even if it was an order of magnitude better on significantly slower results (say 100ms -> 10ms), it would be just one bullet point and far down the list.
I hope this is helpful.
:P
Doesn't https://golang.org/pkg/html/template/#ParseGlob do exactly that?
I'd add whatever functionality you need to html/template in your own code rather than import a dependency.
That's more than enough to raise my eyebrow.
Sorry, OP.
Nice work on your plugin and impressive benchmark statistics!
It's unfortunate the post title was "fastest go template engine" since that draws away from how different the API is from the standard lib (think ERB/EJS v Mustache).
While I'm personally in the "logicless" camp, I know a lot of people who'd appreciate this. Even I would when building something quick and dirty.
[1]: https://github.com/fiatjaf/hyperscript-go
Disclaimer: I wrote a template engine (https://github.com/eknkc/amber) to make this easier (and I like that Jade syntax)
For example, let's say I want to show a usage stat, I'd pass something like { usage: 100, limit: 1000 } to the template engine. Let's say I want to add a percentage. I believe the calculation should be on the presentation layer. That's how I decide to present this particular data.
Go templates lack that functionality for no good reason. And if I'm gonna calculate that on the backend, why exactly am I using a template engine? I'd concatenate strings.
You will quickly find if you use this that it's in fact worse: go templates have LISP syntax. A set of atoms, specified in reverse Polish notation, doing function application to all but the first atom.
[1] https://golang.org/pkg/text/template/#Template.Funcs
[2] https://github.com/Masterminds/sprig
[1] https://github.com/eknkc/amber/blob/master/runtime.go
http://www.more-magic.net/posts/structurally-fixing-injectio...