dyn-template
English | 中文
Dynamic template strings. It works similarly to JavaScript's template literals, with two key differences:
- While template literals return a string directly, dynamic templates return a function that returns a string when called
- If an expression in the dynamic template is a function, that function will be executed each time the dynamic template is called
Installation
npm i dyn-template
Usage
import { dyn } from 'dyn-template'
let n = 0
const random = dyn`${() => ++n}. ${Math.random}`
while (n < 5) console.log(random())
If an expression in the dynamic template is a function, it will be executed each time the dynamic template is called.
On the other hand, if an expression is not a function, it will only be evaluated once when creating the dynamic template.
import { dyn } from 'dyn-template'
const template = dyn`Compile time: ${Date.now()}, Runtime: ${Date.now}`
for (let n = 0; n < 1000; ++n) console.log(template())
Advanced Usage
import { dynTemplate, closure } from 'dyn-template'
const fn1 = () => new Date()
const fn2 = Math.random
const template = dynTemplate`str1 ${fn1} str2 ${'non-function expression'} str3 ${fn2} str4`
console.log(template)
const fn = closure(template)
console.log(fn())
The object returned by dynTemplate
contains three properties:
first
: The first text block in the templatefns
: All functions in the templatestrs
: Other text blocks in the template. If there are non-function expressions, they will be evaluated and concatenated into the text blocks
The fns
and strs
arrays are frozen, so they are immutable, but their elements can be modified.
The closure
function converts the above object into a function. Its implementation is as follows:
function closure(template) {
const { first, fns, strs } = template
return function () { return fns.reduce((r, p, i) => r + p() + strs[i], first) }
}
So the following two approaches are equivalent:
import { dynTemplate, closure, dyn } from 'dyn-template'
const t1 = closure(dynTemplate`...`)
const t2 = dyn`...`
When you need to further process the template content, you can first use dynTemplate
to generate a template object, process it further, and then use closure
to convert it into a function.
When you need to modify the closure process, you can first use dynTemplate
to generate a template object, then rewrite a function similar to closure
:
function compile(template) {
const { first, fns, strs } = template
return function (time) {
const t = time instanceof Date ? time : new Date(time)
return fns.reduce((r, p, i) => r + p(t) + strs[i], first)
}
}
const template = compile(dynTemplate`Today is ${t => t.getMonth() + 1}/${t => t.getDate()}`)
console.log(template(Date.now()))
This allows you to customize the closure calling process to implement more complex functionality. clock-reader is implemented using a similar approach.