Skip to content
Alex Ewerlöf edited this page Aug 17, 2020 · 5 revisions

Q. Is it really faster and smaller than Mustache.JS?

It's a bit of apple vs. orange comparison. Micromustache has a lot of code for making it secure and generate meaningful error messages, and as a result of that, it doesn't use Regular Expressions as heavily as Mustache.jsJS But yes, it's smaller and for most use cases even faster than Mustache.JS (see the perf directory), while being loyal to Mustache.JS syntax as much as possible.

Q. How can I have loops?

Unlike MustacheJS or Handlebars, micromustache does not have a custom syntax for loops. Instead it encourages you to use JavaScript for that (pretty much how JSX avoids custom template syntax and encourages using .map()).

For example if you have an array of objects:

const { render } = require('micromustache')

const people = [
  { name: 'Alex', age: 37 },
  { name: 'Oskar', age: 35 },
  { name: 'Anna', age: 43 }
]

console.log(render(`There are ${people.length} people:\n${peopleBrief}`, {
  people,
  peopleBrief: people.map(p => render(`${name}, ${age} years old`, p)).join('\n')
}))

Q. How do you treat resolver functions?

The renderFn() and renderFnAsync() get a function as their second parameter and run them for every variable name in the template. The function gets the variable name and the scope as arguments and is supposed to return the resolved value ready to be injected into the template string. If your function throws, renderFn()/renderFnAsync() throw as well.

Q. Does Micromustache support nested interpolations?

Let's first define what nested interpolation means:

const scope = {
  names: ['Alex', 'Miranda', 'Jake'],
  idx: 2
}
console.log(render('Hi {{names[{{idx}}]}}!', scope));
// we would expect 'Hi Jake!' but instead this error is thrown: SyntaxError: Variable names cannot have "{{". But at position 3 got "names[{{idx"

Micromustache is built to be as close as possible to the JavaScript Template Literals. Just as 'Hi ${names[${idx}]}!' throws an exception in JavaScript, Micromustache treats nested template literals as SyntaxError.

It is of course possible to write an algorithm that works for it but that will have performance implications that directly fights with the goal of Micromustache for being small and super fast. You can achieve the same goal using two different interpolation tags:

const { render, renderFn, get } = require('../dist/micromustache')

const scope = {
  names: ['Alex', 'Miranda', 'Jake'],
  idx: 2
}

console.log(renderFn('Hi {{names[<idx>]}}!', function resolveFn(varName, scope) {
  // we'll get names[<idx>] here
  const interpolateAngleBrackets = render(varName, scope, { tags: ['<', '>']})
  // Now we have names[2] which we can feed into the render function again
  return render('{{' + interpolateAngleBrackets + '}}', scope)
}, scope));

Q. Do you support multiple scopes and lookup fall back mechanisms?

This can easily be done using JavaScript object-spread operator as seen in one of the examples.

Q. How to handle huge template files?

Micromustache parsing and interpolation are done synchronourly which may block JavaScript event loop. If you are dealing with huge template files, it's recommended to do the interpolation in a Worker.

Q. Why did you re-implement the lodash get() instead of using it?

The short answer is: performance and maintanance. The long answer: one of the promises of micromustache is to be super quick and safe and as a result of that, it doesn't have any dependency. _.get() is a useful function but it does too much which is way more than micromustache needs. Besides, by not having lodash (or other libraries) as a runtime dependency, we eliminate a whole class of updating chore, security vulnerabilities and general troubles that come with the benefits of using a dependency. Re-implementing _.get() for micromustache didn't need too much code but leads to better control and auditability.

Clone this wiki locally