Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
Mikado is the webs fastest template engine for building user interfaces. Carefully crafted to get the most out of the browser. Also providing the fastest Express Render Engine of today. Super-lightweight, outstanding performance, no dependencies.
> All debug versions are providing debug information through the console and gives you helpful advices on certain situations.
### Bundles
> Bundles export all their features as static functions to the public class namespace "Mikado" e.g. `Mikado.register()`.
The abbreviations used at the end of the filenames indicates:
- `bundle` All features included, Mikado is available on `window.Mikado`
- `light` Only basic features are included, Mikado is available on `window.Mikado`
- `es5` bundle has support for EcmaScript5, Mikado is available on `window.Mikado`
- `module` bundle is a Javascript module, Mikado is available by `import Mikado from "./mikado.bundle.module.min.js"`
- `min` bundle is minified
- `debug` bundle has enabled debug mode (only for development purposes, do not use for production)
### Module
When using modules you can choose from 2 variants: `mikado.xxx.module.min.js` has all features bundled on the public class namespace e.g. `Mikado.register()`, whereas the folder `/dist/module/` export most of the features as functions which needs to be imported explicitly by `import { register } from "./dist/module/mikado.js"`.
Also, for each variant there exist:
1. A debug version for the development
2. A pre-compiled minified version for production
### Browser
Load the bundle by a script tag:
```html
```
### NPM
Install Mikado via NPM:
```npm
npm install mikado
```
The **_dist_** folder are located in `node_modules/mikado/dist/`.
### Javascript Modules
Use the bundled version exported as a module:
```html
```
Also, pre-compiled non-bundled production-ready modules are located in `dist/module-min/`.
```html
```
You can also load modules via CDN:
```html
```
> Loading modules via CDN commonly expects to build/bundle your app properly before distribution. Do not load them via CDN in production.
### Feature Comparison "Bundle vs. Light"
The destination root element on where the template should be rendered.
null
template
You will need to assign a template to the Mikado instance (or the name of the template when already registered/loaded).
async
Perform the .render(data) task asynchronously and return a Promise.
false
cache
Enable/disable DOM state caching which can greatly increase performance by a factor up to 25. When enabled make sure to use the DOM Cache Helpers when manipulating the DOM directly on properties which are also covered by template expressions.
false
observe
When using Mikado.Array() for reactive approach you will need to pass this array instance to this property.
null
recycle
When enabled all dom elements which are already rendered will be re-used (recycled) for the next render task. This performs better, but it may produce issues when manual dom manipulations was made which are not fully covered by the template. Alternatively use the keyed strategy, which limits recycling of components by matching the same data key (e.g. ID).
false
state
Pass an extern object which should be referenced as the state used within template expressions.
{ }
pool
Pooling can greatly enhance both the keyed and non-keyed recycle strategy.
false
hydrate
Progressively enables hydration of already existing DOM structures when mounted. Make sure the existing DOM structure is based on the same template. When something differs from the given template schema, the hydration will stop and silently falls back into the default build strategy.
false
## Getting Started (Basic Example)
The Mikado Compiler requires Node.js to be installed. This is probably the simplest step in this guide.
Install Mikado from NPM (this will also install the compiler):
```npm
npm install mikado
```
Assume there is an array of data items to render (or just one item as an object):
```js
const data = [{
username: "User A",
tweets: ["foo", "bar", "foobar"]
},{
username: "User B",
tweets: ["foo", "bar", "foobar"]
},{
username: "User C",
tweets: ["foo", "bar", "foobar"]
}];
```
Accordingly, a template **_tpl/partial/user.html_** might look like:
```html
User:
{{ data.username }}
Tweets:
{{ data.tweets.length }}
```
### Compile the template:
In your console type this command line:
```cmd
npx mikado-compile ./tpl/
```
### Load library and initialize template as ES6 modules:
```html
```
### Load library and initialize template as legacy ES5:
```html
```
> The name of a template inherits from its corresponding filename starting by the folder you've passed through the `--src` flag when calling the compiler.
After creation, you need mount the Mikado view instance to an HTML element as a destination for your render tasks:
```js
view.mount(HTMLelement);
view.render(data);
```
You can also chain methods:
```js
Mikado(template).mount(HTMLelement).render(data);
```
## Rules and Conventions
There is just a single convention you always need to keep in mind:
> **Every template has to provide one single root element as the outer boundary.**
Instead of doing this in a template:
```html
```
Wrapping everything into a single outer root element by doing this:
```html
```
You can also use a `
` or any other element as a template root (also custom elements). The root element can also hold two special attributes `key` and `cache`. We will come later to it.
## Advanced Example
A bit more complex template:
```html
{{@ var is_today = data.date === state.today }}
{{ data.title.toUpperCase() }}
{{# data.content }}
```
You can use any Javascript within the {{ ... }} curly bracket notation. The scope is limited by the template, so variables from one template can't be accessed within another template (use `state` for this purpose).
> To pass HTML markup as a string, the curly brackets needs to be followed by **#** e.g. `{{# ... }}`. For better performance, relevant tasks avoid passing HTML contents as a string.
> To use Javascript outside an element's context you need to prevent concatenation of the returned value. For this purpose, the curly brackets need to be followed by **@** e.g. `{{@ ... }}`.
Within a template there are several **reserved keywords** you can use as an identifier:
Identifier
Description
data
A full reference to the passed data item. Within loops the keyword data points to each of the looped data items.
state
An optional payload used to manually pass in custom specific values or helper functions. The state will be delegated through all nested templates.
index
Represents the index of the currently rendered data item (starting by 0 for the first item).
this
Provides you access to the Mikado view instance (e.g. this.state).
window
Gives access to the global namespace.
_p _v _x _o _f _inc
private identifiers, used by internal processing
You cannot change the names of those preserved keywords, also make sure you didn't override them.
It is recommended to pass custom functions via the _state_ object (see example above `state.parseFooter = function(str){ return str; }`). Alternatively you can also nest more complex computations inline as an IIFE and return the result.
```html
{{
(function(){
var date = new Date();
// perform some code ...
return date.toLocaleString();
}())
}}
```
To finish the example from above you need one single data object or an array of **_data_** items:
```js
var data = [{
"id": "230BA161-675A-2288-3B15-C343DB3A1DFC",
"date": "2019-01-11",
"class": "yellow, green",
"title": "Sed congue, egestas lacinia.",
"content": "
Vivamus non lorem vitae odio sagittis amet ante.
",
"footer": "Pellentesque tincidunt tempus vehicula."
}];
```
Provide the optional **_state_** payload which includes specific values and helper methods used within template expressions:
```js
const state = {
today: "2019-01-11",
theme: "custom",
parseFooter: function(data) {
return data.footer;
}
};
```
Mount the view to a target element as a destination for all the render tasks:
```js
view.mount(HTMLelement);
```
Render a mounted template:
```js
view.render(data, state);
```
Render asynchronously automatically by just providing a callback function:
```js
view.render(data, state, function() {
console.log("finished.");
});
```
To render asynchronously by using promises you need to set the callback value to `true`:
```js
// callback "true" will use Promises
view.render(data, state, true).then(function() {
console.log("finished.");
});
// same, but uses async/await:
await view.render(data, state, true);
console.log("finished.");
```
When async should be the default strategy for all render tasks then you can also set the **_async_** option flag:
```js
const view = new Mikado(template, { async: true });
await view.render(data, state);
console.log("finished.");
```
## Compile Templates
Define an HTML-like template and use double curly brackets to markup dynamic expressions which should be calculated and replaced during runtime:
```html
User:
{{ data.username }}
Tweets:
{{ data.tweets.length }}
```
Save this template e.g. to _tpl/partial/user.html_
> The preserved keyword **_data_** is a reference to the passed data item. You can access the whole nested object.
Mikado comes with a builtin template compiler you can simply access by typing `npx mikado-compile` into your console. The compiler uses a very simple command-line interface (CLI) running on Node.js to perform compilation tasks. The template compiles into a native javascript file which needs to be passed during creation of a Mikado instance. The same markup is also used for the server-side rendering part, so you can share the same template sources for client and server rendering.
Show help to list all available commands:
```cmd
npx mikado-compile --help
```
Compile the template through the command line by:
```cmd
npx mikado-compile tpl/partial/user.html
```
**Basic Notation:**
> npx mikado-compile _source \_
When no destination folder was set, the compiled files will be saved to the source folder. After compilation, you will have 3 different files:
1. **list.js** the template compiled as a ES6 module (which needs to be imported)
2. **list.es5.js** the template compiled as ES5 compatible Javascript (which automatically register when loaded by script tag)
3. **list.html** the source template you have implemented (do not delete it)
**Extended Notation:**
> npx mikado-compile --src _{ source }_ --dest _{ destination }_ --extension html --type module --compact
Compiler Flags:
- `--type module`, `-t module` export as javascript modules (recommended)
- `--type es5`, `-t es5` export as ES5-compatible package
- `--extension html`, `--ext html`, `-e html` the file extension which should be compiled
- `--inline`, `-i` or `--compact`, `-c` switch the build strategy to optimize either the performance (inline) or size (compact)
- `--force`, `-f` force overwriting existing files
- `--pretty`, `-p` do not minify the compiled result
- `--watch`, `-w` start the watcher for automatically compile when files has changed (just for development purposes)
Supported flags as attributes on the template root:
```html
```
```html
```
Using the flag attributes are the most performant variants but also cost you some flexibility, because the cache strategy couldn't be changed in runtime, it needs to change in markup before compilation.
### Auto Naming
There is a new naming system which will apply by default. The name of your html files will be used as unique identifiers of your templates.
Because several folders can include same filenames, the template name inherits from the full path you pass in as `--src`.
Assuming the following file structure:
```
tpl/view/start.html
tpl/view/user.html
tpl/view/cart.html
tpl/partial/start.html
tpl/partial/user.html
tpl/partial/cart.html
```
The command should define the path `/tpl/` as the source root because it is the most inner folder which covers all files:
```cmd
npx mikado-compile ./tpl/
```
The template names then becomes `view/start`, `view/user`, `view/cart` and `partial/start`, `partial/user`, `partial/cart` for the partials. So when including just use this name in your expression `
`
The wrong way is to compile the folder /view/ and /partial/ separately, because their template names will be same.
```cmd
npx mikado-compile ./tpl/view/
npx mikado-compile ./tpl/partial/
```
This might also work, but it is better not to do.
### Prebuilt Cache Strategy
The option `{ cache: true/false }` when creating a Mikado instance could be better declared withing templates on their root element, let the compiler produce more optimized code for this strategy.
```html
```
Also use this approach when set `cache="false"`:
```html
```
### Watcher (Auto-Compile)
A perfect fit for your local development environment is spawning a watcher to automatically compile files when they get changed. Just use the same command line you would also use for a full compilation and append the flag `--watch` or `-w` to it:
```cmd
npx mikado-compile ./tpl/ --watch
```
Don't close the console, otherwise the watcher will stop. You can stop the watcher explicitly by pressing `CTRL + C`.
## Template Expressions
> The template notation expects double curly brackets `{{ ... }}` for any kind of dynamic expressions.
> Except when using {{@ ... }} for inline code notation, the returned value of every dynamic expression will be replaced to its position.
### Value Insertion `{{ ... }}`
```html
{{ data.value }}
```
```js
view.render({ value: "test" });
```
You can also combine multiple expressions with non-expression contents:
```html
The title "{{ data.title }}" has the value: {{ data.value }}
```
```js
view.render({ title: "title", value: "test" });
```
You can also mix text nodes with elements on the same root element:
```html
Title: {{ data.title }} Value: {{ data.value }}
```
```js
view.render({ title: "title", value: "test" });
```
Also, you can use expressions within every attribute:
```html
{{ data.value }}
```
```js
view.render({ id: 1, value: "test", class: "test" });
```
Every Javascript syntax is allowed withing expression:
```html
```
```js
view.render({ active: true, value: "not empty" });
```
Since expressions just need to return a value you can also use IIFE:
```html
{{
(function(){
var date = new Date();
// perform some code ...
return date.toLocaleString();
}())
}}
```
```js
view.render();
```
### JS Inline Code `{{@ ... }}`
The inline code expression is the only one which doesn't return a value to be rendered in place, it just executes.
```html
{{@ const value = data.title.toUpperCase(); }}
{{ value }}
```
```js
view.render({ title: "title" });
```
The scope is limited to the template scope, but you can assign to `state` alternatively to share values across nested instances:
```html
{{@ state.value = data.title.toUpperCase(); }}
```
```js
view.render({ title: "title" });
```
### Truthy Values `{{? ... }}`
This will just output the result when it is not `null`, `undefined`, `NaN` or `false`.
```html
{{? data.value }}
```
```js
view.render([{
value: null
},{
value: NaN
},{
value: undefined
},{
value: false
}]);
```
### Escape Values `{{! ... }}` (SSR only)
This will escape the value before return. This is just important for the server-side-rendering part, the client automatically escape contents by default (except when using the HTML-expression).
```html
{{! data.value }}
```
```js
view.render({ value: "html is not allowed" });
```
### HTML Contents `{{# ... }}`
This will allow for inserting HTML returned string.
> Be aware of this can potentially lead into security issues like XSS. Use carefully!
```html
{{# data.value }}
```
```js
view.render({ value: "html is allowed" });
```
#### Sanitizer
Mikado provides you high performant helper function you can use in this context to escape contents or to sanitize.
```js
view.render({
value: "html allowed " + Mikado.escape("not allowed")
});
```
```js
view.render({
value: "html allowed " + Mikado.sanitize("not allowed")
});
```
Using the sanitizer will remove the tags completely, whereas when escaping the content aren't removed but just escaped.
### Reactive Bindings `{{= ... }}`
Define properties by using pure data object notation without any javascript inside:
```html
{{= data.value }}
```
```js
// store must be an array of elements:
const store = [{ class: "active", value: "foo" }];
// it needs a initial render if store isn't empty:
view.render(store);
// the store array now was proxified!
```
Now you can change the properties of `store` and the corresponding DOM elements will change automatically:
```js
store[0].class = "inactive";
store[0].value = "bar";
```
## Runtime Compiler
Alternatively of using the `npx mikado-compile` you can also compile templates during runtime.
> If a page has set a `Content-Security-Policy` (CSP) header field, using the runtime compiler has disadvantage when not configure `script-src 'unsafe-eval'`. It is recommended to use the Mikado native compiler, which is CSP-friendly and also can optimize your templates more powerful.
The runtime compiler uses the performance optimized `inline` strategy for every task, you can't switch it. The compiler property flag `cache="true"` or `cache="false"` on a template root is not supported, therefore you can't use 2 of the most performant strategies. But they are just slightly faster, so this shouldn't be an issue.
Those features aren't supported by the runtime compiler:
- `cache="true"` or `cache="false"` on a template root
- using any other compiler strategy than `inline`
- detect and replace repeating inline includes
- detect and solve/unroll non-dynamic expressions, e.g. ``
{{ "foor" + "bar " }}
`` will transform to a static content `
foobar
` and removes the expression completely
- runtime-ready templates aren't available on page load (they need to compile)
- the runtime compiler does not pass the "crazy template" test
#### Examples
Define some HTML template structure:
```html
User:
{{ data.user }}
Tweets:
{{ data.tweets.length }}
```
> Template definitions used by the runtime compiler needs manual naming when used as named includes.
The template name will derive from `` or `` and becomes `user-list`.
When using named includes you will need to use this name for referencing, e.g. `
"`.
Compile the template and use it for creating a Mikado view instance:
```js
const template = document.getElementById("user-list");
const tpl = Mikado.compile(template);
const view = new Mikado(tpl, { /* options */ });
view.render(data);
```
When the template was get through element ID you can use a shortcut:
```js
const tpl = Mikado.compile("user-list");
```
Also, you can compile the template and use it for registration as a named include referenced by another template e.g. `
"`:
```js
Mikado.register(Mikado.compile("user-list"));
```
You can use non-template elements for defining templates also:
```css
#user-list{ display: none }
```
```html
User:
{{ data.user }}
Tweets:
{{ data.tweets.length }}
```
Last but not least you can pass the template markup as a string:
```js
const tpl_str = `
User:
{{ data.user }}
Tweets:
{{ data.tweets.length }}
`;
const tpl = Mikado.compile(tpl_str);
const view = new Mikado(tpl, { /* options */ });
view.render(data);
```
### Using Inline Code
The runtime compiler does not support all places of inserting inline code expressions. In some situations it might produce issues like here:
```html
{{@
/* the browser will move this before
! */
const value = "test";
}}
Value: {{ value }}
```
The runtime compiler didn't parse the template by string, instead the compiler creates a dom structure when passing a template as string.
On the example above the `{{@ ... }}` expression is treated as a text node by the browser.
Since the position isn't allowed to place text nodes (after `
`, ``, `
`) the browser moves this text node up to the outer scope of the table. But the inline code is now executed within the first outer template function, instead the inline loop template function needs the value and is running in its own scope.
In this situation you can store values on `state` to pass through inline looped partials.
Or you can use the `
Value: {{ value }}
```
> Don't forget to use the expression notation, otherwise it will be inserted as a normal code element.
> When the `
User:
{{ window.username }}
Tweets:
{{ data.tweets.length }}
```
> You can't use any template expressions outside ``.
You can also render any normal template (non-components) to a plain dedicated shadow root by using the `shadow: true` option (also supported by the light bundle):
```js
const view = new Mikado(tpl, { shadow: true });
```
Theoretically you can put the ``, `` and `` inside a normal non-component template by also using the `shadow: true` option.
But there is one important difference. Within a normal template those tags could be re-rendered and this might end in re-initializing of all those assets.
Within a web component there is a top level scope, which is created once and will stay for all your further template tasks.
The template will render on a new "hidden" element `` which is part of the top level scope.
That is because the view needs to be mounted to an element, and the top level scope of shadow root couldn't be mounted because of mixed content.
Don't rely on the existence of ``, when using static templates or `view.once()` it might not exist.
Assume when mounted a web component template to an element ``, the DOM structure looks like:
```
#shadow-root
#template
#template
#template
...
```
## Full Template Example
Use this almost complete template example to check if you know everything about the template mechanism:
```html
Index
Title
Media
Category
Comment
Date
{{ index + 1 }}
{{= data.title }}
{{# data.media }}
{{? data.category }}
{{! data.comment }}
{{ datestr }}
No entries found.
```
A proper definition and call for this template could look like this:
```js
// the named include "pager" needs to be registered before use
Mikado.register(tpl_pager);
// define route "select-active"
view.route("select-active", function(target, event){
const id = Number(target.dataset.id);
view.state.selected = id;
});
view.render({
view: "video",
entries: [{
id: 1,
date: "2023-12-01T14:00:00",
title: "A simple title 1",
media: "",
category: null,
comment: "Some content",
mode: "off"
},{
id: 2,
date: "2023-12-02T15:00:00",
title: "A simple title 2",
media: "