I built a JS template engine 3x faster than EJS

nebrelbug

Ben Gubler

Posted on April 11, 2020

I built a JS template engine 3x faster than EJS

After hundreds of hours of development, I finally released my open-source project last week. Eta is a pluggable, lightweight, and super-fast JavaScript template engine I created to serve as an alternative to doT and EJS.

Before I get into discussing my development journey, though, let me outline some differences between Eta and EJS.

Eta vs EJS
Eta's syntax is very similar to EJS' (most templates should work with either engine), Eta has a similar API, and Eta and EJS share the same file-handling logic. Here are the differences between Eta and EJS:

  • Eta is more lightweight. Eta weighs around 2KB gzipped, while EJS is 4.4KB gzipped
  • Eta compiles and renders templates much faster than EJS. Check out these benchmarks: https://ghcdn.rawgit.org/eta-dev/eta/master/browser-tests/benchmark.html
  • Eta allows left whitespace control (with -), something that doesn't work in EJS because EJS uses - on the left side to indicate that the value shouldn't be escaped. Instead, Eta uses ~ to output a raw value
  • Eta gives you more flexibility with delimeters -- you could set them to {{ and }}, for example, while with EJS this isn't possible
  • Eta adds plugin support
  • Comments in Eta use /* ... */ which allows commenting around template tags and is more consistent
  • Eta parses strings correctly. Example: <%= "%>" %> works in Eta, while it breaks in EJS
  • Eta exposes Typescript types and distributes a UMD build
  • Custom tag-type prefixes. Example: you could change <%= to <%*

Features Eta and EJS share

  • Async support
  • Partials support
  • File-handling support
    • Eta borrows its file-handling code from EJS, which has over 1.5 million downloads / week. It's pretty reliable 😉
  • Express.js support
  • EJS syntax-highlighting tools work to some extent with Eta

Why did I build Eta?

My journey started around 2 years ago, when I first created a template engine called Squirrelly. After hundreds of hours of performance benchmarking and trying dozens of different parsing methods, I was finally able to break the speed of all other popular template engines.

Over the last year, I've been working on the next version of Squirrelly, which adds some important features like template inheritance and better string parsing. While benchmarking Squirrelly, I realized that it was significantly faster than other template engines like EJS -- even though it supported helpers, filters, template inheritance, etc.

I decided to take the framework behind Squirrelly (all of the behind-the-scenes code) which I had already optimized and tested extensively, and create a simple embedded template engine on top of it. The new template engine would be more configurable than most other template engines, extremely lightweight, very fast, and more reliable than most other template engines.

I named the new template engine "eta" for a few reasons.
1) Eta means "tiny" in Esperanto, and Eta is a tiny template engine
2) Eta is the name of a letter in the Greek alphabet, which I use as a cool logo
3) "Eta" is 3 letters long, which makes it easy to write template files (ex. footer.eta)

Within several weeks, I was able to create Eta. Because I didn't have to worry about Squirrelly's advanced features, Eta took significantly less time to create and test. Using Docusaurus v2, I was able to throw up a documentation site and write a playground.

A few lessons learned

  • In JavaScript (at least the v8 engine) regular expressions are super optimized and are significantly faster than even looping through every character in a string and doing something with it
  • TypeScript catches a lot of stupid errors
  • Running code coverage tests helps find unnecessary (dead) code
  • Performance can be improved significantly by lots of trial-and-error testing
  • with () {} in JavaScript slows down execution and can cause confusing bugs

Eta's Stack

  • Written in TypeScript
  • Compiled with Rollup (which, for libraries, creates much smaller builds than Webpack)
  • Minified with rollup-plugin-terser
  • Tests with Jest
  • Code-coverage with Coveralls
  • Travis CI for Continuous Integration
  • Prettier for formatting
  • ESLint with StandardJS compatibility for linting
  • TypeDoc for automatic API Doc Generation

I hope you enjoyed reading about my journey to create Eta! If you need an embedded JavaScript template engine for a future project, consider using Eta instead of a library like EJS or doT.

💖 💪 🙅 🚩
nebrelbug
Ben Gubler

Posted on April 11, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related