{"id":20936220,"url":"https://github.com/adzerk/micro-html-template","last_synced_at":"2026-04-21T22:02:28.621Z","repository":{"id":66596093,"uuid":"114389282","full_name":"adzerk/micro-html-template","owner":"adzerk","description":"Template compiler for nodejs","archived":false,"fork":false,"pushed_at":"2018-01-19T13:34:04.000Z","size":40,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":24,"default_branch":"master","last_synced_at":"2025-12-31T14:43:44.909Z","etag":null,"topics":["delivery"],"latest_commit_sha":null,"homepage":"","language":"CoffeeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/adzerk.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-12-15T16:16:19.000Z","updated_at":"2025-09-09T13:26:13.000Z","dependencies_parsed_at":null,"dependency_job_id":"2eed66b2-8f8e-4cdd-a957-504111c79608","html_url":"https://github.com/adzerk/micro-html-template","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/adzerk/micro-html-template","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adzerk%2Fmicro-html-template","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adzerk%2Fmicro-html-template/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adzerk%2Fmicro-html-template/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adzerk%2Fmicro-html-template/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/adzerk","download_url":"https://codeload.github.com/adzerk/micro-html-template/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adzerk%2Fmicro-html-template/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32112030,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-21T11:25:29.218Z","status":"ssl_error","status_checked_at":"2026-04-21T11:25:28.499Z","response_time":128,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["delivery"],"created_at":"2024-11-18T22:18:24.855Z","updated_at":"2026-04-21T22:02:28.580Z","avatar_url":"https://github.com/adzerk.png","language":"CoffeeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# micro-html-template\n\nTemplate system based roughly on [Jinja2][jinja], designed with a focus on\nsecurity, simplicity, rendering speed, and minimal clientside footprint.\n\nFeatures:\n\n* **Small feature set** \u0026mdash; focused on simple value replacement and filters.\n* **Small runtime** \u0026mdash; the JavaScript needed to render compiled templates\n  in the client is about 1.1KB, uncompressed.\n* **Small precompiled size** \u0026mdash; compiled templates are approximately the\n  same size as the templates themselves.\n* **Contextual escaping** \u0026mdash; [anti-XSS escaping policies][owasp-xss] are\n  applied automatically based on the HTML context.\n\nNon-Features:\n\n* **Compiling templates in the client** \u0026mdash; templates must be precompiled\n  in nodejs.\n* **Complex template programming** \u0026mdash; no support for loops, conditionals,\n  tags, inheritance, etc.\n* **Protection against malicious templates** \u0026mdash; it is assumed that templates\n  are created by trusted users only.\n\n## Usage\n\nCompile and render a template in nodejs:\n\n```javascript\n// Compile\nvar compile     = require('micro-html-template').compile;\nvar precompiled = compile(\"\u003cimg src='https://example.com?myname={{user.name}}'\u003e\");\n\n// Render\nvar render      = require('micro-html-template-runtime').render;\nvar env         = {user: {name: 'Jar Jar B.'}};\nvar htmlContent = render(precompiled, env);\n```\n\nRender the template in the client:\n\n```html\n\u003cdiv id='template1'\u003e\u003c/div\u003e\n\u003cscript src='dist/micro-html-template-runtime.min.js'\u003e\u003c/script\u003e\n\u003cscript\u003e\n  var precompiled = '...'; // precompiled template string from nodejs\n  var env         = {user: {name: 'Jar Jar B.'}};\n  var htmlContent = microHtmlTemplate.render(precompiled, env);\n  document.getElementById('template1').innerHTML = htmlContent;\n\u003c/script\u003e\n```\n\nThe result:\n\n```html\n\u003cdiv id='template1'\u003e\n  \u003cimg src='https://example.com?myname=Jar%20Jar%20B.'\u003e\n\u003c/div\u003e\n```\n\nSee the [tests][tests] for more examples.\n\n## Templates\n\nThis libarary is designed for applications where templates are created only by\ntrusted users, but data used to render the templates is untrusted. Template\ndata will be automatically protected against XSS by a combination of HTML and\nURI component escaping, depending on the context.\n\n**Templates must be valid HTML** \u0026mdash; macros may only appear in:\n* text nodes\n* quoted attribute values\n\n**Macros in unsafe contexts are ignored** \u0026mdash; macros may not appear in:\n* `\u003cscript\u003e` tags\n* `\u003cstyle\u003e` tags\n* `style` attribute values\n* `on*` event attribute values\n\nOk:\n\n```jinja\n\u003c!-- Text nodes are safe contexts (except in 'style' and 'script' tags). --\u003e\n\u003cdiv\u003eHello, {{user.name}}!\u003c/div\u003e\n```\n\n```jinja\n\u003c!-- Quoted attribute values are safe contexts (except for 'style' and 'on*'). --\u003e\n\u003cimg height='{{height}}px'\u003e\n```\n\nUnsafe:\n\n```jinja\n\u003c!-- Template is not valid HTML. (Behavior is undefined.) --\u003e\n\u003c{{tag.name}} src='http://example.com'\u003e\n```\n\n```jinja\n\u003c!-- Macro in script tag (passed through verbatim). --\u003e\n\u003cscript\u003evar x = {{foo.x}};\u003c/script\u003e\n```\n\n```jinja\n\u003c!-- Macro in style tag (passed through verbatim). --\u003e\n\u003cstyle\u003ehtml {background:{{colors.foo}};}\u003c/style\u003e\n```\n\n```jinja\n\u003c!-- Macro in style attribute (passed through verbatim). --\u003e\n\u003cdiv style='background:{{colors.foo}};'\u003ehello world\u003c/div\u003e\n```\n\n```jinja\n\u003c!-- Macro in on* attribute (passed through verbatim). --\u003e\n\u003cdiv onclick='alert(\"hello {{user.name}}\")'\u003ehello world\u003c/div\u003e\n```\n\n## Contextual Escaping\n\nThe results of all macro replacements are automatically HTML escaped. However,\ncertain attributes are interpreted as URIs by the browser (the `src` attribute\nof an `\u003ciframe\u003e`, for example). Macro replacements in these attributes are URI\nencoded (eg. `encodeURIComponent()`) and then HTML escaped.\n\n```jinja\n\u003c!-- Replacements in text nodes are just HTML escaped. --\u003e\n\u003cdiv\u003ehello {{user.name}}\u003c/div\u003e\n```\n\n```jinja\n\u003c!-- Replacements in regular attributes are just HTML escaped. --\u003e\n\u003cimg data-foo='https://example.com?myname={{user.name}}'\u003e\n```\n\n```jinja\n\u003c!-- Replacements in URI type attributes are both URI encoded and HTML escaped. --\u003e\n\u003cimg src='https://example.com?myname={{user.name}}'\u003e\n```\n\n## Raw Mode\n\nAutomatic contextual escaping can be disabled for individual macros: see [Filters](#filters) below.\n\n## Values\n\nThe values used in macro expansion are provided as literals or via the `env`\nobject (passed as an argument to `render`).\n\n```jinja\n\u003c!-- JSON string and number literals are values that can be used in macros. --\u003e\n\u003cul\u003e\n  \u003cli\u003ei = {{\"√-͞1\"}}\u003c/li\u003e\n  \u003cli\u003e? = {{42}}\u003c/li\u003e\n  \u003cli\u003eπ = {{3.14}}\u003c/li\u003e\n  \u003cli\u003eħ = {{6.58e-16}}\u003c/li\u003e\n\u003c/ul\u003e\n```\n\n```jinja\n\u003c!-- Variable names refer to properties of the env object. --\u003e\n\u003cdiv\u003ehello {{name}}\u003c/div\u003e\n```\n\n```jinja\n\u003c!-- Use the dot operator to access nested values. --\u003e\n\u003cdiv\u003ehello {{user.name}}\u003c/div\u003e\n```\n\n```jinja\n\u003c!-- Square brackets work, too. --\u003e\n\u003cdiv\u003ehello {{user[\"name\"]}}\u003c/div\u003e\n```\n\n```jinja\n\u003c!-- Variables can be used inside the square brackets. --\u003e\n\u003cdiv\u003ehello {{user[prop]}}\u003c/div\u003e\n```\n\n```jinja\n\u003c!-- Square brackets are also used for array access. --\u003e\n\u003cdiv\u003ehello {{users[0].name}}\u003c/div\u003e\n```\n\n## Filters\n\nFilters are functions that are applied to the replacement text. Filters are\nexpressed as a pipeline:\n\n```jinja\n\u003cimg src='https://example.com?q={{query | filter1 | filter2}}'\u003e\n```\n\nFilters beginning with a `.` character denote method invocation:\n\n```jinja\n\u003cimg src='https://example.com?q={{query | .toUpperCase}}'\u003e\n```\n\nFilters and methods may take arguments:\n\n```jinja\n\u003cimg src='https://example.com?q={{query | doit(\"foo\", bar.baz) | .substr(42)}}'\u003e\n```\n\nThe following built-in filters are included:\n\n* `id` \u0026mdash; The identity filter, does nothing.\n* `uri` \u0026mdash; Escapes input for URI component context.\n* `html` \u0026mdash; Escapes input for HTML context.\n* `raw` \u0026mdash; Applied at the end of the pipeline this filter disables auto-escaping.\n\nNote that the `uri` and `html` filters are automatically applied as needed to\nprevent XSS. However, it may sometimes make sense to use them in macros, for\ninstance to escape URI components in an attribute that is not automatically\ninterpreted by the browser as a URI type:\n\n```jinja\n\u003c!-- The 'data-myurl' attribute normally would not be considered a URI context\n     so URI component escaping must be specified by adding the uri filter. --\u003e\n\u003cdiv data-myurl='https://example.com?q={{query | uri}}'\u003e\u003c/div\u003e\n```\n\nOr if you need to double-escape a URI component for some reason:\n\n```jinja\n\u003c!-- The 'href' attribute is already a URI type, so this will be double-escaped. --\u003e\n\u003ca href='https://example.com?q={{query | uri}}'\u003eQuery\u003c/a\u003e\n```\n\nOr when using the `raw` filter on trusted data:\n\n```jinja\n\u003c!-- Without \"raw\" the macro would be URI component escaped, which we don't want.\n     Using the \"html\" filter preserves the HTML escaping, though, which we do want. --\u003e\n\u003cimg src='{{impressionUrl | html | raw}}'\u003e\n```\n\n## Custom Filters\n\nFilters can be added to the runtime in nodejs:\n\n```javascript\nruntime = require('micro-html-template-runtime');\n\nruntime.filters.uppercase = function(val) {\n  return val.toUpperCase();\n};\n```\n\nor in the client:\n\n```html\n\u003cscript\u003e\n  microHtmlTemplate.filters.uppercase = function(val) {\n    return val.toUpperCase();\n  };\n\u003c/script\u003e\n```\n\nFilters may accept additional arguments:\n\n```html\n\u003cscript\u003e\n  microHtmlTemplate.filters.wrap = function(val, start, end) {\n    return start + val + end;\n  };\n\u003c/script\u003e\n```\n\nPass the additional arguments to the filter in the template:\n\n```jinja\n\u003cimg src='https://example.com?q={{query | wrap(\"[\", \"]\")}}'\u003e\n```\n\n## Escaping Macro Delimiters\n\nTo include the macro start delimiter `{{` itself in a template it must be\nescaped by preceeding it with another start delimiter, like this: `{{{{`.\n\n```jinja\n\u003c!-- Start delimiter escaped with '{{{{'. --\u003e\n\u003cdiv\u003e{{{{user.name}} = '{{user.name}}'\u003c/div\u003e\n```\n\n```jinja\n\u003c!-- The rendered template. --\u003e\n\u003cdiv\u003e{{user.name}} = 'Jar Jar B.'\u003c/div\u003e\n```\n\n## Hacking\n\n```bash\n# Install dependencies.\nnpm install\n```\n\n```bash\n# Compile parser, minify runtime, etc.\nmake\n```\n\n```bash\n# Run tests.\nmake test\n```\n\n## License\n\nCopyright © 2017 Adzerk, Inc.\nDistributed under the [Apache License, Version 2.0][apache].\n\n[apache]: https://www.apache.org/licenses/LICENSE-2.0\n[jinja]: http://jinja.pocoo.org/docs/2.10/\n[tests]: test/micro-html-template.tests.coffee\n[owasp-xss]: https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadzerk%2Fmicro-html-template","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fadzerk%2Fmicro-html-template","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadzerk%2Fmicro-html-template/lists"}