Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/jcormont/async-html-template
Simple async/await-able HTML template engine
https://github.com/jcormont/async-html-template
async asynchronous await express expressjs html renderer view-engine
Last synced: 13 days ago
JSON representation
Simple async/await-able HTML template engine
- Host: GitHub
- URL: https://github.com/jcormont/async-html-template
- Owner: jcormont
- License: mit
- Created: 2017-10-20T06:31:54.000Z (about 7 years ago)
- Default Branch: master
- Last Pushed: 2017-11-04T00:33:03.000Z (about 7 years ago)
- Last Synced: 2024-12-08T00:47:30.825Z (about 1 month ago)
- Topics: async, asynchronous, await, express, expressjs, html, renderer, view-engine
- Language: TypeScript
- Size: 22.5 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Async HTML Template Engine
A simple asynchronous (using async/await) HTML template engine, for use with Express or as a standalone HTML generator.
> **Note:** this module is ONLY for use with NodeJS 8+ (for native async/await), and does NOT work in the browser.
## Usage (Express)
Register the view engine as follows:
```javascript
app.engine("html", require("async-html-template").AsyncHtmlViewEngine);
app.set("view engine", "html");
```(or, in TypeScript) --
```typescript
import { AsyncHtmlViewEngine } from "async-html-template";
app.engine("html", AsyncHtmlViewEngine);
app.set("view engine", "html");
```Then, use Express views to render content:
```javascript
app.get("/", (req, res) => {
res.render("index", { title: "Hello, world!" });
})
```## Standalone Usage
You can also use the template engine without Express.
For simple one-off transforms, use the exported `renderAsync` and `renderFileAsync` functions:
* `renderAsync(templateText, context)` returns a Promise for rendered HTML based on given template string and context object.
* `renderFileAsync(fileName, context)` returns a Promise for rendered HTML based on the template in the given file and with the given context object.The exported `Template` class can be used directly as well. It encapsulates an asynchronously compiled function that efficiently generates HTML output for a given context object.
```javascript
// render a template from a file:
let fileTemplate = Template.fromFile("./index.html");
let fileResult = await fileTemplate.renderAsync({ title: "Hello, world!" });// render a template from a string:
let str = `{{ title }}
`;
let strTemplate = new Template(str);
let strResult = await strTemplate.renderAsync({ title: "Hello, world!" });
```## Optimization
Templates that are generated by `renderFileAsync` and `Template.fromFile` (but NOT the partials included by any of these templates) are automatically _cached_, so that files are generally only read and compiled only once.
The resulting HTML is never cached, even for the same context object.
By default, HTML output is minified and comments are removed (using the NPM package `html-minifier`). You can supply minification options to the `renderAsync` method of the `Template` class, _or_ use the exported `defaultHtmlMinifierOptions` object which contains default options.
## Templates
A template is basically just (partial) HTML, with added code that runs while rendering the template.
### Expression Tags
Tags that look like `{{ ... }}` contain JavaScript expressions that are evaluated while rendering. For each tag, the result is HTML-encoded and inserted in place of the tag.
As part of the expression, you can use properties from the context object (passed in through Express `.render`, or any of the `Template` rendering methods), as if they are variables. Alternatively you can use the `context` object explicitly, e.g. if a property is masked by a local variable or if its name is a reserved word.
```html
Hello, {{ firstName }}
Your case number is {{ context.case.getNumber() }}
```Use the `` tag described below if you do not want the result of an expression to be HTML-encoded.
### Template Script Code
Any script code inside of a script tags that contains the `in-template` attribute is not copied to the output, but is run while rendering instead.
You can use properties from the context object in template script code as well.
```html
let result = [];
for (let i = 0; i < firstName.length; i++) {
result.push(firstName.charCodeAt(i));
}Your name in Unicode is {{ JSON.stringify(result) }}
```### Loops
Wrap a part of your template in a `` ... `` tag to add a for-loop around the wrapped area of your template, with exactly the same syntax as in JavaScript.
```html
{{ i }}
{{ property }}: {{ person.attributes[property] }}
var fib = [1, 1, 2, 3, 5, 8, 13, 21];
{{ n }}
{{ n }} ({{ index }})
```For a while-loop, you can use the `` tag.
```html
Fib in reverse is
{{ fib.pop() }}
```### Conditionals
Wrap a part of your template in a `` ... `` tag to check if a condition is true _while rendering_, and skip rendering the wrapped area if not.
```html
Children
Name: {{ child.name }}
```Optionally, you can leave out the braces from the value of the `if` attribute (i.e. `if="expression"`) for exactly the same result.
You can also combine conditionals with loops in the same `` tag.
```html
Child: {{ child.name }}
```### Literal HTML Output
For an expression that returns HTML which should be appended literally (instead of being HTML-encoded), you can use the `` tag.
This tag does _not_ wrap the output in a surrounding tag.
```html
let myHtml = "<b>Hello</b>";
This is HTML-encoded: {{ myHtml }}
This is not:
```### Reusable Templates (Mixin Functions)
Using the `` tag, you can define a named template (sometimes called a 'mixin' function) that can be used multiple times throughout the rest of your template. This does in fact define an (asynchronous) function within the compiled template, which can be passed around and called using its identifier.
To make it easier to call functions defined in this way, you can use the `` tag. If you include any content within this tag, the resulting HTML will be passed to the defined function in a `content` property (also available as `context.content`).
```html
await new Promise(r => setTimeout(r, 1000));
One second later.
```
Alternatively, you can pass in a different context object, using the `context="..."` attribute. The result of the expression is used as the function's context.
```html
Hello, {{ name }}!```
### Partial Includes
You can include (partial) HTML templates from other files using the `` tag. Any given file name is considered to be relative to the current file -- so this only works if the template is loaded from a file in the first place (i.e. not using the `renderAsync(templateText, context)` function, for example).
This tag can also be combined with conditionals or loops, which causes the partial template to be evaluated repeatedly and/or conditionally.
If you need the partial template to be rendered with a different context object, you can provide the `context="..."` attribute. The result of the expression is used as the partial template's context, which can be different for each iteration of a combined loop (if any).
If you do not specify a context expression, a shallow clone of the current context object will be used as the context for the included partial, along with wrapped HTML content (if any) in the `content` property.
```html
```
Note that any _variables_ set in the current template scope (i.e. using `let` or `var`) are not available to the partial template. You **can** set properties of the `context` object, which will also be available to partial templates with the same context:
```html
// add current child to context object
context.child = child;
```
Just like with template functions defined using ``, you can pass contained content along to the partial template. The content will end up in the `content` property of the partial's context. For this reason, the `partial` attribute is also aliased as `wrap`, since it can be used to wrap sections into an outer 'template'.
Any functions defined in your containing code up to the point of the `` tag will also be passed to the partial template (unless you explicity specify another context object). These functions can be used by the partial template using the `` tag.
```html
console.log("foo")
Content
Lorem ipsum.
```
## Asynchronous Code
Because of the asynchronous nature of this template engine, you can actually include `await` expressions in your template code. This is really helpful if your (view) model has `async` features, which can be consumed directly by the template, instead of having to `await` any data that is used inside of your template.
Given a model that looks like this:
```typescript
export class WaitForIt {
static async getSomeDataAsync() {
// do something useful here, like loading data from a server...
await new Promise(res => setTimeout(res, 1000));
return { foo: ["Bar", "Baz", "Quux"] };
}
}
```You can use `await` expressions for this model's results directly in a template:
```html
let data = await WaitForIt.getSomeDataAsync();
{{ name }}
{{ name }}
```