Introducing Our New Templating Engine
-
Hi everybody,
Over the past year I've been working on building a new templating engine from the ground up. I did this for several main reasons:
- templates.js was buggy and hard to maintain
- templates.js was orders of magnitude slower compared to other templating engines
- templates.js uses orders of magnitude more CPU time than other templating engines
- Curiosity surrounding parsers and compilers, especially dealing with how Babel and JS AST formats work
Why was templates.js slow?
It works opposite of most templating engines, iterating over the entire data object, instead of fetching values from it based on template tokens. This meant iterating through the template string possibly hundreds of times per request.
templates.js was begging for a replacement. My solution:
Benchpress
Benchpress is a brand new templating engine built from the ground up to be feature-rich and very fast. It is mostly backwards compatible with templates.js, and in some areas providing more flexible syntax.
How is it so fast?
Benchpress compiles template files into Javascript functions composed of string concatenation. For example, the following template:
I love {{forum}} because it uses {{templater}}!
Is compiled into this Javascript module:
(function (factory) { if (typeof module === 'object' && module.exports) { module.exports = factory(); } else if (typeof define === 'function' && define.amd) { define(factory); } })(function () { function compiled(helpers, context, get, iter, helper) { return 'I love ' + get(context && context['forum']) + ' because it uses ' + get(context && context['templater']) + '!'; } return compiled; });
This puts Benchpress among the fastest templating libraries available. Faster than Handlebars, EJS, underscore, and Pug (Jade). It's almost 40x faster than templates.js was.
Breaking changes between templates.js and Benchpress
I tried to make Benchpress as backwards compatible as possible. Most existing templates should work fine. However, there are a few instances where Benchpress will behave differently.
- If you are iterating over an object or array, you can't access it's properties directly, since you can use
{obj.prop}
to mean theprop
property of each element. templates.js supported both of these, but due to the ambiguity of the syntax, Benchpress requires you to use{../../obj.prop}
to access that specific property. - Somehow templates.js supports iterating over deep values. For example, for this data:
{ obj: { arr: [4, 7, 2] } }
and this template:<!-- BEGIN arr -->{@value}<!-- END arr -->
it would output472
, even thougharr
isn't at the top level of the input data. Obviously, this is not supported in Benchpress. - Another crazy thing that templates.js supported was reversing the iterators in the template, so
<!-- BEGIN arr1 --><!-- BEGIN arr2 -->
behaved the same as<!-- BEGIN arr2 --><!-- BEGIN arr1 -->
. This is unsupported in Benchpress because it makes no sense.
By far, the largest breaking change in Benchpress is that client-side template compilation is unsupported. In fact, using
Benchpress.parse(template, data)
is entirely unsupported. There is a new function only available on the server side,Benchpress.compileParse(template, data, callback)
which will compile a given template and then execute it with the given data. You must otherwise precompile templates before using them client-side. Any templates in NodeBB, themes, and plugins that are provided normally will continue to be compiled automatically.I'm very excited to introduce you all to Benchpress, and for the future it has with NodeBB! Benchpress is planned on being shipped with NodeBB in an upcoming major release.
Edit: just to clarify, client-side parsing, using
Benchpress.parse(templateName, data, callback)
is still available client side. Client side compilation is unsupported, but client side parsing is still supported.Edit2: I forgot to mention that this forum is currently powered by Benchpress.
-
Have fun.I will support you forever.
-
@shard it's in the benchpressjs branch of the nodebb repository at the moment.
-
There are docs up on the Github page detailing syntax and behavior. There is a new alternate syntax available,
{{{ if isTrue }}} is true {{{ end }}}
, and that should make things easier as the behavior of the alternate syntax is more predictable in several usage areas. -
Well, for me NodeBB works great. I run it on a micro instance and resource consumption is very low. There were some minor issues, but overall I'm very happy with it. I just don't use plugins which are unsupported, i think this is a common sense when deploying open source code developed by community. I think it could be useful (and it will help to avoid a lot of confusion) if we put plugins into different categories: stable (always tested with every new release of NodeBB), and unstable (use at your own risk), this model works well for Debian Linux, that has three branches: Stable, Testing and Unstable (sid).
-
-
Why didn't you use Twig.js? Twig.js is the fastest template engine in javascript, and also the most powerful. You can look at the design, every possible optimization is made.
-
@razr-world twig is not compatible with templates.js syntax.
Also, it's tough claiming to be faster than Benchpressjs. I haven't seen any benchmarks comparing the two.
-
@razr-world I don't see anywhere that makes these claims, but they both compile to JS, so the performance should be similar.
I'd like to see actual benchmarks as well.
-
template-benchmark
There you go, published results. It looks like Twig.js is even slower than templates.js was, and much slower than Benchpress. I am a little dubious of those results, though, as I could have easily messed something up in the benchmark.
-
There's one more breaking change that I did not find documented anywhere.
For our theme we had to change:var templates = require('templates.js'); templates.registerHelper('generateCategoryBorder', helpers.generateCategoryBorder);
to
var Benchpress = require('benchpressjs'); Benchpress.registerHelper('generateCategoryBorder', helpers.generateCategoryBorder);
Not a big deal but some folks might struggle to see why their template helpers don't work on server side.
-
-