A composable DOM based template engine
npm i @lcf.vs/dom-engine
There is 2 type of markers:
- Required:
{name}
- The value can't be nullish
- Optional:
{?name}
- If a nullish value is provided for an attribute, that attribute is removed
import { template } from '@lcf.vs/dom-engine'
const pTemplate = template(`<p class="{?classes}">{salutations} {?name}</p>`, {
classes: null,
salutations: null,
name: null
})
import { source } from '@lcf.vs/dom-engine'
const pTemplate = {
[source]: '<p class="{?classes}">{salutations} {?name}</p>',
classes: null,
salutations: null,
name: null
}
// object representing <p>hello user-name</p>
const p = {
...pTemplate,
salutations: 'hello',
name: 'user-name'
}
// object representing <p>hello</p>
const p = {
...pTemplate,
salutations: 'hello'
}
// Error: missing {salutations} (on serialization)
const p = {
...pTemplate
}
const taggedName = {
[source]: '<strong>{name}</strong>',
name: null
}
// object representing <p>hello <string>user-name</strong></p>
const p = {
...pTemplate,
salutations: 'hello',
name: {
...taggedName,
name: 'user-name'
}
}
// object representing <p>hello <strong>user-name</strong></p>
const p = {
...pTemplate,
salutations: 'hello',
name: {
...taggedName,
name: 'user-name'
}
}
// object representing <p>hello <strong><span>user-name</span></strong></p>
const p = {
...pTemplate,
salutations: 'hello',
name: template(`<span>user-name</span>`)
}
// object representing <p>hello <strong><span>user</span>-<span>name</span></strong></p>
const p = {
...pTemplate,
salutations: 'hello',
name: [
template(`<span>user</span>`),
template(`-`),
template(`<span>name</span>`)
]
}
// object representing <p>hello <strong>user</strong></p>
const pTemplate = {
[source]: '<p>{salutations} <strong>{user.name}</strong></p>',
salutations: 'hello',
user: {
name: 'user'
}
}
import { serialize } from '@lcf.vs/dom-engine'
const p = template(`<p>user-name</p>`)
const html = await serialize(p)
import { template, source } from '@lcf.vs/dom-engine'
const tpl = template(html, { ...fields } = {})
// or
const tpl = {
[source]: html,
...fields
}
import { load } from '@lcf.vs/dom-engine'
// loads a file with the same name than the current module,
// but with a .html extension instead of the current one
const tpl = await load(import.meta, { ...options } = {}, { ...data } = {})
Where the options are the async readFile()
ones
import { serialize } from '@lcf.vs/dom-engine'
const htmlString = await serialize(template)
Or
import { render } from '@lcf.vs/dom-engine'
const htmlNode = render(template)
import { load } from '@lcf.vs/dom-engine'
// loads a file with the same name than the current module,
// but with a .html extension instead of the current one
const tpl = await load(import.meta, { ...options } = {}, { ...data } = {})
Where the options are the fetch()
ones
import { serialize } from '@lcf.vs/dom-engine'
const htmlString = await serialize(template)
Or
import { render } from '@lcf.vs/dom-engine'
const htmlNode = render(template)
The engine also supports the rendering of some templates stored into a ServiceWorker
.
To use it, you need to add the following components.
import '@lcf.vs/dom-engine/lib/worker-client.js'
import { load } from '@lcf.vs/dom-engine'
// loads a file with the same name than the current module,
// but with a .html extension instead of the current one
const tpl = await load(import.meta, { ...optio*ns } = {}, { ...data } = {})
Where the options are the fetch()
ones
import { serialize, source } from '@lcf.vs/dom-engine'
const text = 'This page is built by sw-template'
const view = {
[source]: `<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>{text}</title>
<script src="/main.js" type="module"></script>
</head>
<body>
<main>
<h1>{text}</h1>
<a href="/">back to home</a>
</main>
</body>
</html>`
}
const html = await serialize({
...view,
text
})
Just note that: if the browser doesn't support the ES6 modules, into the ServiceWorker
, you should need to bundle your code.
To improve your client-side security, you can add the following header on your requests (or via a <meta>
)
Content-Security-Policy: default-src 'none'; connect-src 'self'; script-src 'self'; style-src 'self'; require-trusted-types-for 'script'; trusted-types dom-engine
Since the templates filling is intended to avoid XSS injections, by design, you need to be sure about your templates.
Of course, it's just a minimal one, you can adapt it on your needs.