Easy-Render is a vDOM renderer designed to be as easy to use as possible.
- It's small.
- It requires NO transpilation, everything runs as is in the browser.
- Everything is 100% typed and ready for Typescript!
NPM:
CDN:
<script src="https://cdn.jsdelivr.net/npm/easy-render/cdn/easy-render.js"></script>
<script>
const { render } = easyRender;
</script>
Please ⭐️ this repository!
- Hello World: https://jsfiddle.net/um3Lac8x/1/
- Table generation: https://jsfiddle.net/35vLp9rh/2/
- Updates: https://jsfiddle.net/etp1xz02/9/
- User input: https://jsfiddle.net/wLh9t1rx/3/
- Probabilistic Propagation: https://jsfiddle.net/1vodkugj/13/
- Interpolation animation:
- With html-router: https://jsfiddle.net/cdxm6zy0/7/
- With simply-reactive: https://jsfiddle.net/mx1h2ctd/13/
You can setup easy-render in one of two ways.
The default render method expects a dom element with id 'root' to exsist.
import { render } from 'easy-render';
render`
<h2>Hello World!</h1>
`;
import { Renderer } from 'easy-render';
const { render } = Renderer({
rootElement: document.getElementById('root')
});
render`
<h2>Hello World!</h1>
`;
This library is still very much a work in progress and anything in this readme, ESPECIALLY beyond this point, is to be considered volatile and is likely to not work correctly or at all.
r
should return a brynja builder. This way r
would be implicitly responsible for rendering its own subtree, independant from the entire tree.
type r = (staticSegments: TemplateStringsArray, ...dynamicSegments: DynamicSegments[]) => BrynjaBuilder
This would mean that the following code:
render`
<div>
${[
r`<h1>Hello World</h1>`
]}
</div>
`;
...would result in the following brynja builder:
const _0 = _=>_
.child('h1', _=>_
.text('Hello World')
)
render(_=>_
.child('div', _=>_
.do(_0)
)
);
This whould also mean that easy-render
would support full interop with brynja
:
import { render } from 'easy-render';
import { createComponent } from 'brynja';
const HelloWorld = createComponent(() => _=>_
.child('h1', _=>_
.text('Hello World')
)
);
render`
<div>
${[
HelloWorld()
]}
</div>
`;
...and vice versa... interestingly:
import { r } from 'easy-render';
import { render } from 'brynja';
const HelloWorld = () => r`
<h1>Hello World</h1>
`;
render(_=>_
.child('div', _=>_
.do(HelloWorld())
)
);
Internallay r
would make up the majority of the logic in the render
function (mock implementation):
export function Renderer(config: { rootElement: HTMLElement, rootElementBuilder?: BuilderCB }): IRenderer {
const brynja = BrynjaRenderer({
rootElement: config.rootElement,
});
return {
render: (staticSegments, ...dynamicSegments) => {
const brynjaBuilder = r(staticSegments, ...dynamicSegments);
// Render using brynja
brynja.render(_=>_
.do(config.rootElementBuilder ?? (_=> {
// Echo props from root node if no custom rootElementBuilder was provided
_.while(i => i < config.rootElement.attributes.length, (_, i)=> {
const attribute = config.rootElement.attributes.item(i);
if (attribute === null) { return; }
_.prop(attribute.name, attribute.value);
})
}))
.do(brynjaBuilder)
);
}
}
}
Mock implementation of r
:
const r = (staticSegments: TemplateStringsArray, ...dynamicSegments: DynamicSegments[]): BrynjaBuilder => {
const { xml, dynamics } = processTagFunctionData({
static: staticSegments,
dynamic: dynamicSegments,
});
const DOM = parseXML(xml);
const builder = constructBrynjaBuilder({ DOM, dynamics });
return builder;
}
import { render } from 'easy-render';
render`
<div class="box">
<button
click=${e => console.log(e)}
style=${{
background: 'orangered',
':hover': {
background: 'skyblue',
}
}}
>Click me</button>
</div>
`;
Data in ${}
may either be a CSS object, an event handler function, a string, a number, or a list of strings or numbers
- Intermediate structure, to preserve clojures for functions, to reduce amount of parcing for style object, and to allow for caching the parsed XML result unless the string structure changes.
<div class="box">
<button
click="placeholder-function-0"
style="placeholder-object-0"
>Click me</button>
</div>
-
Check if intermediate structure is the same as the cached structure.
-
If cache miss: I) Pass the intermediate structure into an xml parser. II) Create a Brynja builder for the resulting XML elements.
-
Call the stored Brynja builder, passing in any placeholder values as arguments.
Same as the following:
import { render } from 'brynja';
const builder = (args) =>
render(_=>_
.child('div', _=>_
.class('box')
.child('button', _=>_
.on('click', args.function[0])
.style(args.object[0])
.text('Click me')
)
)
);
builder({
function: [
e => console.log(e),
],
object: [
{background: 'orangered', ':hover':{background: 'skyblue'}},
],
});