• Stars
    star
    235
  • Rank 171,079 (Top 4 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created about 11 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

โ“‚ An extremely fast and small sub-implementation of the {{mustache}} template engine for JavaScript

Downloads GitHub stars Known Vulnerabilities GitHub license Version code style: prettier GitHub issues

micromustache

Logo

A secure, fast and lightweight template engine with some handy additions.

โ›น Check out the playground

Think of it as a sweet spot between plain text interpolation and mustache.js; Certainly not as logic-ful as Handlebars! Sometimes a stricter syntax is the right boundary to reduce potential errors and improve performance. This tool has a limited scope that doesn't attempt to solve everybody's use case, and instead do a specific thing well.

  • ๐Ÿƒ Faster than MustacheJS (Micromustache is the fastest template engine that doesn't need pre-compilation and still works in CSP environments)
  • ๐Ÿ”’ Secure has limits for variable length, number of interpolations, nesting debth and common Javascript pitfalls (__proto__, constructor, getters/etc). Works in CSP environments (no usage of eval() or new Function()). Published only with 2FA.
  • โœ Bracket notation support a[1]['foo'] accessors (mustache.js/handlebar syntax of a.1.foo is also supported).
  • ๐ŸŽˆ Lightweight less than 350 source lines of code, easy to audit, small API surface, easy to pick up
  • ๐Ÿณ No dependencies
  • ๐Ÿ Small memory footprint sane caching strategy, no memory leak
  • ๐Ÿšฉ Meaningful errors to improve developer experience. All functions test their input contracts and throw meaningful errors to improve developer experience (DX).
  • โšก TypeScript types included out of the box and updated with every version of the library
  • ๐Ÿ‡ Works in node (CommonJS) and Browser (UMD) and EcmaScript 6 Modules (ESM)
  • ๐Ÿ›  Thoroughly tested (full test coverage over 120+ tests). Also tested to produce the same results as Mustache.js.
  • ๐Ÿ“– Full JSDoc documentation

If variable interpolation is all you need, micromustache is a drop-in replacement for MustacheJS (see its differences with Mustache.js)

Try it in your browser!

Getting started

Use directly with UNPKG:

import { render } from 'https://unpkg.com/browse/micromustache/dist/micromustache.mjs'
console.log(render('Hello {{name}}!', { name: 'world' }))
// Hello world!

Install:

$ npm i micromustache

Use:

const { render } = require('micromustache')
console.log(render('Hello {{name}}!', { name: 'world' }))
// Hello world!

Why not just use EcmaScript template literals?

Template literals work great when the template and the variables are in the same scope but not so well when the template is in another scope or is not known ahead of time. For example, suppose you had a function like this:

function greet(name) {
  return `Hi ${name}!`
}

After your function became successful and you got rich ๐Ÿค‘ you may decide to dominate the world and expand to new markets which speak other languages. You need to internationalize it. Adding one more language is easy:

function greet(name, lang) {
  // Note the lang parameter that contains a language code
  return lang === 'sv' ? `Hej ${name}!` : `Hi ${name}!`
}

But how about a bunch of them?

function greet(name, lang) {
  switch (lang) {
    case 'sv': return `Hej ${name}!`
    case 'es': return `Hola ${name}!`
    default:
    case 'en': return `Hi ${name}!`
  }
}

That doesn't scale well as you dominate country after country and need to support more languages! Besides, that's just one string! The main problem is that the content (the text) is coupled to the code (the variable interpolation). Template engines help you to move the content out of the function and let something else deal with that concern.

const { render } = require('micromustache')
// A very simplified i18n database
const db = {
  en: {
    greeting: 'Hi {{name}}!',
    // ...
  },
  sv: {
    greeting: 'Hej {{name}}!',
    // ...
  },
  // ...
}

function greet(name, lang) {
  return render(db[lang].greeting, { name } )
}

Now it's better! ๐Ÿ˜Ž All the templates are together and they are easy to update and translate. By default, we use the popular syntax that encloses paths between double curly braces ({{ and }}) but you can customize micromustache if you prefer something else. Just like template literals, you can of course reference deep nested objects:

const { render } = require('micromustache')
const scope = {
  fruits: [
    { name: 'Apple', color: 'red' },
    { name: 'Banana', color: 'yellow' },
  ]
}
console.log(render('I like {{fruits[1].color}}!', scope))
// I like Bababa!

It worth to note that Mustache and Handlebars don't support fruits[1].color syntax and rather expect you to write it as fruits.1.color.

The real power of micromustache comes from letting you resolve a path using your own functions! To pass a resolver function, you can use renderFn() instead of render():

const { renderFn } = require('micromustache')
// Just converts the path to upper case
const up = str => str.toUpperCase()

console.log(renderFn('My name is {{Alex}}!', up))
// My name is ALEX!

The resolver gets the scope as its second parameter. If you want to lookup a value, there's a get() function as well:

const { renderFn, get } = require('micromustache')

// Looks up the value and converts it to stars
function star(path, scope) {
  // path comes from the template and is 'password' here
  // scope is { password: 'abc' }
  const value = get(scope, path) // value is 'abc'
  return '*'.repeat(value.length)
}

console.log(renderFn('My password is {{password}}!', star, { password: 'abc' }))
// My password is ***!

If you want to resolve a value asynchronously, we got you covered using the renderFnAsync() instead of renderFn(). For example the following code uses node-fetch to resolve a url.

const { renderFnAsync } = require('micromustache')
const fetch = require('node-fetch')

async function taskTitleFromUrl(url) {
  const response = await fetch(url)
  const obj = await response.json()
  return obj.title
}

console.log(await renderFnAsync('Got {{https://jsonplaceholder.typicode.com/todos/1}}!', fetch))
// Got delectus aut autem!

If you find yourself working on a particular template too often, you can compile() it once and cache the result so the future renders will be much faster. The compiler returns an object with render(), renderFn() and renderFnAsync() methods. The only difference is that they don't get the template and only need a scope:

const { compile } = require('micromustache')
const compiled = compile('Hello {{name}}! I am {{age}} years old!')
console.log(compiled.render({ name: 'world', age: 42 }))
// Hello world! I'm 42
// The methods are bound so you can use the destructed version for brevity
const { render } = compile
console.log(render({ name: 'world', age: 42 }))
// Hello world! I'm 42

If the compiled variable above is garbage collected, the cache is freed (unlike some other template engines that dearly keep hold of the compiled result in their cache which may leads to memory leaks or out of memory errors over longer usage).

Using the options you can do all sorts of fancy stuff. For example, here is an imitation of the C# string interpolation syntax:

const { render } = require('micromustache')
const $ = scope => strings => render(strings[0], scope, { tags: ['{', '}'] })

const name = 'Michael'
console.log($({ name })`Hello {name}!`)
// Hello Michael!

API

On Github pages

Examples

Check out the examples directory. Note that they need you to build the project locally.

FAQ

On wiki

Known issues

On wiki

License

MIT


Made in Sweden ๐Ÿ‡ธ๐Ÿ‡ช by @alexewerlof

More Repositories

1

typescript

Just a boilerplate for a Typescript/Node project with yarn, linting, github-ready documentation and mocha+chai tests
TypeScript
32
star
2

cap-parallel

JavaScript
25
star
3

slc

A simple service level calculator
HTML
19
star
4

combine-json

Combines a group of files into one JavaScript object
JavaScript
17
star
5

am

A simple and light way to run a main function asynchronously
JavaScript
12
star
6

pk

A tiny utility to extract info from package.json
JavaScript
10
star
7

ewerlof-clock

A simple web based clock that works offline on mobile devices using PWA techniques
JavaScript
9
star
8

js-operators-table

a little demo to show how javascript treats its binary operators
JavaScript
7
star
9

jty

A minimal type checking library that I need in various projects for safer programming
TypeScript
6
star
10

1-click-timer

JavaScript
3
star
11

eventjs

A powerful and lightweight event handler for Javascript
JavaScript
3
star
12

jj

Make HTML and CSS in Just Javascript!
JavaScript
3
star
13

TagCounter

A browser extension that shows stats about HTML tags on the page
JavaScript
2
star
14

callifexists

A simple utility to call a function if it exists
JavaScript
2
star
15

jsregex

A free open source mobile app for learning javascript regular expressions
JavaScript
2
star
16

ja

A simple CLI to read files from git repositories
JavaScript
2
star
17

sudoku-esm

An ESM version of the sudoku repo
JavaScript
2
star
18

badge

A tiny web app that puts a badged on your profile picture consistent with LinkedIn style but with your prefered text and colors.
HTML
2
star
19

percentile

JavaScript
2
star
20

go-big-factorial

A dead simple project for computing factorial of big numbers in Go
Go
1
star
21

sudoku-go

A reimplementation of the node sudoku project in Go
Go
1
star
22

brute-force

A customizable brute-force password cracker, but nothing fancy
JavaScript
1
star
23

spt-11

Just a quick test for SPT
JavaScript
1
star
24

jest-mock

https://github.com/facebook/jest/issues/2349
JavaScript
1
star
25

mithril-clock

Learned mithril with this
HTML
1
star
26

vue-clock

Same as ewerlof-clock and react-clock but in Vue
JavaScript
1
star
27

fibonacci

two algorithms for computing nth number in the factorial serie using JavaScript's new `BigInt` data type.
JavaScript
1
star
28

hnlink

a tiny web application that takes a URL and title to generate a link that will directly take you to the Hacker News submit page
HTML
1
star