template-templates
Version:
Use incredibly efficient and stupidly-tiny functions to parse plain template-strings.
210 lines (144 loc) • 5.25 kB
Markdown
# template-templates
Use incredibly efficient and stupidly-tiny functions to parse plain [template-string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals). Your target will [need to support those](https://caniuse.com/#feat=template-literals) for it to work.
It's meant to just be a zero-dependency ultra-tiny way to get compiled templates, using a familiar syntax.
See [it running, here](http://konsumer.js.org/template-templates/).
## really stupidly-tiny
```
206 B: template-templates.cjs.gz
171 B: template-templates.cjs.br
183 B: template-templates.modern.js.gz
161 B: template-templates.modern.js.br
208 B: template-templates.mjs.gz
179 B: template-templates.mjs.br
290 B: template-templates.umd.js.gz
237 B: template-templates.umd.js.br
```
## installation
Add it to you project:
```
npm i template-templates
```
## usage
*TLDR*: If you just want to see a code-example, have a look at the [unit-test](https://github.com/konsumer/template-templates/blob/master/test/template-template.test.js)
First, let's imagine we have a file named `demo.tpl` that looks like this:
```
Hi ${name},
${news === 'good'
? 'We are delighted to inform you that'
: 'We regret having to break this bad news to you, but'
} ${reason}
Signed Your Eternal Friends at ${company},
${agent}
```
This is just a regular [template-string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals). Variables are expanded into the scope.
### node
There are 2 different ways to use it, which are performance-wise about the same:
```js
import tt from 'template-templates'
import { readFile } from 'fs/promises'
// load the file contents
const tstring = await readFile('demo.tpl', 'utf8')
// these are some vars I'm going to pass to the template
const vars = {
name: 'Mr. Anderson',
company: 'MegaCorp',
agent: 'Agent Smith',
news: 'bad',
reason: 'your cat died.'
}
// first example, just gimme the string, in one-use:
console.log(tt(tstring, vars))
// second example: compile it for ultimate performance with re-use
// give it a list of valid vars
const template = tt.compile(tstring, Object.keys(vars))
// use it
console.log(template(vars))
/*
Hi Mr. Anderson,
We regret having to break this bad news to you, but your cat died.
Signed Your Eternal Friends at MegaCorp,
Agent Smith
*/
```
If you change your variables for good news, that works too:
```js
const vars = {
name: 'Mr. Anderson',
company: 'MegaCorp',
agent: 'Agent Smith',
news: 'good',
reason: 'you won the lottery.'
}
console.log(tt(tstring, vars))
/*
Hi Mr. Anderson,
We are delighted to inform you that you won the lottery.
Signed Your Eternal Friends at MegaCorp,
Agent Smith
*/
```
### browser
You can use it the same way in a browser. Let's imagine you want to fetch that same template, from above:
```html
<script type="module">
import tt from 'https://esm.run/template-templates'
const vars = {
name: 'Mr. Anderson',
company: 'MegaCorp',
agent: 'Agent Smith',
news: 'bad',
reason: 'your cat died.'
}
const tstring = await fetch('./demo.tpl').then(r => r.text())
console.log(tt(tstring, vars))
</script>
```
You can also see an example that uses inline-templates, [here](https://github.com/konsumer/template-templates/blob/master/test/demo.html).
### advanced
#### back-ticks
You can use back-ticks directly in your template, if you need to, which normally you would have to escape:
```
This is a markdown string with `code`.
```
#### plugins
You can give it util functions, in it's variables, and use them, if you like. Think of this as "plugins":
```js
import tt from 'template-templates'
import { pluralize } from 'inflection'
const tstring = 'You have ${count} ${pluralize(thing, count)}.'
const vars = {
pluralize,
count: 10,
thing: 'marble'
}
console.log(tt(tstring, vars))
/*
You have 10 marbles.
*/
```
#### pre-compiling
There isn't really a huge performance difference between using `compile` first, or the immediate-mode. The downside is that you have to tell it what variables are going to be valid, but this should be pretty simple, in most cases. This technique shines in a place like a build script, where you want all the template functions, already working, without needing access to file-system to load templates, or have a dependency on `template-templates` in the output:
```js
import tt from 'template-templates'
import glob from 'glob-promise'
import { readFile, writeFile } from 'fs/promises'
import { basename } from 'path'
const out = []
for (const file of await glob('./templates/*.tpl')) {
const name = basename(file, '.tpl')
out.push(`export const ${name} = ${tt.compile(await readFile(file, 'utf8'), ['name', 'company', 'agent', 'news', 'reason']).toString()}`))
}
await writeFile('templates.js', out.join('\n\n'))
```
then you can use them later:
```js
import { demo } from './templates.js'
console.log(demo({
name: 'Mr. Anderson',
company: 'MegaCorp',
agent: 'Agent Smith',
news: 'good',
reason: 'you won the lottery.'
}))
```
I might use this technique, for example, if I don't want to include `template-templates` in the output, and I don't want to worry about how to work with the filesystem.