UNPKG

9.89 kBMarkdownView Raw
1[![Downloads](https://img.shields.io/npm/dm/micromustache.svg?style=flat-square)](http://npm-stat.com/charts.html?package=micromustache&from=2017-01-01)
2[![GitHub stars](https://img.shields.io/github/stars/userpixel/micromustache?style=flat-square)](https://github.com/userpixel/micromustache/stargazers)
3[![Known Vulnerabilities](https://snyk.io/test/github/userpixel/micromustache/badge.svg?style=flat-square)](https://snyk.io/test/github/userpixel/micromustache)
4[![GitHub license](https://img.shields.io/github/license/userpixel/micromustache?style=flat-square)](https://github.com/userpixel/micromustache/blob/master/LICENSE.md)
5[![Version](https://img.shields.io/npm/v/micromustache.svg?style=flat-square)](http://npm.im/micromustache)
6[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier)
7[![GitHub issues](https://img.shields.io/github/issues/userpixel/micromustache.svg?style=flat-square)](https://github.com/userpixel/micromustache/issues)
8
9# micromustache
10
11![Logo](https://raw.github.com/userpixel/micromustache/master/logo.png)
12
13A **secure**, fast and lightweight template engine with some handy additions.
14
15β›Ή Check out **[the playground](https://unpkg.com/micromustache/playground/index.html)**
16
17Think of it as a sweet spot between plain text interpolation and [mustache.js](https://github.com/janl/mustache.js); Certainly not as logic-ful as [Handlebars](http://handlebarsjs.com/)! 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.
18
19* πŸƒ **2x-3x** faster than MustacheJS (_Micromustache is the fastest template engine that doesn't need pre-compilation and still works in CSP environments_)
20* πŸ”’ **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. [No regexp](https://medium.com/@liran.tal/node-js-pitfalls-how-a-regex-can-bring-your-system-down-cbf1dc6c4e02).
21* 🎈 **Lightweight** No dependencies, less than 400 lines of source code, easy to audit, small API surface, easy to pick up
22* 🐁 **Small memory footprint** sane caching strategy, no memory leak
23* 🏳 **No dependencies**
24* ✏ **Bracket notation** support `a[1]['foo']` accessors (mustache.js/handlebar syntax of `a.1.foo` is also supported).
25* 🚩 **Meaningful errors** in case of template syntax errors to make it easy to spot and fix. All functions test their input contracts and throw meaningful errors to improve developer experience (DX).
26* ⚑ **TypeScript** types included out of the box and updated with every version of the library
27* πŸ‡ Works in node (CommonJS) and Browser (UMD) and EcmaScript 6 Modules (ESM)
28* πŸ›  Well tested (full test coverage over 120+ tests). Also tested to produce the same results as [Mustache.js](https://github.com/janl/mustache.js/).
29* πŸ“– Full JSDoc documentation
30
31If variable interpolation is all you need, *micromustache* is a [drop-in replacement](src/mustachejs.spec.ts) for MustacheJS (see its differences with [Mustache.js](https://github.com/userpixel/micromustache/wiki/Differences-with-Mustache.js))
32
33[Try it in your browser!](https://npm.runkit.com/micromustache)
34
35# Getting started
36
37Use directly with [UNPKG](https://unpkg.com/browse/micromustache/):
38
39```javascript
40import { render } from 'https://unpkg.com/browse/micromustache/dist/micromustache.mjs'
41console.log(render('Hello {{name}}!', { name: 'world' }))
42// Hello world!
43```
44
45Install:
46
47```bash
48$ npm i micromustache
49```
50
51Use:
52
53```javascript
54const { render } = require('micromustache')
55console.log(render('Hello {{name}}!', { name: 'world' }))
56// Hello world!
57```
58
59Why not just use EcmaScript [template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals)?
60
61Template 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:
62
63```javascript
64function greet(name) {
65 return `Hi ${name}!`
66}
67```
68
69After 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:
70
71```javascript
72function greet(name, lang) {
73 // Note the lang parameter that contains a language code
74 return lang === 'sv' ? `Hej ${name}!` : `Hi ${name}!`
75}
76```
77
78But how about a bunch of them?
79
80```javascript
81function greet(name, lang) {
82 switch (lang) {
83 case 'sv': return `Hej ${name}!`
84 case 'es': return `Hola ${name}!`
85 default:
86 case 'en': return `Hi ${name}!`
87 }
88}
89```
90
91That 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.
92
93```javascript
94const { render } = require('micromustache')
95// A very simplified i18n database
96const db = {
97 en: {
98 greeting: 'Hi {{name}}!',
99 // ...
100 },
101 sv: {
102 greeting: 'Hej {{name}}!',
103 // ...
104 },
105 // ...
106}
107
108function greet(name, lang) {
109 return render(db[lang].greeting, { name } )
110}
111```
112
113Now 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 variable names between double curly braces (`{{` and `}}`) but you can customize _micromustache_ if you prefer something else.
114Just like template literals, you can of course reference deep nested objects:
115
116```javascript
117const { render } = require('micromustache')
118const scope = {
119 fruits: [
120 { name: 'Apple', color: 'red' },
121 { name: 'Banana', color: 'yellow' },
122 ]
123}
124console.log(render('I like {{fruits[1].color}}!', scope))
125// I like Bababa!
126```
127
128*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`.*
129
130The real power of micromustache comes from letting you resolve a variable name using your own functions! To pass a resolver function, you can use `renderFn()` instead of `render()`:
131
132```javascript
133const { renderFn } = require('micromustache')
134// Just converts the variable name to upper case
135const up = str => str.toUpperCase()
136
137console.log(renderFn('My name is {{Alex}}!', up))
138// My name is ALEX!
139```
140
141The resolver gets the scope as its second parameter. If you want to lookup a value, there's a `get()` function as well:
142
143```javascript
144const { renderFn, get } = require('micromustache')
145
146// Looks up the value and converts it to stars
147function star(varName, scope) {
148 // varName comes from the template and is 'password' here
149 // scope is { password: 'abc' }
150 const value = get(scope, varName) // value is 'abc'
151 return '*'.repeat(value.length)
152}
153
154console.log(renderFn('My password is {{password}}!', star, { password: 'abc' }))
155// My password is ***!
156```
157
158If 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](https://www.npmjs.com/package/node-fetch) to resolve a url.
159
160```javascript
161const { renderFnAsync } = require('micromustache')
162const fetch = require('node-fetch')
163
164async function taskTitleFromUrl(url) {
165 const response = await fetch(url)
166 const obj = await response.json()
167 return obj.title
168}
169
170console.log(await renderFnAsync('Got {{https://jsonplaceholder.typicode.com/todos/1}}!', fetch))
171// Got delectus aut autem!
172```
173
174If 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:
175
176```javascript
177const { compile } = require('micromustache')
178const compiled = compile('Hello {{name}}! I am {{age}} years old!')
179console.log(compiled.render({ name: 'world', age: 42 }))
180// Hello world! I'm 42
181// The methods are bound so you can use the destructed version for brevity
182const { render } = compile
183console.log(render({ name: 'world', age: 42 }))
184// Hello world! I'm 42
185```
186
187*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).*
188
189Using the options you can do all sorts of fancy stuff. For example, here is an imitation of the **C#** string interpolation syntax:
190
191```javascript
192const { render } = require('micromustache')
193const $ = scope => strings => render(strings[0], scope, { tags: ['{', '}'] })
194
195const name = 'Michael'
196console.log($({ name })`Hello {name}!`)
197// Hello Michael!
198```
199
200# API
201
202[On Github pages](https://userpixel.github.io/micromustache/)
203
204# Examples
205
206Check out the [`examples`](./examples) directory.
207_Note that they need you to build the project locally._
208
209# FAQ
210
211[On wiki](https://github.com/userpixel/micromustache/wiki/FAQ)
212
213# Known issues
214
215[On wiki](https://github.com/userpixel/micromustache/wiki/Known-issues)
216
217# License
218
219[MIT](./LICENSE.md)
220
221---
222
223_Made in Sweden πŸ‡ΈπŸ‡ͺ by [@alexewerlof](https://mobile.twitter.com/alexewerlof)_
224
225<a href="https://opencollective.com/micromustache" target="_blank">
226 <img src="https://opencollective.com/micromustache/donate/button@2x.png?color=white" width=300 />
227</a>