Loading repository data…
Loading repository data…
prasannavl / repository
A super simple, render-agnostic component library for the modern web that emphasizes framework and renderer freedom
A transparent discovery signal based on current public GitHub metadata.
This score does not audit code, security, maintainers, documentation quality, or suitability. Verify the repository and its current documentation before adoption.
A super simple, render-agnostic, ultra light-weight micro-framework for the modern web, that provides Component semantics with the highest possible flexibility, lowest possible cognitive overhead and 100% web standards compliant in under 1KB.
Let's you use the DOM as framework or bring your framework, use the DOM as renderer or bring your renderer, and let them all talk to each other nicely.
Compared to other similar wrappers and/or so called lightweight components, icomponents merely provide a consistent interface, has nothing more than a single allocation of it's own (which is the lightweight Renderer object), and all it does is a few function calls that V8 should optimize out in most cases, and puts you right back into your code.
npm install icomponent
As of v2.0.0, only es6 modules are provided. (See changelog). Written in TypeScript, and as such, definitions are included.
Install the above npm packages directly, if you prefer not to use your own renderer. They generally include the upstream package as well as icomponent as dependencies.
All of the above packages provide an implementation of Component such as LitComponent, ReactComponent, etc. The function of these adapters are simple - icomponent exports Component that has a no-op renderer by default (which can be changed by setting Renderer.render), icomponent-lit adapter provides LitComponent that by default uses the lit-html as the renderer backend. Similarly for the others.
They also usually re-export some handy ones from the upstream packages for convenience. The component specific README should have more information.
Other adaptors like Inferno, CycleJs etc, should be very easy to write, but I haven't got around to doing it yet.
To use directly, in the browser.
<script type="module">
import { Component } from 'https://unpkg.com/icomponent@latest/lib/index.js';
</script>
For implementation specific packages, you need to have the correct packages in scope as well. You're generally better off using npm/yarn or Code Sandbox for live playground.
icomponent has a core goal to stand on it's own, it's flexibility and minimal abstraction makes it ideal to be able to mix and match renderers, and use hyperhtml, lit-html, React, Vue, Mithril, Inferno, CycleJs etc side-by-side, package each of them as individual isolated and standards compliant web components in the same project, without worrying about one affecting the other.render logic, and there are some supported adaptors mentioned above, I'd like to add more, as time permits under the same project for a more seamless experience.lit-html, hyperhtml, jsx, document.createElement, React.createElement or even direct html strings: Your call. (I highly recommend lit-html or hyperhtml). You can even use React, or Vue's renderer if full VDOM is your thing and you'd like to package them up as isolated web-components quickly. Better yet - you can use them all in the same application.queueRender, render, and clearRenderQueue - all of them do what they precisely say. No misnomer or complications like in React where render actually means, return a view. (I'd actually call it a design bug in React. It has nothing to do with rendering. It just builds a view - I'd have called it view).icomponent provides the web component model. So, you can easily do things like these by just writing your own render functions:
jsx without react on native dom? Use nativejsx for views, and use document.appendChild/replaceChild on render. Or use jsx-dom.jsx using innerHTML: Try vhtmlhyperscript and it's vdom with icomponent model? Just return your h from views, and use document.appendChild/replaceChild similar on render, very similar to jsx.While used very rarely, let's start with the raw way to do things. This does come in handy, to write low overhead static components, though I probably would use the append/replaceChild instead below.
import { Component, ComponentRenderer } from "icomponent";
export class Hello extends Component {
createRenderer() {
return new ComponentRenderer(this, () => { this.innerHTML = this.view() });
}
view() {
return "<div>Hello there!</div>"
}
}
customElements.define("my-hello", Hello);
A little nicer, programmatic way instead of innerHTML.
import { Component, ComponentRenderer } from "icomponent";
export class Hello extends Component {
createRenderer() {
return new ComponentRenderer(this, () => this._render());
}
_render() {
let v = this.view();
this.childElementCount > 0 ?
this.replaceChild(v, this.firstElementChild!) :
this.appendChild(v);
}
view() {
let el = document.createElement("div");
el.textContent = "Hello there!";
return el;
}
}
customElements.define("my-hello", Hello);
One could also potentially use a NoopRenderer, to completely bypass the rendering and control everything manually.
Now to something more useful that can be used day-to-day with lit-html or hyper-html.
Using icomponent-lit or icomponent-hyper
// Both these adaptors use the exact same code. Use
// whichever you prefer and comment the other.
import { LitComponent as Component, html } from "icomponent-lit";
// import { HyperComponent as Component, html } from "icomponent-hyper";
class App extends Component {
view() {
return html`
<div>Hello world!</div>
`;
}
}
customElements.define("x-app", App);
// HTML
// <html><x-app></x-app></html>
Note: icomponent-hyper also exports hyper's bind and wire. html is a convenience export to retain similar semantics between hyper and lit-html.
import { ReactComponent } from "icomponent-react";
import React from "react";
class App extends ReactComponent {
// Yup, full goodness of react with jsx!
// While this component is now managed by react, you can
// use any icomponent methods as well like `render`,
// `queueRender`, etc and the whole shebang.
view() {
return <SomeReactComponent>
<div>Hello world!</div>
</SomeReactComponent>;
}
}
customElements.define("x-app", App);
// HTML
// <html><x-app></x-app></html>
import { ReactComponentFn } from "icomponent-react";
import React from "react";
import MySuperCoolReactComponent from "./my-component";
customElements.define("my-component", ReactComponentFn(() => MySuperCoolReactComponent));
// HTML
// <html><my-component></my-component></html>
Yup. That's it. One line, and you get a full icomponent goodness, with the react component. You can also explicitly do this as a class with your view simply returning the react component.
This is the same one, using lit-html, but without any adaptors, overriding the default renderer.
import { Component, Renderer } from "icomponent";
import { html, render } from "lit-html";
// Set the render function. By default it's a noop.
// Set it only once per application, or alternatively,
// override `createRenderer` function and to provide your own render fn.
// render is any function that takes one argument - the original
// component by default.
Renderer.render = (c) => render(c.view(), c.getRenderRoot());
class App extends Component {
view() {
return html`
<div>Hello world!</div>
`;
}
}
customElements.define("x-app", App);
// HTML
// <html><x-app></x-app></html>
Same as the above, but without using any adaptor, or overriding the default renderer. This implementation is also similar to what the adaptors do internally.
import { Component, Renderer } from "icomponent";
import { html, render } from "lit-html";
class LitHtmlComponent extends Component {
// Override this function to change any rendering logic.
// This can use hyperhtml, React, Vue, or any custom logic
// as desired.
createRenderer() {
// The icomponent-lit does the exact same thing conceptually,
// just in a slightly more optimized way.
return new Renderer(this, () => render(this.view(), this.getRenderRoot()));
}
}
class App extends LitHtmlComponent {
view() {
return html`
<my-nav></my-nav>
<div>Hello world!</div>
`;
}
}
class Nav extends LitHtmlComponent {
view() {
return html`
<nav>Oo, my nav!</nav>
`;
}
}
ComponentFn provides functional semantics. Functional com