{"id":22780062,"url":"https://github.com/sitegui/ejs-html","last_synced_at":"2025-04-15T14:43:13.192Z","repository":{"id":57221159,"uuid":"47900166","full_name":"sitegui/ejs-html","owner":"sitegui","description":"Embedded JavaScript HTML templates. Another implementation of EJS, focused on run-time performance, basic HTML syntax checking and outputting minified HTML.","archived":false,"fork":false,"pushed_at":"2018-01-30T16:41:13.000Z","size":136,"stargazers_count":8,"open_issues_count":3,"forks_count":3,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-28T21:21:35.959Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sitegui.png","metadata":{"files":{"readme":"README.md","changelog":"HISTORY.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-12-13T00:29:25.000Z","updated_at":"2024-01-09T07:52:59.000Z","dependencies_parsed_at":"2022-08-29T01:50:54.701Z","dependency_job_id":null,"html_url":"https://github.com/sitegui/ejs-html","commit_stats":null,"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sitegui%2Fejs-html","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sitegui%2Fejs-html/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sitegui%2Fejs-html/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sitegui%2Fejs-html/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sitegui","download_url":"https://codeload.github.com/sitegui/ejs-html/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249091858,"owners_count":21211419,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-11T20:12:10.152Z","updated_at":"2025-04-15T14:43:13.175Z","avatar_url":"https://github.com/sitegui.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# EJS HTML\r\n[![Build Status](https://travis-ci.org/sitegui/ejs-html.svg?branch=master)](https://travis-ci.org/sitegui/ejs-html)\r\n[![Inline docs](https://inch-ci.org/github/sitegui/ejs-html.svg?branch=master)](https://inch-ci.org/github/sitegui/ejs-html)\r\n[![Dependency Status](https://david-dm.org/sitegui/ejs-html.svg)](https://david-dm.org/sitegui/ejs-html)\r\n\r\nEmbedded JavaScript HTML templates. An implementation of EJS focused on run-time performance, HTML syntax checking, minified HTML output and custom HTML elements.\r\n\r\n## Usage\r\n`npm install ejs-html --save`\r\n\r\n```js\r\nlet ejs = require('ejs-html')\r\n\r\nlet html = ejs.render('\u003cinput type=\"text\" disabled=\"\u003c%=disabled%\u003e\" value=\"\u003c%=value%\u003e\" /\u003e', {\r\n    disabled: false,\r\n    value: 'hi you'\r\n}, {\r\n    vars: ['disabled', 'value']\r\n})\r\n\r\n// html = '\u003cinput type=text value=\"hi you\"\u003e'\r\n```\r\n\r\n## Why another EJS implementation?\r\nThis 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.\r\n\r\nCheck their excellent site for EJS-specific docs and tutorials.\r\n\r\nStrictly speaking, this *is not* even EJS (details bellow).\r\n\r\n## Breaking changes in v5\r\nOld versions compiled to sloppy mode and used the `with(locals)` block by default.\r\nThat allowed one to write `\u003c%= a %\u003e` instead of `\u003c%= locals.a %\u003e` but had more unwanted consequences.\r\nRead 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).\r\n\r\n## Features\r\n\r\n### Compile-time HTML minification\r\nThe template source is parsed and minified on compile time, so there is no impact on render-time. The minification applies these rules:\r\n\r\n* Collapse text whitespace: `\u003cb\u003eHello\\n\\t you\u003c/b\u003e` is transformed to `\u003cb\u003eHello\\nyou\u003c/b\u003e`\r\n* Remove attribute quotes: `\u003cdiv class=\"alert\"\u003e` → `\u003cdiv class=alert\u003e`\r\n* Normalize attributes spaces: `\u003cinput \\n required\u003e` → `\u003cinput required\u003e`\r\n* Normalize class spaces: `\u003cdiv class=\"  a   b \"\u003e` → `\u003cdiv class=\"a b\"\u003e`\r\n* Simplify boolean attributes: `\u003cinput required=\"oh-yeah!\"\u003e` → `\u003cinput required\u003e`\r\n* Remove self-close slash: `\u003cbr /\u003e` → `\u003cbr\u003e`\r\n\r\n### Render-time error mapping\r\nErrors during render-time are mapped back to their original source location (that is, we keep an internal source map)\r\n\r\n```js\r\nejs.render(`\u003cselect\u003e\r\n\u003c% for (let option of locals.options) { %\u003e\r\n    \u003coption value=\"\u003c%= option.value %\u003e\"\u003e\r\n      \u003c%= option.text %\u003e\r\n    \u003c/option\u003e\r\n\u003c% } %\u003e\r\n\u003c/select\u003e`, {\r\n    options: [null]\r\n})\r\n```\r\n\r\n```\r\nTypeError: ejs:3\r\n 1    | \u003cselect\u003e\r\n 2    | \u003c% for (let option of options) { %\u003e\r\n 3 \u003e\u003e |         \u003coption value=\"\u003c%= option.value %\u003e\"\u003e\r\n 4    |                 \u003c%= option.text %\u003e\r\n 5    |         \u003c/option\u003e\r\n\r\nCannot read property 'value' of null\r\n    at eval (eval at module.exports (D:\\Programs\\ejs-html\\lib\\compile.js:45:20), \u003canonymous\u003e:4:51)\r\n    at D:\\Programs\\ejs-html\\lib\\compile.js:64:11\r\n    at Object.module.exports.render (D:\\Programs\\ejs-html\\index.js:12:48)\r\n```\r\n\r\n### Boolean attributes\r\nAttributes like `disabled` and `checked` are recognized as boolean. So one may write `disabled=\u003c%=disabled%\u003e` instead of `\u003c%if(disabled){%\u003edisabled\u003c%}%\u003e`, as one must in plain EJS.\r\n\r\nThis 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.\r\n\r\n### Server-side compiled, client-side rendered\r\nCompile the template server-side and export a function to render it in the client-side.\r\n\r\n### Extensible semantics\r\nTransformers may be registered to change the parsed elements tree and implement custom semantics.\r\n\r\nFor example:\r\n```js\r\n// change I elements for EM\r\n\r\nvar render = ejs.compile('\u003ci\u003eHi\u003c/i\u003e \u003cp\u003e\u003ci\u003eDeep\u003c/i\u003e\u003c/p\u003e', {\r\n    transformer: function translate(tokens) {\r\n        tokens.forEach(token =\u003e {\r\n            if (token.type === 'element') {\r\n                if (token.name === 'i') {\r\n                    token.name = 'em'\r\n                }\r\n                translate(token.children)\r\n            }\r\n        })\r\n    }\r\n})\r\n\r\nrender() // '\u003cem\u003eHi\u003c/em\u003e \u003cp\u003e\u003cem\u003eDeep\u003c/em\u003e\u003c/p\u003e'\r\n```\r\n\r\n### Custom elements\r\nUnleash the semantic power of HTML with custom elements. To use custom elements you must first define one:\r\n\r\nFor example, define your own confirm dialog (in `dialog.ejs`):\r\n```html\r\n\u003cdiv class=\"dialog\"\u003e\r\n    \u003cdiv class=\"dialog-title\"\u003e\r\n        \u003c%= title %\u003e\r\n        \u003c% if (closable) { %\u003e\r\n            \u003cdiv class=\"dialog-close\"\u003eX\u003c/div\u003e\r\n        \u003c% } %\u003e\r\n    \u003c/div\u003e\r\n    \u003ceh-placeholder\u003e\r\n        \u003c!-- dialog content goes here --\u003e\r\n    \u003c/eh-placeholder\u003e\r\n    \u003cdiv class=\"dialog-buttons\"\u003e\r\n        \u003cbutton class=\"dialog-yes\"\u003eYes\u003c/button\u003e\r\n        \u003cbutton class=\"dialog-no\"\u003eNo\u003c/button\u003e\r\n    \u003c/div\u003e\r\n\u003c/div\u003e\r\n```\r\n\r\nAnd then use it, like:\r\n```html\r\n\u003ccustom-dialog title=\"Wanna Know?\" closable\u003e\r\n    \u003cem\u003eHTML\u003c/em\u003e Content\r\n\u003c/custom-dialog\u003e\r\n```\r\n\r\nThe attributes on the `custom-dialog` tag is passed as locals to `dialog.ejs` and its content replaces the `\u003ceh-placeholder\u003e\u003c/eh-placeholder\u003e` tag.\r\n\r\nCustom elements is a more powerful replacement for ejs' include feature.\r\n\r\nThis 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)\r\n\r\n## Source maps\r\nCompile with support for source map generation (requires node \u003e= v8, since `source-map` has dropped support for older versions)\r\n```js\r\nlet fn = ejs.compile('Hello \u003c%= locals.world %\u003e', {sourceMap: true})\r\n// The actual result may vary\r\nfn.code // \"use strict\";locals=locals||{};let __c=locals.__contents||{};return \"Hello \"+(__l.s=__l.e=1,__e(locals.world));\r\nfn.map // {\"version\":3,\"sources\":[\"ejs\"],\"names\":[],\"mappings\":\"gGAAU,Y\",\"file\":\"ejs.js\"}\r\nfn.mapWithCode // {\"version\":3,\"sources\":[\"ejs\"],\"names\":[],\"mappings\":\"gGAAU,Y\",\"file\":\"ejs.js\",\"sourcesContent\":[\"Hello \u003c%= locals.world %\u003e\"]}\r\n```\r\n\r\n## Missing features\r\nThe following list of features are supported in other EJS implementations, but not by this one (at least, yet):\r\n\r\n* No support for custom delimiters\r\n* No caching\r\n* No built-in express support\r\n* No include: use custom elements instead\r\n\r\n## API\r\n\r\nThe main API is the `compile` function. Everything else is auxiliary.\r\n\r\n### compile(source[, options])\r\nCompile the given EJS-HTML source into a render function. `options` is an optional object, with the following optional keys:\r\n\r\n* `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\r\n* `filename`: used to name the file in render-time error's stack trace\r\n* `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.\r\n* `strictMode`: if `false`, use sloppy mode and wrap the code in a `with(locals) {}` block (defaults to `true`).\r\n* `vars`: an array of var names that will be exposed from `locals` (defaults to `[]`).\r\n* `sourceMap`: if `true`, create and return the source map\r\n\r\nThis 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.\r\n\r\nThe returned function has three extra properties if `sourceMap` is active:\r\n* `fn.code`: compiled JS code\r\n* `fn.map`: source map without the source code\r\n* `fn.mapWithCode`: source map with the source code\r\n\r\n### compile.standAlone(source[, options])\r\nLike `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:\r\n\r\n```js\r\n// On the server\r\nlet functionBody = ejs.compile.standAlone('\u003cp\u003eHi \u003c%=name%\u003e\u003c/p\u003e', {vars: ['name']})\r\n\r\n// On the client\r\nvar render = new Function('locals, renderCustom', functionBody)\r\nrender({name: 'you'}) // \u003cp\u003eHi you\u003c/p\u003e\r\n```\r\n\r\n### compile.standAloneAsObject(source[, options])\r\nLike `compile.standAlone()`, but returns an object with three properties:\r\n* `obj.code`: the compiled code, the same value returned by `compile.standAlone()`\r\n* `obj.map` and `obj.mapWithCode`: extra properties when `sourceMap` option is active\r\n\r\n### render(source[, locals[, options]])\r\nJust a convinience for `compile(source, options)(locals)`.\r\n\r\n### parse(source)\r\nParse the given EJS-HTML source into a array of tokens. Use for low-level, crazy thinks (like some internal tooling).\r\n\r\n### reduce(tokens[, options])\r\nRemove comments, transform fixed tokens back to text and apply HTML minification. Use for low-level, crazy things.\r\n\r\n### escape.html(str)\r\nReturn a HTML-safe version of `str`, escaping \u0026, \u003c, \u003e, \" and '\r\n\r\n### escape.js(str)\r\nEscape as to make safe to put inside double quotes: `x = \"...\"`, escaping \\, \\n, \\r and \"\r\n\r\n### escape.getSnippet(source, lineStart, lineEnd)\r\nExtract the code snippet in the given region (used internally to create error messages)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsitegui%2Fejs-html","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsitegui%2Fejs-html","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsitegui%2Fejs-html/lists"}