https://github.com/sitegui/ejs-html
Embedded JavaScript HTML templates. Another implementation of EJS, focused on run-time performance, basic HTML syntax checking and outputting minified HTML.
https://github.com/sitegui/ejs-html
Last synced: over 1 year ago
JSON representation
Embedded JavaScript HTML templates. Another implementation of EJS, focused on run-time performance, basic HTML syntax checking and outputting minified HTML.
- Host: GitHub
- URL: https://github.com/sitegui/ejs-html
- Owner: sitegui
- License: mit
- Created: 2015-12-13T00:29:25.000Z (over 10 years ago)
- Default Branch: master
- Last Pushed: 2018-01-30T16:41:13.000Z (over 8 years ago)
- Last Synced: 2025-03-28T21:21:35.959Z (over 1 year ago)
- Language: JavaScript
- Size: 133 KB
- Stars: 8
- Watchers: 1
- Forks: 3
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- Changelog: HISTORY.md
- License: LICENSE
Awesome Lists containing this project
README
# EJS HTML
[](https://travis-ci.org/sitegui/ejs-html)
[](https://inch-ci.org/github/sitegui/ejs-html)
[](https://david-dm.org/sitegui/ejs-html)
Embedded JavaScript HTML templates. An implementation of EJS focused on run-time performance, HTML syntax checking, minified HTML output and custom HTML elements.
## Usage
`npm install ejs-html --save`
```js
let ejs = require('ejs-html')
let html = ejs.render('', {
disabled: false,
value: 'hi you'
}, {
vars: ['disabled', 'value']
})
// html = ''
```
## Why another EJS implementation?
This module is inspired by [EJS](http://ejs.co/), and is a subset of its syntax, focused on giving HTML first-class support. That is, not all EJS are valid EJS-HTML. Most features listed bellow are possible only with an HTML-aware parser.
Check their excellent site for EJS-specific docs and tutorials.
Strictly speaking, this *is not* even EJS (details bellow).
## Breaking changes in v5
Old versions compiled to sloppy mode and used the `with(locals)` block by default.
That allowed one to write `<%= a %>` instead of `<%= locals.a %>` but had more unwanted consequences.
Read more about what changed and how to opt-out from the change in [HISTORY.md](https://github.com/sitegui/ejs-html/blob/master/HISTORY.md).
## Features
### Compile-time HTML minification
The template source is parsed and minified on compile time, so there is no impact on render-time. The minification applies these rules:
* Collapse text whitespace: `Hello\n\t you` is transformed to `Hello\nyou`
* Remove attribute quotes: `
` → ``
* Normalize attributes spaces: `` → ``
* Normalize class spaces: `` → ``
* Simplify boolean attributes: `` → ``
* Remove self-close slash: `
` → `
`
### Render-time error mapping
Errors during render-time are mapped back to their original source location (that is, we keep an internal source map)
```js
ejs.render(`
<% for (let option of locals.options) { %>
<%= option.text %>
<% } %>
`, {
options: [null]
})
```
```
TypeError: ejs:3
1 |
2 | <% for (let option of options) { %>
3 >> |
4 | <%= option.text %>
5 |
Cannot read property 'value' of null
at eval (eval at module.exports (D:\Programs\ejs-html\lib\compile.js:45:20), :4:51)
at D:\Programs\ejs-html\lib\compile.js:64:11
at Object.module.exports.render (D:\Programs\ejs-html\index.js:12:48)
```
### Boolean attributes
Attributes like `disabled` and `checked` are recognized as boolean. So one may write `disabled=<%=disabled%>` instead of `<%if(disabled){%>disabled<%}%>`, as one must in plain EJS.
This is one point that makes EJS-HTML not EJS-compliant. In EJS, any literal text is outputed as is. In the example above this is not what happens: the text `disabled=` is not outputed if the local value `disabled` is falsy, since ejs-html knows this is a boolean attribute.
### Server-side compiled, client-side rendered
Compile the template server-side and export a function to render it in the client-side.
### Extensible semantics
Transformers may be registered to change the parsed elements tree and implement custom semantics.
For example:
```js
// change I elements for EM
var render = ejs.compile('Hi
Deep
', {
transformer: function translate(tokens) {
tokens.forEach(token => {
if (token.type === 'element') {
if (token.name === 'i') {
token.name = 'em'
}
translate(token.children)
}
})
}
})
render() // 'Hi
Deep
'
```
### Custom elements
Unleash the semantic power of HTML with custom elements. To use custom elements you must first define one:
For example, define your own confirm dialog (in `dialog.ejs`):
```html
<%= title %>
<% if (closable) { %>
X
<% } %>
```
And then use it, like:
```html
HTML Content
```
The attributes on the `custom-dialog` tag is passed as locals to `dialog.ejs` and its content replaces the `` tag.
Custom elements is a more powerful replacement for ejs' include feature.
This is the most basic usage of this feature. For more (like passing JS values and multiple content areas), see [custom-els.md](https://github.com/sitegui/ejs-html/blob/master/custom-els.md)
## Source maps
Compile with support for source map generation (requires node >= v8, since `source-map` has dropped support for older versions)
```js
let fn = ejs.compile('Hello <%= locals.world %>', {sourceMap: true})
// The actual result may vary
fn.code // "use strict";locals=locals||{};let __c=locals.__contents||{};return "Hello "+(__l.s=__l.e=1,__e(locals.world));
fn.map // {"version":3,"sources":["ejs"],"names":[],"mappings":"gGAAU,Y","file":"ejs.js"}
fn.mapWithCode // {"version":3,"sources":["ejs"],"names":[],"mappings":"gGAAU,Y","file":"ejs.js","sourcesContent":["Hello <%= locals.world %>"]}
```
## Missing features
The following list of features are supported in other EJS implementations, but not by this one (at least, yet):
* No support for custom delimiters
* No caching
* No built-in express support
* No include: use custom elements instead
## API
The main API is the `compile` function. Everything else is auxiliary.
### compile(source[, options])
Compile the given EJS-HTML source into a render function. `options` is an optional object, with the following optional keys:
* `compileDebug`: if `false`, no extended context will be added to exceptions thrown at runtime (defaults to `true`). If `true`, the compiled code will be larger and will include the original EJS source
* `filename`: used to name the file in render-time error's stack trace
* `transformer`: a function that can transform the parsed HTML element tree, before the minification and compilation. This should return a new array of tokens or `undefined` to use the same (in case of in-place changes). Consult the definition of a `Token` in the [parse.js](https://github.com/sitegui/ejs-html/blob/master/lib/parse.js) file.
* `strictMode`: if `false`, use sloppy mode and wrap the code in a `with(locals) {}` block (defaults to `true`).
* `vars`: an array of var names that will be exposed from `locals` (defaults to `[]`).
* `sourceMap`: if `true`, create and return the source map
This will return a compiled render function that can then be called like: `render(locals[, renderCustom])`. `locals` is the data object used to fill the template. `renderCustom` is an optional function used to render custom elements, see [custom-els.md](https://github.com/sitegui/ejs-html/blob/master/custom-els.md) for more info about it.
The returned function has three extra properties if `sourceMap` is active:
* `fn.code`: compiled JS code
* `fn.map`: source map without the source code
* `fn.mapWithCode`: source map with the source code
### compile.standAlone(source[, options])
Like `compile()`, but returns the function body code as a string, so that it can be exported somewhere else. A use case for this is compile the EJS template in the server, export the function to the client and render in the browser:
```js
// On the server
let functionBody = ejs.compile.standAlone('
Hi <%=name%>
', {vars: ['name']})
// On the client
var render = new Function('locals, renderCustom', functionBody)
render({name: 'you'}) //
Hi you
```
### compile.standAloneAsObject(source[, options])
Like `compile.standAlone()`, but returns an object with three properties:
* `obj.code`: the compiled code, the same value returned by `compile.standAlone()`
* `obj.map` and `obj.mapWithCode`: extra properties when `sourceMap` option is active
### render(source[, locals[, options]])
Just a convinience for `compile(source, options)(locals)`.
### parse(source)
Parse the given EJS-HTML source into a array of tokens. Use for low-level, crazy thinks (like some internal tooling).
### reduce(tokens[, options])
Remove comments, transform fixed tokens back to text and apply HTML minification. Use for low-level, crazy things.
### escape.html(str)
Return a HTML-safe version of `str`, escaping &, <, >, " and '
### escape.js(str)
Escape as to make safe to put inside double quotes: `x = "..."`, escaping \, \n, \r and "
### escape.getSnippet(source, lineStart, lineEnd)
Extract the code snippet in the given region (used internally to create error messages)