Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/tmorin/idomizer

An HTML template parser compiling an incremental-dom render factory.
https://github.com/tmorin/idomizer

babel-plugin browserify incremental-dom loader template webpack

Last synced: 3 months ago
JSON representation

An HTML template parser compiling an incremental-dom render factory.

Awesome Lists containing this project

README

        

# idomizer

[![Continous Integration](https://github.com/tmorin/idomizer/actions/workflows/continous-integration.yaml/badge.svg)](https://github.com/tmorin/idomizer/actions/workflows/continous-integration.yaml)

`idomizer` is an HTML template compiler providing an [incremental-dom] render factory.
`idomizer` can be used at compile time (front end projects) or runtime time(back end projects).

Versions and compatibilities:

- idomizer <= 0.5 -> _incremental-dom_ 0.4 and below.
- idomizer >= 0.6 -> _incremental-dom_ 0.5 and above.
- idomizer >= 1.0.0 -> _incremental-dom_ 0.6 and above.

## Installation

```bash
$ npm install idomizer
```

```html

var factory = idomizer.compile('<h1>Hello!</h1>');
var render = factory(IncrementalDOM);
IncrementalDOM.patch(document.body, render);

```

### Babel

A babel's plugin is available to compile an idomizer template into an [incremental-dom] render factory.

See the [babel's plugins](https://babeljs.io/docs/en/plugins#syntax-plugins) page to get more information about plugins in babel.

```javascript
{
plugins: ['idomizer/lib/plugins/babel-idomizer.js']
}
```

Presently the plugin only support [ES6 Template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) tagged with _idomizer_.

For instance,
```javascript
const template = idomizer`

Hello

`;
```
will be compiled into:
```javascript
var template = function (_i, _h) {
var _elementOpen = _i.elementOpen,
_elementClose = _i.elementClose,
_elementVoid = _i.elementVoid,
_text = _i.text,
_skip = _i.skip;
return function (_data_) {
var helpers = _h || {},
data = _data_ || {};
_elementOpen('h1', null, null, 'class', data.h1Class);
_text('Hello');
_elementClose('h1');
};
};
```

Be aware the template can not contain expressions like ``${anExpression}``.

### Webpack

A webpack's loader is available to compile an idomizer file into an [incremental-dom] render factory.

See [module.rules](https://webpack.js.org/configuration/module/#module-rules) to get more information about loaders in webpack.

```
module.loaders: [
{test: /\.idomizer$/, loader: 'idomizer/lib/plugins/idomizer-loader'}
];
```

### Browserify

A browserify's transform module is available to compile an idomizer file into an [incremental-dom] render factory.

See [transforms](https://github.com/substack/browserify-handbook#transforms) to get more information about the transform system in browserify.

```shell
browserify -t idomizer/lib/plugins/idomizerify main.js > bundle.js
```

```javascript
const browserify = require('browserify');
const idomizerify = require('idomizer/lib/plugins/idomizerify');
const bundle = browserify();
bundle.transform({ extension: 'html' }, idomizerify);
```

## API

``idomizer.compile`` transforms an HTML template into a factory method.

```javascript
// idomizer.compile('

Hello

') will return:
function template(_i, _h) {
var _elementOpen = _i.elementOpen,
_elementClose = _i.elementClose,
_elementVoid = _i.elementVoid,
_text = _i.text,
_skip = _i.skip;
return function (_data_) {
var helpers = _h || {},
data = _data_ || {};
_elementOpen('h1', null, ['class', 'main'], null);
_text('Hello');
_elementClose('h1');
};
}
```

The factory method requires the _incremental-dom_ library and an optional map of helpers.
The factory returns the _incremental-dom_'s render method.

## Syntax

### Static attributes

From
```javascript
idomizer.compile(`

Hello

`)(IncrementalDOM);
```
To
```javascript
function template(_i, _h) {
var _elementOpen = _i.elementOpen,
_elementClose = _i.elementClose,
_elementVoid = _i.elementVoid,
_text = _i.text,
_skip = _i.skip;
return function (_data_) {
var helpers = _h || {},
data = _data_ || {};
_elementOpen('h1', null, ['class', 'main'], null);
_text('Hello');
_elementClose('h1');
};
}
```

### Dynamic attributes

From
```javascript
idomizer.compile(`

Hello

`)(IncrementalDOM)
```
To
```javascript
function template(_i, _h) {
var _elementOpen = _i.elementOpen,
_elementClose = _i.elementClose,
_elementVoid = _i.elementVoid,
_text = _i.text,
_skip = _i.skip;
return function (_data_) {
var helpers = _h || {},
data = _data_ || {};
_elementOpen('h1', null, null, 'class', (data.h1Class));
_text('Hello');
_elementClose('h1');
};
}
```

### Self closing elements

From
```javascript
idomizer.compile(``)(IncrementalDOM)
```
To
```javascript
function template(_i, _h) {
var _elementOpen = _i.elementOpen,
_elementClose = _i.elementClose,
_elementVoid = _i.elementVoid,
_text = _i.text,
_skip = _i.skip;
return function (_data_) {
var helpers = _h || {},
data = _data_ || {};
_elementVoid('input', null, ['type', 'text'], 'value', (data.value));
};
}
```

### Dynamic text nodes

From
```javascript
idomizer.compile(``)(IncrementalDOM)
// or
idomizer.compile(`{{ data.value }}`)(IncrementalDOM)
```
To
```javascript
function template(_i, _h) {
var _elementOpen = _i.elementOpen,
_elementClose = _i.elementClose,
_elementVoid = _i.elementVoid,
_text = _i.text,
_skip = _i.skip;
return function (_data_) {
var helpers = _h || {},
data = _data_ || {};
_elementOpen('strong', null, null, null);
_text(data.value);
_elementClose('strong');
};
}
```

### Condition with the tags _if_, _else-if_ and _else_

From
```javascript
idomizer.compile(`

YES!

MAY BE!

NO!

`)(IncrementalDOM);
```
To
```javascript
function template(_i, _h) {
var _elementOpen = _i.elementOpen,
_elementClose = _i.elementClose,
_elementVoid = _i.elementVoid,
_text = _i.text,
_skip = _i.skip;
return function (_data_) {
var helpers = _h || {},
data = _data_ || {};
if (data.yes) {
_text('YES!');
} else if (data.yes !== false) {
_text('MAY BE!');
} else {
_text('NO!');
}
};
}
```

### Iteration with the tag _each_

From
```javascript
idomizer.compile(`


-


`)(IncrementalDOM);
```
To
```javascript
function template(_i, _h) {
var _elementOpen = _i.elementOpen,
_elementClose = _i.elementClose,
_elementVoid = _i.elementVoid,
_text = _i.text,
_skip = _i.skip;
return function (_data_) {
var helpers = _h || {},
data = _data_ || {};
(data.items || []).forEach(function (item, index) {
_elementOpen('strong', (index), null, null);
_text(index);
_text('-');
_text(item);
_elementClose('strong');
});
};
}
```

### Iteration with inline javascript

From
```javascript
idomizer.compile(`
[[ data.items.forEach(function (item, i) { ]]

-

[[ }); ]]
`)(IncrementalDOM);
```
To
```javascript
function template(_i, _h) {
var _elementOpen = _i.elementOpen,
_elementClose = _i.elementClose,
_elementVoid = _i.elementVoid,
_text = _i.text,
_skip = _i.skip;
return function (_data_) {
var helpers = _h || {},
data = _data_ || {};
data.items.forEach(function (item, i) {
_elementOpen('strong', (i), null, null);
_text(i);
_text('-');
_text(item);
_elementClose('strong');
});
};
}
```

### Custom tags

From
```javascript
idomizer.compile(`strong textstrong text`, {
tags: {
'x-test': {
onopentag(name, attrs, key, statics, varArgs, options) {
return `t('${name} element');`;
}
}
}
})(IncrementalDOM);
```
To
```javascript
function template(_i, _h) {
var _elementOpen = _i.elementOpen,
_elementClose = _i.elementClose,
_elementVoid = _i.elementVoid,
_text = _i.text,
_skip = _i.skip;
return function (_data_) {
var helpers = _h || {},
data = _data_ || {};
_elementOpen('strong', null, null, null);
_text('strong text');
_elementClose('strong');
_text('x-test element');
_elementOpen('strong', null, null, null);
_text('strong text');
_elementClose('strong');
};
}
```

### Custom helpers

From
```javascript
const subRender = compile(`helper content`)(IncrementalDOM);
idomizer.compile(`
strong text

strong text
`)(IncrementalDOM, {subRender});
```
To
```javascript
function template(_i, _h) {
var _elementOpen = _i.elementOpen,
_elementClose = _i.elementClose,
_elementVoid = _i.elementVoid,
_text = _i.text,
_skip = _i.skip;
return function (_data_) {
var helpers = _h || {},
data = _data_ || {};
_elementOpen('strong', null, null, null);
_text('strong text');
_elementClose('strong');
helpers.subRender(data);
_elementOpen('strong', null, null, null);
_text('strong text');
_elementClose('strong');
};
}
```

### Custom elements

For [incremental-dom], custom elements are regular HTML elements.
So, if a custom element generates a sub-tree (i.e. a light DOM) outside of a ShadowDOM node,
it will be overridden during the execution of the function `patch()`.
To control this default behavior, [incremental-dom] provides the function `skip()` saying:
_don't touch the inner light DOM of the just opened node!_

By default, idomizier detects the custom elements and force the call of the function `skip()` to protect their light DOM nodes.
Custom elements are detected according to the following rules:

- from the name, because of the `-` character
- from the attribute `ìs`

Obviously, this behavior can be deactivated:

- globally (for a whole HTML template)
```javascript
const render = compile(`

will part of the light DOM

`, {skipCustomElements : false})
```
- locally (an HTML element), ``
```javascript
const render = compile(`

will part of the light DOM

`)
```

[incremental-dom]: https://google.github.io/incremental-dom