Сравните стиль кодирования, размер пакета и производительность 33 различных способов создания веб-компонента.
То же
Web Компонент был написан в 33 вариантах.
HTMLElement
Домашняя страница: https://html.spec.whatwg.org/multipage/custom-elements.html
Попробуйте в WebComponents.dev
класс MyCounter расширяет HTMLElement {
constructor () {
супер();
this.count = 0;
const style = `
* {
размер шрифта: 200%;
}
span {
ширина: 4бэр;
дисплей: встроенный блок;
выравнивание текста: центр;
}
button {
ширина: 64 пикселя;
высота: 64 пикселя;
граница: нет;
радиус границы: 10 пикселей;
цвет фона: морской;
цвет белый;
}
`;
const html = `
$ {this.count}
`;
this.attachShadow ({режим: 'открытый'});
this.shadowRoot.innerHTML = `
$ {html}
`;
this.buttonInc = this.shadowRoot.getElementById ('inc');
this.buttonDec = this.shadowRoot.getElementById ('dec');
this.spanValue = this.shadowRoot.querySelector ('диапазон');
this.inc = this.inc.bind (это);
this.dec = this.dec.bind (это);
}
inc () {
this.count ++;
this.update ();
}
dec () {
this.count--;
this.update ();
}
Обновить() {
this.spanValue.innerText = this.count;
}
connectedCallback () {
this.buttonInc.addEventListener («щелкните», this.inc);
this.buttonDec.addEventListener («щелкните», this.dec);
}
disconnectedCallback () {
this.buttonInc.removeEventListener («щелкните», this.inc);
this.buttonDec.removeEventListener («щелкните», this.dec);
}
}
customElements.define ('мой-счетчик', MyCounter);
HTMLElement (w / Lighterhtml)
Сила и опыт hyperHTML без его сложности
Домашняя страница: https://medium.com/@WebReflection/lit-html-vs-hyperhtml-vs-lighterhtml-c084abfe1285[19459002provided
GitHub: https://github.com/WebReflection/ lighterhtml
Попробуйте в WebComponents.dev
импортировать {html, render} из lighterhtml;
class MyCounter расширяет HTMLElement {
constructor () {
супер();
this.count = 0;
this.attachShadow ({режим: 'открытый'});
this.update ();
}
inc = () => {
this.count ++;
this.update ();
};
dec = () => {
this.count--;
this.update ();
};
стиль() {
return `
* {
размер шрифта: 200%;
}
span {
ширина: 4бэр;
дисплей: встроенный блок;
выравнивание текста: центр;
}
button {
ширина: 64 пикселя;
высота: 64 пикселя;
граница: нет;
радиус границы: 10 пикселей;
цвет фона: морской;
цвет белый;
}
`;
}
template () {
return html`
$ {this.count}
`;
}
Обновить() {
render (this.shadowRoot, this.template ());
}
}
customElements.define ('мой-счетчик', MyCounter);
HTMLElement (w / Lit-html)
Lit-Html — Эффективная, выразительная, расширяемая библиотека шаблонов HTML для JavaScript
Домашняя страница: https://lit-html.polymer-project.org/
GitHub: https://github.com/polymer / lit-html
Попробуйте в WebComponents.dev
импортировать {html, render} из 'lit-html';
class MyCounter расширяет HTMLElement {
constructor () {
супер();
this.count = 0;
this.attachShadow ({режим: 'открытый'});
this.update ();
}
inc () {
this.count ++;
this.update ();
}
dec () {
this.count--;
this.update ();
}
стиль() {
return `
* {
размер шрифта: 200%;
}
span {
ширина: 4бэр;
дисплей: встроенный блок;
выравнивание текста: центр;
}
button {
ширина: 64 пикселя;
высота: 64 пикселя;
граница: нет;
радиус границы: 10 пикселей;
цвет фона: морской;
цвет белый;
}
`;
}
template () {
return html`
$ {this.count}
`;
}
Обновить() {
render (this.template (), this.shadowRoot, {eventContext: this});
}
}
customElements.define ('мой-счетчик', MyCounter);
HTMLElement (w / uhtml)
micro html — это файл на ~ 2.5K легчеhtml подмножество для создания декларативного и реактивного пользовательского интерфейса с помощью тегов шаблонных литералов.
Домашняя страница: https://github.com/WebReflection/uhtml
GitHub: https://github.com/WebReflection/uhtml
Попробуйте в WebComponents.dev
импортировать {html, render} из "uhtml";
class MyCounter расширяет HTMLElement {
constructor () {
супер();
this.count = 0;
this.attachShadow ({режим: "открытый"});
this.update ();
}
inc = () => {
this.count ++;
this.update ();
};
dec = () => {
this.count--;
this.update ();
};
template () {
return html`
$ {this.count}
`;
}
Обновить() {
render (this.shadowRoot, this.template ());
}
}
customElements.define ("мой счетчик", MyCounter);
CanJS
Создавайте приложения CRUD в меньшем количестве строк кода.
Домашняя страница: https://canjs.com/[19459002impression
GitHub: https://github.com/canjs/canjs
Попробуйте в WebComponents.dev
импорт {StacheElement} из "банка";
// Расширяем компонент для определения настраиваемого элемента
class MyCounter расширяет StacheElement {
constructor () {
супер();
this.viewRoot = this.attachShadow ({режим: "открытый"});
}
статический вид = `
{{this.count}}
`;
static props = {
количество: 0
};
increment () {
this.count ++;
}
Decment () {
this.count--;
}
}
customElements.define ("мой счетчик", MyCounter);
Элемент HyperHTML
Независимый от фреймворка, hyperHTML может использоваться для визуализации любого представления, включая пользовательские элементы и Веб-компоненты.
GitHub: https://github.com/WebReflection/hyperHTML-Element
Попробуйте в WebComponents.dev
импортировать HyperHTMLElement из "hyperhtml-element";
class MyCounter расширяет HyperHTMLElement {
constructor () {
супер();
this.attachShadow ({режим: "открытый"});
}
created () {
this.count = 0;
this.render ();
}
inc = () => {
this.count ++;
this.render ();
};
dec = () => {
this.count--;
this.render ();
};
render () {
вернуть this.html`
$ {this.count}
`;
}
}
MyCounter.define ("мой счетчик");
LitElement
Домашняя страница: https://lit-element.polymer-project.org /
GitHub: https://github.com/polymer/lit-element
Попробуйте в WebComponents.dev
импортировать {LitElement, html, css} из 'lit-element' ;
экспортный класс MyCounter расширяет LitElement {
static properties = {
count: {type: Number}
};
статические стили = css`
* {
размер шрифта: 200%;
}
span {
ширина: 4бэр;
дисплей: встроенный блок;
выравнивание текста: центр;
}
button {
ширина: 64 пикселя;
высота: 64 пикселя;
граница: нет;
радиус границы: 10 пикселей;
цвет фона: морской;
цвет белый;
}
`;
constructor () {
супер();
this.count = 0;
}
inc () {
this.count ++;
}
dec () {
this.count--;
}
render () {
return html`
$ {this.count}
`;
}
}
customElements.define ('мой-счетчик', MyCounter);
Neow (Alpha)
Современный, быстрый и легкий — это интерфейсный каркас чтобы влюбиться в. (ALPHA)
Домашняя страница: https://neow.dev
GitHub: (alpha)
Попробуйте WebComponents.dev
импортировать {ComponentMixin} из "@ neow / core ";
class MyComponent расширяет ComponentMixin (HTMLElement) {
статический шаблон = `
{{this.counter}}
`;
счетчик = 0;
inc () {
this.counter ++;
}
dec () {
this.counter--;
}
}
customElements.define ("мой счетчик", MyComponent);
Omi с классом
Front End Cross-Frameworks Framework — объединение веб-компонентов, JSX , Virtual DOM, функциональный стиль, наблюдение или прокси в единую структуру с крошечным размером и высокой производительностью. Напишите компоненты один раз, используя везде, например Omi, React, Preact, Vue или Angular.
Домашняя страница: http://omijs.org
GitHub: https://github.com / Tencent / omi
Попробуйте в WebComponents.dev
импортировать {define, WeElement, html} из «omi»;
class MyCounter extends WeElement {
static get propTypes () {
возвращение {
порядковый номер
};
}
static get defaultProps () {
return {count: 0};
}
install () {
this.data = {количество: this.props.count};
}
static get css () {
return `
* {
размер шрифта: 200%;
}
span {
ширина: 4бэр;
дисплей: встроенный блок;
выравнивание текста: центр;
}
button {
ширина: 64 пикселя;
высота: 64 пикселя;
граница: нет;
радиус границы: 10 пикселей;
цвет фона: морской;
цвет белый;
}
`;
}
inc = () => {
this.data.count ++;
this.update ();
};
dec = () => {
this.data.count--;
this.update ();
};
render (props) {
return html`
$ {this.data.count}
`;
}
}
определить ("мой-счетчик", MyCounter);
SkateJS (с Lit-html)
SkateJS — Элементы кастомизации без усилий современными библиотеками представлений.
Домашняя страница: https://skatejs.netlify.com/
GitHub: https://github.com/skatejs/skatejs
Попробуйте в WebComponents.dev
импорт элемента из "@ skatejs / element";
импортировать {render, html} из "lit-html";
class MyCounterElement extends Element {
static get props () {
возвращение {
порядковый номер
};
}
inc = () => {
this.count ++;
};
dec = () => {
this.count--;
};
render () {
const style = `
* {
размер шрифта: 200%;
}
span {
ширина: 4бэр;
дисплей: встроенный блок;
выравнивание текста: центр;
}
button {
ширина: 64 пикселя;
высота: 64 пикселя;
граница: нет;
радиус границы: 10 пикселей;
цвет фона: морской;
цвет белый;
} `;
return html`
$ {this.count}
`;
}
renderer () {
return render (this.render (), this.renderRoot);
}
}
customElements.define ("мой счетчик", MyCounterElement);
SkateJS (с Preact)
SkateJS — Простые пользовательские элементы на базе современных библиотек представлений .
Домашняя страница: https://skatejs.netlify.com/
GitHub: https://github.com/skatejs/skatejs
Попробуйте в WebComponents.dev
/ ** @jsx h ** /
импортировать элемент, {h} из "@ skatejs / element-preact";
class MyCounterElement extends Element {
static get props () {
возвращение {
порядковый номер
};
}
inc = () => {
this.count ++;
};
dec = () => {
this.count--;
};
render () {
const style = `host * {
размер шрифта: 200%;
}
span {
ширина: 4бэр;
дисплей: встроенный блок;
выравнивание текста: центр;
}
button {
ширина: 64 пикселя;
высота: 64 пикселя;
граница: нет;
радиус границы: 10 пикселей;
цвет фона: морской;
цвет белый;
} `;
возвращение (
{this.count}
);
}
}
customElements.define ("мой счетчик", MyCounterElement);
SlimJS
Slim.js — это молниеносная библиотека для разработки собственных веб-компонентов и пользовательских элементов на основе по современным стандартам. Никакой черной магии, никаких бесполезных зависимостей.
Домашняя страница: https://slimjs.com
GitHub: https://github.com/slimjs/slim.js
WebComponents.dev
импорт {Slim} из "slim-js / Slim.js";
импортировать {tag, template, useShadow} из "slim-js / Decorators";
@tag ("мой счетчик")
@useShadow (правда)
@template (`
{{parseCount (count)}}
`)
class MyCounter extends Slim {
constructor () {
супер();
this.count = 0;
}
parseCount (num) {
return String (число);
}
inc () {
this.count ++;
}
dec () {
this.count--;
}
}
Atomico
Atomico — это микробиблиотека (3.9 kB), вдохновленный React Hooks, разработанный и оптимизированный для создания небольших, мощных, декларативных веб-компонентов и использующих только функции
Домашняя страница: https://atomico.gitbook.io/doc/[19459002
GitHub: https://github.com/atomicojs/atomico
Попробуйте WebComponents.dev
/ ** @jsx h * /
import {h, customElement, useProp} из "atomico";
function MyCounter () {
let [count, setCount] = useProp ("счетчик");
const style = `
* {
размер шрифта: 200%;
}
span {
ширина: 4бэр;
дисплей: встроенный блок;
выравнивание текста: центр;
}
button {
ширина: 64 пикселя;
высота: 64 пикселя;
граница: нет;
радиус границы: 10 пикселей;
цвет фона: морской;
цвет белый;
} `;
возвращение (
{count}
);
}
MyCounter.props = {
count: {
тип: Число,
отражать: правда,
значение: 0
}
};
customElements.define ("мой счетчик", customElement (MyCounter));
Gallop
Использование всех возможностей веб-компонентов
GitHub: https: // github.com/tarnishablec/gallop
Попробуйте в WebComponents.dev
импортировать {компонент, html, useState, useStyle, css} из "@ gallop / gallop";
экспорт const MyCounter = component (
"мой счетчик",
() => {
константа [state] = useState ({количество: 0});
useStyle (
() => css`
* {
размер шрифта: 200%;
}
span {
ширина: 4бэр;
дисплей: встроенный блок;
выравнивание текста: центр;
}
button {
ширина: 64 пикселя;
высота: 64 пикселя;
граница: нет;
радиус границы: 10 пикселей;
цвет фона: морской;
цвет белый;
}
`
);
return html`
$ {state.count}
`;
},
{propList: []}
);
Haunted
React's Hooks API, реализованный для веб-компонентов 👻
GitHub: https: //github.com/matthewp/haunted
Попробуйте в WebComponents.dev
импортировать {html} из "lit-html";
import {component, useState} из "привидений";
function Counter () {
const [count, setCount] = useState (0);
return html`
$ {count}
`;
}
customElements.define ("мой счетчик", компонент (Счетчик));
Ересь с крючком
Не моделируйте DOM. Будьте ДОМОМ. Пользовательские элементы в стиле React с помощью встроенного API V1 расширяются.
Домашняя страница: https://medium.com/@WebReflection/any-holy-grail-for-web-components-c3d4973f3f3f
GitHub: https://github.com/WebReflection/heresy
Попробуйте в WebComponents.dev
импортировать {определить} из "ереси";
define ("MyCounter", {
стиль: MyCounter => `
$ {MyCounter} * {
размер шрифта: 200%;
}
$ {MyCounter} span {
ширина: 4бэр;
дисплей: встроенный блок;
выравнивание текста: центр;
}
Кнопка $ {MyCounter} {
ширина: 64 пикселя;
высота: 64 пикселя;
граница: нет;
радиус границы: 10 пикселей;
цвет фона: морской;
цвет белый;
}
`,
render ({useState}) {
const [count, update] = useState (0);
this.html`
`;
}
});
Ересь
Не моделировать DOM . Будьте ДОМОМ. Пользовательские элементы в стиле React с помощью встроенного API V1 расширяются.
Домашняя страница: https://medium.com/@WebReflection/any-holy-grail-for-web-components-c3d4973f3f3f
GitHub: https://github.com/WebReflection/heresy
Попробуйте в WebComponents.dev
импортировать {определить} из "ереси";
define ("MyCounter", {
стиль: MyCounter => `
$ {MyCounter} * {
размер шрифта: 200%;
}
$ {MyCounter} span {
ширина: 4бэр;
дисплей: встроенный блок;
выравнивание текста: центр;
}
Кнопка $ {MyCounter} {
ширина: 64 пикселя;
высота: 64 пикселя;
граница: нет;
радиус границы: 10 пикселей;
цвет фона: морской;
цвет белый;
}
`,
oninit () {
this.count = 0;
},
onclick ({currentTarget}) {
это [currentTarget.dataset.op] ();
this.render ();
},
inc () {
this.count ++;
},
dec () {
this.count--;
},
render () {
this.html`
$ {this.count}
`;
}
});
Гибриды
Гибриды — это библиотека пользовательского интерфейса для создания веб-компонентов с сильным декларативным и функциональным подходом на основе простого объекты и чистые функции.
Домашняя страница: https://hybrids.js.org
GitHub: https://github.com/hybridsjs/hybrids
Попробуйте WebComponents.dev
импорт {html, define} из "гибридов";
function inc (host) {
host.count ++;
}
function dec (host) {
host.count--;
}
const MyCounter = {
количество: 0,
render: ({count}) => html`
$ {count}
`
};
определить ("мой-счетчик", MyCounter);
Литедом
Очень маленькая (3 КБ) библиотека представлений, которая упакована: Веб-компоненты, Пользовательский элемент, Шаблонные литералы, реактивный, привязка данных, односторонний поток данных, двусторонняя привязка данных, обработка событий, свойства, жизненный цикл, управление состоянием, вычисляемые свойства, директивы. Никаких зависимостей, никакого виртуального дома, никакого инструмента для сборки. Вот Это Да! … но это просто библиотека просмотра!
Домашняя страница: https://litedom.js.org/
GitHub: https://github.com/mardix/litedom
Попробуйте в WebComponents.dev
импортировать Литедом из "литедом";
Литедом ({
tagName: "мой-счетчик",
shadowDOM: правда,
шаблон: `
{this.count}
`,
данные: {
количество: 0
},
dec () {
this.data.count--;
},
inc () {
this.data.count ++;
}
});
Оттавино
Крошечная, быстрая и декларативная разработка пользовательского интерфейса. Использование собственного API пользовательских элементов (но не только). Все очень просто.
GitHub: https://github.com/betterthancode/ottavino
Попробуйте в WebComponents.dev
импортировать {компонент} из "ottavino";
составная часть({
тег: "мой счетчик",
тень: правда,
шаблон: `
{{this.count}}
`,
properties: {
количество: 0
},
этот: {
увеличить: function () {
this.count ++;
},
уменьшение: function () {
this.count--;
}
}
});
Швейцарский
Функциональные настраиваемые элементы
GitHub: https://github.com / luwes / swiss
Попробуйте в WebComponents.dev
импортировать {определить} из "swiss";
импортировать {html, render} из "lit-html";
const Counter = (CE) => (el) => {
el.attachShadow ({режим: "открытый"});
возвращение {
обновление: () =>
визуализировать (
html`
$ {el.count}
`,
el.shadowRoot
),
};
};
define ("my-counter", {
реквизит: {count: 0},
настройка: Счетчик,
});
uce
Пользовательские элементы на основе µhtml.
Домашняя страница: https: // github .com / WebReflection / uce
GitHub: https://github.com/WebReflection/uce
Попробуйте в WebComponents.dev
импортировать {определить} из "uce";
define ("my-counter", {
attachShadow: {режим: "открытый"},
в этом() {
this.count = 0;
this.dec = () => {
this.count--;
this.render ();
};
this.inc = () => {
this.count ++;
this.render ();
};
this.render ();
},
render () {
this.html`
$ {this.count}
`;
}
});
Веб-компоненты Lightning
⚡️ LWC — A Молниеносная скорость, Фонд веб-компонентов корпоративного уровня
Домашняя страница: https://lwc.dev
GitHub: https://github.com/salesforce/lwc
Попробуйте использовать веб-компоненты. dev
импорт {LightningElement, api, buildCustomElementConstructor} из "lwc";
экспорт класса по умолчанию MyCounter extends LightningElement {
count = 0;
inc () {
this.count ++;
}
dec () {
this.count--;
}
}
customElements.define ("мой счетчик", buildCustomElementConstructor (MyCounter));
Элемент Lume
Создание пользовательских элементов с реактивностью и автоматическим повторным рендерингом
GitHub: https://github.com/lume/element
Попробуйте в WebComponents.dev
импортировать {Element, css, createSignal} из "@ lume / element";
экспортный класс MyCounter расширяет Element {
constructor () {
супер();
this._count = createSignal (0);
}
get count () {
вернуть this._count [0] ();
}
set count (val) {
this._count [1] (val);
}
template () {
возвращение (
<>
{this.count}
>
);
}
static get css () {
return css`
* {
размер шрифта: 200%;
}
span {
ширина: 4бэр;
дисплей: встроенный блок;
выравнивание текста: центр;
}
button {
ширина: 4бэр;
высота: 4бэр;
граница: нет;
радиус границы: 10 пикселей;
цвет фона: морской;
цвет белый;
}
`;
}
}
customElements.define ("мой счетчик", MyCounter);
Solid Element
Обманчиво простая библиотека пользовательского интерфейса
GitHub: https: //github.com/ryansolid/solid
Попробуйте в WebComponents.dev
import {createSignal} из "solid-js";
импорт {customElement} из "твердого элемента";
const style = `div * {
размер шрифта: 200%;
}
span {
ширина: 4бэр;
дисплей: встроенный блок;
выравнивание текста: центр;
}
button {
ширина: 4бэр;
высота: 4бэр;
граница: нет;
радиус границы: 10 пикселей;
цвет фона: морской;
цвет белый;
} `;
customElement ("my-counter", () => {
const [count, setCount] = createSignal (0);
возвращение (
{count}
);
});
Stencil
Stencil — это набор инструментов для создания многоразовых масштабируемых систем проектирования. Создавайте небольшие, невероятно быстрые и полностью основанные на стандартах веб-компоненты, которые работают в каждом браузере.
Домашняя страница: https://stenciljs.com/
GitHub: https://github.com / ionic-team / stencil
Попробуйте в WebComponents.dev
/ * @jsx h * /
импортировать {h, Component, State, Host} из "@stencil / core";
@Составная часть({
тег: "мой счетчик",
styleUrl: "index.css",
тень: правда
})
export class MyCounter {
@State () count: number = 0;
inc () {
this.count ++;
}
dec () {
this.count--;
}
render () {
возвращение (
{this.count}
);
}
}
Угловые 9 элементов (обернутые угловыми- элементы)
Один каркас. Мобильные и настольные компьютеры.
Домашняя страница: https://angular.io/[19459002 visible
GitHub: https://github.com/angular/angular
Попробуйте в WebComponents.dev
импорт {
Вход,
Составная часть,
ViewEncapsulation,
ChangeDetectorRef
} от "@ angular / core";
@Составная часть({
селектор: "мой счетчик",
шаблон: `
{{count}}
`,
стили: [
`
* {
font-size: 200%;
}
span {
width: 4rem;
display: inline-block;
text-align: center;
}
button {
width: 64px;
height: 64px;
border: none;
border-radius: 10px;
background-color: seagreen;
color: white;
}
`
],
инкапсуляция: ViewEncapsulation.ShadowDom
})
экспорт класса по умолчанию MyCounter {
@Input () count: number = 0;
конструктор (частный компакт-диск: ChangeDetectorRef) {}
dec () {
this.count--;
this.cd.detectChanges ();
}
inc () {
this.count ++;
this.cd.detectChanges ();
}
}
Preact w / Class (с добавлением preact-custom-element)
Fast 3kB альтернатива реагировать с использованием того же современного API.
Домашняя страница: https://preactjs.com/
GitHub: https://github.com/preactjs/preact
Попробуйте использовать WebComponents. dev
импорт {createCustomElement} из "@ wcd / preact-custom-element";
импортировать {Component, html} из "htm / preact";
импортный «преакт»;
class MyCounter extends Component {
state = {
количество: 0
};
inc = () => {
this.setState (prev => ({count: prev.count + 1}));
};
dec = () => {
this.setState (prev => ({count: prev.count - 1}));
};
render (props, state) {
return html`
$ {state.count}
`;
}
}
customElements.define ("мой-счетчик", createCustomElement (MyCounter, ["count"]));
React с классом (в оболочке с помощью компонента react-to-web)
Библиотека JavaScript для создания пользовательских интерфейсов
Домашняя страница: https://reactjs.org/[19459002impression
GitHub: https://github.com/facebook/react/
Попробуйте в WebComponents.dev
импорт React из "react";
импортировать ReactDOM из "react-dom";
импортировать reactToWebComponent из "response-to-webcomponent";
interface State {
порядковый номер;
}
интерфейс Props {}
экспорт класса по умолчанию MyCounter расширяет React.Component {
constructor (props) {
супер (реквизит);
this.state = {
количество: 0
};
}
render () {
const styles = `.my-counter * {
размер шрифта: 200%;
}
.my-counter span {
ширина: 4бэр;
дисплей: встроенный блок;
выравнивание текста: центр;
}
.my-counter button {
ширина: 64 пикселя;
высота: 64 пикселя;
граница: нет;
радиус границы: 10 пикселей;
цвет фона: морской;
цвет белый;
} `;
возвращение (
{this.state.count}
);
}
}
customElements.define (
"мой счетчик",
reactToWebComponent (MyCounter, React, ReactDOM)
);
React w / Hook (завернутый в компонент react-to-web)
Библиотека JavaScript для создания пользовательских интерфейсов
Домашняя страница: https://reactjs.org/[19459002impression
GitHub: https://github.com/facebook/react/
Попробуйте в WebComponents.dev
импортировать React, {useState} из "react";
импортировать ReactDOM из "react-dom";
импортировать reactToWebComponent из "response-to-webcomponent";
экспортировать функцию по умолчанию MyCounter () {
const [count, setCount] = useState (0);
const styles = `
.my-counter * {
размер шрифта: 200%;
}
.my-counter span {
ширина: 4бэр;
дисплей: встроенный блок;
выравнивание текста: центр;
}
.my-counter button {
ширина: 64 пикселя;
высота: 64 пикселя;
граница: нет;
радиус границы: 10 пикселей;
цвет фона: морской;
цвет белый;
} `;
возвращение (
{count}
);
}
customElements.define (
"мой счетчик",
reactToWebComponent (MyCounter, React, ReactDOM)
);
Riot (в оболочке с @ riotjs / custom-elements)
Простая и элегантная библиотека пользовательского интерфейса на основе компонентов
Домашняя страница: https://riot.js.org/[19459002impression
GitHub: https://github.com/riot/riot
Попробуйте в WebComponents.dev
{state.count}
Svelte (с {customElement: true})
Кибернетически улучшенные веб-приложения
Домашняя страница: https://svelte.dev/[19459002impression
GitHub: https://github.com/sveltejs/svelte
Попробуйте в WebComponents.dev
{count}
Vue.js (завернутый в vue-custom-element)
🖖 Vue .js — это прогрессивная, постепенно адаптируемая среда JavaScript для создания пользовательского интерфейса в Интернете.
Домашняя страница: https://vuejs.org/
GitHub: https://github.com/ vuejs / vue
Попробуйте в WebComponents.dev
{{count}}
Содержание статьи
- 1 HTMLElement
- 2 HTMLElement (w/ Lighterhtml)
- 3 HTMLElement (w/ Lit-html)
- 4 HTMLElement (w/ uhtml)
- 5 CanJS
- 6 HyperHTML Element
- 7 LitElement
- 8 Neow (Alpha)
- 9 Omi w/Class
- 10 SkateJS (with Lit-html)
- 11 SkateJS (with Preact)
- 12 SlimJS
- 13 Atomico
- 14 Gallop
- 15 Haunted
- 16 Heresy w/Hook
- 17 Heresy
- 18 Hybrids
- 19 Litedom
- 20 Ottavino
- 21 Swiss
- 22 uce
- 23 Lightning Web Components
- 24 Lume Element
- 25 Solid Element
- 26 Stencil
- 27 Angular 9 Elements
- 28 Preact w/Class
- 29 React w/Class
- 30 React w/Hook
- 31 Riot
- 32 Svelte
- 33 Vue.js
HTMLElement
No dependencies
Component size including library
Minified — Uncompressed | 1,293 |
Minified + Gzip | 558 |
Minified + Brotli | 418 |
Composition
Open Bundle Visualizer
Compilation details
All Sources have been Transpiled by WebComponents.dev compiler with the following Babel settings:
[
[
Babel.availablePresets['env'],
{
targets: {
browsers:
'last 2 Chrome versions, last 2 Firefox versions, last 2 Safari versions, last 2 iOS versions, last 2 Android versions',
},
modules: 'false',
bugfixes: true,
},
],
[Babel.availablePresets['react']],
],
plugins: [
[Babel.availablePlugins['proposal-decorators']{ legacy: true }],
[Babel.availablePlugins['proposal-class-properties']{ loose: true }],
]
Bundling details
Bundled with Rollup
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
...
input: 'source.js',
output: {
dir: 'dist'),
format: 'esm',
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
withdeps ? resolve() : undefined,
commonjs( /* { namedExports: for React } */ ),
terser({ output: { comments: false } }),
...
HTMLElement (w/ Lighterhtml)
Dependencies
lighterhtml : ^3.1.3
Component size including library
Minified — Uncompressed | 15,699 |
Minified + Gzip | 6,360 |
Minified + Brotli | 5,799 |
Composition
Open Bundle Visualizer
Compilation details
All Sources have been Transpiled by WebComponents.dev compiler with the following Babel settings:
[
[
Babel.availablePresets['env'],
{
targets: {
browsers:
'last 2 Chrome versions, last 2 Firefox versions, last 2 Safari versions, last 2 iOS versions, last 2 Android versions',
},
modules: 'false',
bugfixes: true,
},
],
[Babel.availablePresets['react']],
],
plugins: [
[Babel.availablePlugins['proposal-decorators']{ legacy: true }],
[Babel.availablePlugins['proposal-class-properties']{ loose: true }],
]
Bundling details
Bundled with Rollup
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
...
input: 'source.js',
output: {
dir: 'dist'),
format: 'esm',
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
withdeps ? resolve() : undefined,
commonjs( /* { namedExports: for React } */ ),
terser({ output: { comments: false } }),
...
HTMLElement (w/ Lit-html)
Dependencies
lit-html : ^1.2.1
Component size including library
Minified — Uncompressed | 9,955 |
Minified + Gzip | 3,530 |
Minified + Brotli | 3,144 |
Composition
Open Bundle Visualizer
Compilation details
All Sources have been Transpiled by WebComponents.dev compiler with the following Babel settings:
[
[
Babel.availablePresets['env'],
{
targets: {
browsers:
'last 2 Chrome versions, last 2 Firefox versions, last 2 Safari versions, last 2 iOS versions, last 2 Android versions',
},
modules: 'false',
bugfixes: true,
},
],
[Babel.availablePresets['react']],
],
plugins: [
[Babel.availablePlugins['proposal-decorators']{ legacy: true }],
[Babel.availablePlugins['proposal-class-properties']{ loose: true }],
]
Bundling details
Bundled with Rollup
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
...
input: 'source.js',
output: {
dir: 'dist'),
format: 'esm',
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
withdeps ? resolve() : undefined,
commonjs( /* { namedExports: for React } */ ),
terser({ output: { comments: false } }),
...
HTMLElement (w/ uhtml)
Dependencies
uhtml : ^1.11.6
Component size including library
Minified — Uncompressed | 6,973 |
Minified + Gzip | 3,179 |
Minified + Brotli | 2,849 |
Composition
Open Bundle Visualizer
Compilation details
All Sources have been Transpiled by WebComponents.dev compiler with the following Babel settings:
[
[
Babel.availablePresets['env'],
{
targets: {
browsers:
'last 2 Chrome versions, last 2 Firefox versions, last 2 Safari versions, last 2 iOS versions, last 2 Android versions',
},
modules: 'false',
bugfixes: true,
},
],
[Babel.availablePresets['react']],
],
plugins: [
[Babel.availablePlugins['proposal-decorators']{ legacy: true }],
[Babel.availablePlugins['proposal-class-properties']{ loose: true }],
]
Bundling details
Bundled with Rollup
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
...
input: 'source.js',
output: {
dir: 'dist'),
format: 'esm',
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
withdeps ? resolve() : undefined,
commonjs( /* { namedExports: for React } */ ),
terser({ output: { comments: false } }),
...
CanJS
Dependencies
can : ^6.4.0
Component size including library
Minified — Uncompressed | 230,634 |
Minified + Gzip | 63,154 |
Minified + Brotli | 54,620 |
Composition
Open Bundle Visualizer
Compilation details
All Sources have been Transpiled by WebComponents.dev compiler with the following Babel settings:
[
[
Babel.availablePresets['env'],
{
targets: {
browsers:
'last 2 Chrome versions, last 2 Firefox versions, last 2 Safari versions, last 2 iOS versions, last 2 Android versions',
},
modules: 'false',
bugfixes: true,
},
],
[Babel.availablePresets['react']],
],
plugins: [
[Babel.availablePlugins['proposal-decorators']{ legacy: true }],
[Babel.availablePlugins['proposal-class-properties']{ loose: true }],
]
Bundling details
Bundled with Rollup
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
...
input: 'source.js',
output: {
dir: 'dist'),
format: 'esm',
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
withdeps ? resolve() : undefined,
commonjs( /* { namedExports: for React } */ ),
terser({ output: { comments: false } }),
...
HyperHTML Element
Dependencies
hyperhtml-element : ^3.12.3
Component size including library
Minified — Uncompressed | 23,316 |
Minified + Gzip | 9,061 |
Minified + Brotli | 8,277 |
Composition
Open Bundle Visualizer
Compilation details
All Sources have been Transpiled by WebComponents.dev compiler with the following Babel settings:
[
[
Babel.availablePresets['env'],
{
targets: {
browsers:
'last 2 Chrome versions, last 2 Firefox versions, last 2 Safari versions, last 2 iOS versions, last 2 Android versions',
},
modules: 'false',
bugfixes: true,
},
],
[Babel.availablePresets['react']],
],
plugins: [
[Babel.availablePlugins['proposal-decorators']{ legacy: true }],
[Babel.availablePlugins['proposal-class-properties']{ loose: true }],
]
Bundling details
Bundled with Rollup
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
...
input: 'source.js',
output: {
dir: 'dist'),
format: 'esm',
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
withdeps ? resolve() : undefined,
commonjs( /* { namedExports: for React } */ ),
terser({ output: { comments: false } }),
...
LitElement
Dependencies
lit-element : ^2.3.1
Component size including library
Minified — Uncompressed | 20,395 |
Minified + Gzip | 6,682 |
Minified + Brotli | 5,997 |
Composition
Open Bundle Visualizer
Compilation details
All Sources have been Transpiled by WebComponents.dev compiler with the following Babel settings:
[
[
Babel.availablePresets['env'],
{
targets: {
browsers:
'last 2 Chrome versions, last 2 Firefox versions, last 2 Safari versions, last 2 iOS versions, last 2 Android versions',
},
modules: 'false',
bugfixes: true,
},
],
[Babel.availablePresets['react']],
],
plugins: [
[Babel.availablePlugins['proposal-decorators']{ legacy: true }],
[Babel.availablePlugins['proposal-class-properties']{ loose: true }],
]
Bundling details
Bundled with Rollup
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
...
input: 'source.js',
output: {
dir: 'dist'),
format: 'esm',
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
withdeps ? resolve() : undefined,
commonjs( /* { namedExports: for React } */ ),
terser({ output: { comments: false } }),
...
Neow (Alpha)
Dependencies
@neow/core : 0.0.6
Component size including library
Minified — Uncompressed | 4,435 |
Minified + Gzip | 1,879 |
Minified + Brotli | 1,617 |
Composition
Open Bundle Visualizer
Compilation details
All Sources have been Transpiled by WebComponents.dev compiler with the following Babel settings:
[
[
Babel.availablePresets['env'],
{
targets: {
browsers:
'last 2 Chrome versions, last 2 Firefox versions, last 2 Safari versions, last 2 iOS versions, last 2 Android versions',
},
modules: 'false',
bugfixes: true,
},
],
[Babel.availablePresets['react']],
],
plugins: [
[Babel.availablePlugins['proposal-decorators']{ legacy: true }],
[Babel.availablePlugins['proposal-class-properties']{ loose: true }],
]
Bundling details
Bundled with Rollup
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
...
input: 'source.js',
output: {
dir: 'dist'),
format: 'esm',
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
withdeps ? resolve() : undefined,
commonjs( /* { namedExports: for React } */ ),
terser({ output: { comments: false } }),
...
Omi w/Class
Dependencies
omi : ^6.19.3
Component size including library
Minified — Uncompressed | 24,622 |
Minified + Gzip | 8,412 |
Minified + Brotli | 7,566 |
Composition
Open Bundle Visualizer
Compilation details
All Sources have been Transpiled by WebComponents.dev compiler with the following Babel settings:
[
[
Babel.availablePresets['env'],
{
targets: {
browsers:
'last 2 Chrome versions, last 2 Firefox versions, last 2 Safari versions, last 2 iOS versions, last 2 Android versions',
},
modules: 'false',
bugfixes: true,
},
],
[Babel.availablePresets['react']],
],
plugins: [
[Babel.availablePlugins['proposal-decorators']{ legacy: true }],
[Babel.availablePlugins['proposal-class-properties']{ loose: true }],
]
Bundling details
Bundled with Rollup
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
...
input: 'source.js',
output: {
dir: 'dist'),
format: 'esm',
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
withdeps ? resolve() : undefined,
commonjs( /* { namedExports: for React } */ ),
terser({ output: { comments: false } }),
...
SkateJS (with Lit-html)
Dependencies
@skatejs/element : 0.0.1
lit-html : ^1.2.1
Component size including library
Minified — Uncompressed | 15,580 |
Minified + Gzip | 5,248 |
Minified + Brotli | 4,662 |
Composition
Open Bundle Visualizer
Compilation details
All Sources have been Transpiled by WebComponents.dev compiler with the following Babel settings:
[
[
Babel.availablePresets['env'],
{
targets: {
browsers:
'last 2 Chrome versions, last 2 Firefox versions, last 2 Safari versions, last 2 iOS versions, last 2 Android versions',
},
modules: 'false',
bugfixes: true,
},
],
[Babel.availablePresets['react']],
],
plugins: [
[Babel.availablePlugins['proposal-decorators']{ legacy: true }],
[Babel.availablePlugins['proposal-class-properties']{ loose: true }],
]
Bundling details
Bundled with Rollup
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
...
input: 'source.js',
output: {
dir: 'dist'),
format: 'esm',
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
withdeps ? resolve() : undefined,
commonjs( /* { namedExports: for React } */ ),
terser({ output: { comments: false } }),
...
SkateJS (with Preact)
Dependencies
@skatejs/element-preact : 0.0.1
Component size including library
Minified — Uncompressed | 17,557 |
Minified + Gzip | 6,244 |
Minified + Brotli | 5,630 |
Composition
Open Bundle Visualizer
Compilation details
All Sources have been Transpiled by WebComponents.dev compiler with the following Babel settings:
[
[
Babel.availablePresets['env'],
{
targets: {
browsers:
'last 2 Chrome versions, last 2 Firefox versions, last 2 Safari versions, last 2 iOS versions, last 2 Android versions',
},
modules: 'false',
bugfixes: true,
},
],
[Babel.availablePresets['react']],
],
plugins: [
[Babel.availablePlugins['proposal-decorators']{ legacy: true }],
[Babel.availablePlugins['proposal-class-properties']{ loose: true }],
]
Bundling details
Bundled with Rollup
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
...
input: 'source.js',
output: {
dir: 'dist'),
format: 'esm',
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
withdeps ? resolve() : undefined,
commonjs( /* { namedExports: for React } */ ),
terser({ output: { comments: false } }),
...
SlimJS
Dependencies
slim-js : ^4.0.7
Component size including library
Minified — Uncompressed | 9,467 |
Minified + Gzip | 3,661 |
Minified + Brotli | 3,220 |
Composition
Open Bundle Visualizer
Compilation details
All Sources have been Transpiled by WebComponents.dev compiler with the following Babel settings:
[
[
Babel.availablePresets['env'],
{
targets: {
browsers:
'last 2 Chrome versions, last 2 Firefox versions, last 2 Safari versions, last 2 iOS versions, last 2 Android versions',
},
modules: 'false',
bugfixes: true,
},
],
[Babel.availablePresets['react']],
],
plugins: [
[Babel.availablePlugins['proposal-decorators']{ legacy: true }],
[Babel.availablePlugins['proposal-class-properties']{ loose: true }],
]
Bundling details
Bundled with Rollup
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
...
input: 'source.js',
output: {
dir: 'dist'),
format: 'esm',
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
withdeps ? resolve() : undefined,
commonjs( /* { namedExports: for React } */ ),
terser({ output: { comments: false } }),
...
Atomico
Dependencies
atomico : ^0.23.2
Component size including library
Minified — Uncompressed | 5,800 |
Minified + Gzip | 2,735 |
Minified + Brotli | 2,434 |
Composition
Open Bundle Visualizer
Compilation details
All Sources have been Transpiled by WebComponents.dev compiler with the following Babel settings:
[
[
Babel.availablePresets['env'],
{
targets: {
browsers:
'last 2 Chrome versions, last 2 Firefox versions, last 2 Safari versions, last 2 iOS versions, last 2 Android versions',
},
modules: 'false',
bugfixes: true,
},
],
[Babel.availablePresets['react']],
],
plugins: [
[Babel.availablePlugins['proposal-decorators']{ legacy: true }],
[Babel.availablePlugins['proposal-class-properties']{ loose: true }],
]
Bundling details
Bundled with Rollup
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
...
input: 'source.js',
output: {
dir: 'dist'),
format: 'esm',
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
withdeps ? resolve() : undefined,
commonjs( /* { namedExports: for React } */ ),
terser({ output: { comments: false } }),
...
Gallop
Dependencies
@gallop/gallop : ^0.9.9-beta.6
Component size including library
Minified — Uncompressed | 11,921 |
Minified + Gzip | 4,581 |
Minified + Brotli | 4,083 |
Composition
Open Bundle Visualizer
Compilation details
All Sources have been Transpiled by WebComponents.dev compiler with the following Babel settings:
[
[
Babel.availablePresets['env'],
{
targets: {
browsers:
'last 2 Chrome versions, last 2 Firefox versions, last 2 Safari versions, last 2 iOS versions, last 2 Android versions',
},
modules: 'false',
bugfixes: true,
},
],
[Babel.availablePresets['react']],
],
plugins: [
[Babel.availablePlugins['proposal-decorators']{ legacy: true }],
[Babel.availablePlugins['proposal-class-properties']{ loose: true }],
]
Bundling details
Bundled with Rollup
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
...
input: 'source.js',
output: {
dir: 'dist'),
format: 'esm',
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
withdeps ? resolve() : undefined,
commonjs( /* { namedExports: for React } */ ),
terser({ output: { comments: false } }),
...
Haunted
Dependencies
haunted : ^4.7.0
Component size including library
Minified — Uncompressed | 15,327 |
Minified + Gzip | 5,267 |
Minified + Brotli | 4,708 |
Composition
Open Bundle Visualizer
Compilation details
All Sources have been Transpiled by WebComponents.dev compiler with the following Babel settings:
[
[
Babel.availablePresets['env'],
{
targets: {
browsers:
'last 2 Chrome versions, last 2 Firefox versions, last 2 Safari versions, last 2 iOS versions, last 2 Android versions',
},
modules: 'false',
bugfixes: true,
},
],
[Babel.availablePresets['react']],
],
plugins: [
[Babel.availablePlugins['proposal-decorators']{ legacy: true }],
[Babel.availablePlugins['proposal-class-properties']{ loose: true }],
]
Bundling details
Bundled with Rollup
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
...
input: 'source.js',
output: {
dir: 'dist'),
format: 'esm',
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
withdeps ? resolve() : undefined,
commonjs( /* { namedExports: for React } */ ),
terser({ output: { comments: false } }),
...
Heresy w/Hook
Dependencies
heresy : ^0.28.1
Component size including library
Minified — Uncompressed | 26,556 |
Minified + Gzip | 9,984 |
Minified + Brotli | 9,094 |
Composition
Open Bundle Visualizer
Compilation details
All Sources have been Transpiled by WebComponents.dev compiler with the following Babel settings:
[
[
Babel.availablePresets['env'],
{
targets: {
browsers:
'last 2 Chrome versions, last 2 Firefox versions, last 2 Safari versions, last 2 iOS versions, last 2 Android versions',
},
modules: 'false',
bugfixes: true,
},
],
[Babel.availablePresets['react']],
],
plugins: [
[Babel.availablePlugins['proposal-decorators']{ legacy: true }],
[Babel.availablePlugins['proposal-class-properties']{ loose: true }],
]
Bundling details
Bundled with Rollup
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
...
input: 'source.js',
output: {
dir: 'dist'),
format: 'esm',
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
withdeps ? resolve() : undefined,
commonjs( /* { namedExports: for React } */ ),
terser({ output: { comments: false } }),
...
Heresy
Dependencies
heresy : ^0.28.1
Component size including library
Minified — Uncompressed | 26,679 |
Minified + Gzip | 10,022 |
Minified + Brotli | 9,130 |
Composition
Open Bundle Visualizer
Compilation details
All Sources have been Transpiled by WebComponents.dev compiler with the following Babel settings:
[
[
Babel.availablePresets['env'],
{
targets: {
browsers:
'last 2 Chrome versions, last 2 Firefox versions, last 2 Safari versions, last 2 iOS versions, last 2 Android versions',
},
modules: 'false',
bugfixes: true,
},
],
[Babel.availablePresets['react']],
],
plugins: [
[Babel.availablePlugins['proposal-decorators']{ legacy: true }],
[Babel.availablePlugins['proposal-class-properties']{ loose: true }],
]
Bundling details
Bundled with Rollup
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
...
input: 'source.js',
output: {
dir: 'dist'),
format: 'esm',
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
withdeps ? resolve() : undefined,
commonjs( /* { namedExports: for React } */ ),
terser({ output: { comments: false } }),
...
Hybrids
Dependencies
hybrids : ^4.2.1
Component size including library
Minified — Uncompressed | 20,811 |
Minified + Gzip | 6,941 |
Minified + Brotli | 6,257 |
Composition
Open Bundle Visualizer
Compilation details
All Sources have been Transpiled by WebComponents.dev compiler with the following Babel settings:
[
[
Babel.availablePresets['env'],
{
targets: {
browsers:
'last 2 Chrome versions, last 2 Firefox versions, last 2 Safari versions, last 2 iOS versions, last 2 Android versions',
},
modules: 'false',
bugfixes: true,
},
],
[Babel.availablePresets['react']],
],
plugins: [
[Babel.availablePlugins['proposal-decorators']{ legacy: true }],
[Babel.availablePlugins['proposal-class-properties']{ loose: true }],
]
Bundling details
Bundled with Rollup
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
...
input: 'source.js',
output: {
dir: 'dist'),
format: 'esm',
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
withdeps ? resolve() : undefined,
commonjs( /* { namedExports: for React } */ ),
terser({ output: { comments: false } }),
...
Litedom
Dependencies
litedom : ^0.12.1
Component size including library
Minified — Uncompressed | 9,392 |
Minified + Gzip | 3,835 |
Minified + Brotli | 3,412 |
Composition
Open Bundle Visualizer
Compilation details
All Sources have been Transpiled by WebComponents.dev compiler with the following Babel settings:
[
[
Babel.availablePresets['env'],
{
targets: {
browsers:
'last 2 Chrome versions, last 2 Firefox versions, last 2 Safari versions, last 2 iOS versions, last 2 Android versions',
},
modules: 'false',
bugfixes: true,
},
],
[Babel.availablePresets['react']],
],
plugins: [
[Babel.availablePlugins['proposal-decorators']{ legacy: true }],
[Babel.availablePlugins['proposal-class-properties']{ loose: true }],
]
Bundling details
Bundled with Rollup
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
...
input: 'source.js',
output: {
dir: 'dist'),
format: 'esm',
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
withdeps ? resolve() : undefined,
commonjs( /* { namedExports: for React } */ ),
terser({ output: { comments: false } }),
...
Ottavino
Dependencies
ottavino : ^0.2.4
Component size including library
Minified — Uncompressed | 4,444 |
Minified + Gzip | 1,977 |
Minified + Brotli | 1,709 |
Composition
Open Bundle Visualizer
Compilation details
All Sources have been Transpiled by WebComponents.dev compiler with the following Babel settings:
[
[
Babel.availablePresets['env'],
{
targets: {
browsers:
'last 2 Chrome versions, last 2 Firefox versions, last 2 Safari versions, last 2 iOS versions, last 2 Android versions',
},
modules: 'false',
bugfixes: true,
},
],
[Babel.availablePresets['react']],
],
plugins: [
[Babel.availablePlugins['proposal-decorators']{ legacy: true }],
[Babel.availablePlugins['proposal-class-properties']{ loose: true }],
]
Bundling details
Bundled with Rollup
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
...
input: 'source.js',
output: {
dir: 'dist'),
format: 'esm',
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
withdeps ? resolve() : undefined,
commonjs( /* { namedExports: for React } */ ),
terser({ output: { comments: false } }),
...
Swiss
Dependencies
swiss : ^2.0.0
Component size including library
Minified — Uncompressed | 12,126 |
Minified + Gzip | 4,373 |
Minified + Brotli | 3,888 |
Composition
Open Bundle Visualizer
Compilation details
All Sources have been Transpiled by WebComponents.dev compiler with the following Babel settings:
[
[
Babel.availablePresets['env'],
{
targets: {
browsers:
'last 2 Chrome versions, last 2 Firefox versions, last 2 Safari versions, last 2 iOS versions, last 2 Android versions',
},
modules: 'false',
bugfixes: true,
},
],
[Babel.availablePresets['react']],
],
plugins: [
[Babel.availablePlugins['proposal-decorators']{ legacy: true }],
[Babel.availablePlugins['proposal-class-properties']{ loose: true }],
]
Bundling details
Bundled with Rollup
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
...
input: 'source.js',
output: {
dir: 'dist'),
format: 'esm',
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
withdeps ? resolve() : undefined,
commonjs( /* { namedExports: for React } */ ),
terser({ output: { comments: false } }),
...
uce
Dependencies
uce : ^0.13.1
Component size including library
Minified — Uncompressed | 8,563 |
Minified + Gzip | 3,829 |
Minified + Brotli | 3,438 |
Composition
Open Bundle Visualizer
Compilation details
All Sources have been Transpiled by WebComponents.dev compiler with the following Babel settings:
[
[
Babel.availablePresets['env'],
{
targets: {
browsers:
'last 2 Chrome versions, last 2 Firefox versions, last 2 Safari versions, last 2 iOS versions, last 2 Android versions',
},
modules: 'false',
bugfixes: true,
},
],
[Babel.availablePresets['react']],
],
plugins: [
[Babel.availablePlugins['proposal-decorators']{ legacy: true }],
[Babel.availablePlugins['proposal-class-properties']{ loose: true }],
]
Bundling details
Bundled with Rollup
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
...
input: 'source.js',
output: {
dir: 'dist'),
format: 'esm',
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
withdeps ? resolve() : undefined,
commonjs( /* { namedExports: for React } */ ),
terser({ output: { comments: false } }),
...
Lightning Web Components
Dependencies
lwc : ^1.6.2
Component size including library
Minified — Uncompressed | 38,531 |
Minified + Gzip | 13,079 |
Minified + Brotli | 11,763 |
Composition
Open Bundle Visualizer
Compilation details
All Sources have been Transpiled by WebComponents.dev compiler with the following LWC settings:
const outputConfig: {
format: 'esm',
sourcemap: true,
};
Bundling details
Bundled with Rollup
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
...
input: 'source.js',
output: {
dir: 'dist'),
format: 'esm',
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
withdeps ? resolve() : undefined,
commonjs( /* { namedExports: for React } */ ),
terser({ output: { comments: false } }),
...
Lume Element
Dependencies
@lume/element : 0.0.15
Component size including library
Minified — Uncompressed | 9,520 |
Minified + Gzip | 3,781 |
Minified + Brotli | 3,379 |
Composition
Open Bundle Visualizer
Compilation details
All Sources have been Transpiled by WebComponents.dev compiler with the solid
preset:
{
"presets": [
"solid"
]
}
Bundling details
Bundled with Rollup
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
...
input: 'source.js',
output: {
dir: 'dist'),
format: 'esm',
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
withdeps ? resolve() : undefined,
commonjs( /* { namedExports: for React } */ ),
terser({ output: { comments: false } }),
...
Solid Element
Dependencies
solid-js : ^0.18.4
solid-element : ^0.18.4
Component size including library
Minified — Uncompressed | 12,575 |
Minified + Gzip | 4,846 |
Minified + Brotli | 4,316 |
Composition
Open Bundle Visualizer
Compilation details
All Sources have been Transpiled by WebComponents.dev compiler with the solid
preset:
{
"presets": [
"solid"
]
}
Bundling details
Bundled with Rollup
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
...
input: 'source.js',
output: {
dir: 'dist'),
format: 'esm',
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
withdeps ? resolve() : undefined,
commonjs( /* { namedExports: for React } */ ),
terser({ output: { comments: false } }),
...
Stencil
Dependencies
@stencil/core : ^1.14.0
Component size including library
Minified — Uncompressed | 6,811 |
Minified + Gzip | 3,565 |
Minified + Brotli | 3,154 |
Composition
Open Bundle Visualizer
Compilation details
All Sources have been compiled with Stencil CLI and settings:
// tsconfig.js
...
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"allowUnreachableCode": false,
"declaration": false,
"experimentalDecorators": true,
"lib": ["DOM", "ES2018"],
"moduleResolution": "node",
"module": "esnext",
"target": "es2017",
"noUnusedLocals": true,
"noUnusedParameters": true,
"jsx": "react",
"jsxFactory": "h",
"types": []
}
...
//stencil.config.js
import { Config } from '@stencil/core';
export const config: Config = {
srcDir: 'stencil/src',
namespace: 'my-counter',
hashFileNames: false,
plugins: [],
outputTargets: [
{
type: 'www',
serviceWorker: null, // disable service workers
},
],
hydratedFlag: null,
extras: {
cssVarsShim: false,
dynamicImportShim: false,
safari10: false,
scriptDataOpts: false,
shadowDomShim: false,
},
};
Bundling details
Bundled by Stencil CLI
Angular 9 Elements
Dependencies
@angular/core : ^9.1.9
@angular/cli : ^9.1.7
@angular/common : ^9.1.9
@angular/compiler : ^9.1.9
@angular/compiler-cli : ^9.1.9
@angular-devkit/build-angular : ^0.901.7
document-register-element : ^1.14.3
@angular/elements : ^9.1.9
@angular/platform-browser-dynamic : ^9.1.9
@angular/platform-browser : ^9.1.9
Component size including library
Minified — Uncompressed | 227,232 |
Minified + Gzip | 69,831 |
Minified + Brotli | 59,961 |
Composition
Open Bundle Visualizer
Compilation details
Compile with Angular compiler and the following angular.json
:
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "download",
"projects": {
"elements": {
"root": "download/009-angular-9-elements",
"sourceRoot": "download/009-angular-9-elements/src",
"projectType": "application",
"prefix": "app",
"schematics": {},
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"aot": true,
"outputPath": "download/009-angular-9-elements/dist",
"index": "download/009-angular-9-elements/src/index.html",
"main": "download/009-angular-9-elements/src/index.ts",
"tsConfig": "angular.tsconfig.json",
"polyfills": "polyfills.ts",
"assets": [],
"styles": [],
"scripts": [
{
"input": "node_modules/document-register-element/build/document-register-element.js"
}
]
},
"configurations": {
"production": {
"optimization": true,
"outputHashing": "none",
"sourceMap": true,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": false,
"vendorChunk": true,
"buildOptimizer": true
}
}
}
}
}
},
"defaultProject": "elements",
"schematics": {
"@schematics/angular:component": {
"prefix": "app",
"style": "css"
},
"@schematics/angular:directive": {
"prefix": "app"
}
}
}
And following tsconfig.json
:
{
"compileOnSave": false,
"compilerOptions": {
"module": "esnext",
"outDir": "./download/009-angular-9-elements/dist/out-tsc",
"baseUrl": "download/009-angular-9-elements/src",
"sourceMap": true,
"declaration": false,
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "es2015",
"typeRoots": ["node_modules/@types"],
"lib": ["es2016", "dom"],
"paths": {
"EnumUtils": ["dist/enum-utils"],
"EnumUtils/*": ["dist/enum-utils/*"]
}
},
"files": ["download/009-angular-9-elements/src/index.ts", "polyfills.ts"]
}
Bundling details
Bundled with Angular CLI
Preact w/Class
Dependencies
preact : ^10.4.4
@wcd/preact-custom-element : ^3.1.3
Component size including library
Minified — Uncompressed | 11,617 |
Minified + Gzip | 4,774 |
Minified + Brotli | 4,346 |
Composition
Open Bundle Visualizer
Compilation details
All Sources have been Transpiled by WebComponents.dev compiler with the following Babel settings:
[
[
Babel.availablePresets['env'],
{
targets: {
browsers:
'last 2 Chrome versions, last 2 Firefox versions, last 2 Safari versions, last 2 iOS versions, last 2 Android versions',
},
modules: 'false',
bugfixes: true,
},
],
[Babel.availablePresets['react']],
],
plugins: [
[Babel.availablePlugins['proposal-decorators']{ legacy: true }],
[Babel.availablePlugins['proposal-class-properties']{ loose: true }],
]
Bundling details
Bundled with Rollup
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
...
input: 'source.js',
output: {
dir: 'dist'),
format: 'esm',
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
withdeps ? resolve() : undefined,
commonjs( /* { namedExports: for React } */ ),
terser({ output: { comments: false } }),
...
React w/Class
Dependencies
react : ^16.13.1
react-dom : ^16.13.1
react-to-webcomponent : ^1.4.0
Component size including library
Minified — Uncompressed | 131,430 |
Minified + Gzip | 40,901 |
Minified + Brotli | 36,008 |
Composition
Open Bundle Visualizer
Compilation details
All Sources have been Transpiled by WebComponents.dev compiler with the following TypeScript settings:
{
module: ts.ModuleKind.ESNext,
experimentalDecorators: true,
emitDecoratorMetadata: true,
lib: ['ESNext', 'dom'],
target: ts.ScriptTarget.ESNext
};
Bundling details
Bundled with Rollup
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
...
input: 'source.js',
output: {
dir: 'dist'),
format: 'esm',
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
withdeps ? resolve() : undefined,
commonjs( /* { namedExports: for React } */ ),
terser({ output: { comments: false } }),
...
React w/Hook
Dependencies
react : ^16.13.1
react-dom : ^16.13.1
react-to-webcomponent : ^1.4.0
Component size including library
Minified — Uncompressed | 131,306 |
Minified + Gzip | 40,870 |
Minified + Brotli | 36,004 |
Composition
Open Bundle Visualizer
Compilation details
All Sources have been Transpiled by WebComponents.dev compiler with the following TypeScript settings:
{
module: ts.ModuleKind.ESNext,
experimentalDecorators: true,
emitDecoratorMetadata: true,
lib: ['ESNext', 'dom'],
target: ts.ScriptTarget.ESNext
};
Bundling details
Bundled with Rollup
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
...
input: 'source.js',
output: {
dir: 'dist'),
format: 'esm',
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
withdeps ? resolve() : undefined,
commonjs( /* { namedExports: for React } */ ),
terser({ output: { comments: false } }),
...
Riot
Dependencies
riot : ^4.12.4
@riotjs/custom-elements : ^4.1.1
Component size including library
Minified — Uncompressed | 18,809 |
Minified + Gzip | 6,906 |
Minified + Brotli | 6,240 |
Composition
Open Bundle Visualizer
Compilation details
All Sources have been Transpiled by WebComponents.dev compiler with the following Riot settings:
const settings = {
scopedCss: false,
};
Bundling details
Bundled with Rollup
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
...
input: 'source.js',
output: {
dir: 'dist'),
format: 'esm',
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
withdeps ? resolve() : undefined,
commonjs( /* { namedExports: for React } */ ),
terser({ output: { comments: false } }),
...
Svelte
Dependencies
svelte : ^3.23.0
Component size including library
Minified — Uncompressed | 3,592 |
Minified + Gzip | 1,728 |
Minified + Brotli | 1,511 |
Composition
Open Bundle Visualizer
Compilation details
All Sources have been Transpiled by WebComponents.dev compiler with the following Svelte settings:
const options = {
format: 'esm',
customElement: true
};
Bundling details
Bundled with Rollup
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
...
input: 'source.js',
output: {
dir: 'dist'),
format: 'esm',
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
withdeps ? resolve() : undefined,
commonjs( /* { namedExports: for React } */ ),
terser({ output: { comments: false } }),
...
Vue.js
Dependencies
vue : ^2.6.11
vue-custom-element : ^3.2.14
Component size including library
Minified — Uncompressed | 76,860 |
Minified + Gzip | 27,176 |
Minified + Brotli | 24,357 |
Composition
Open Bundle Visualizer
Compilation details
Vue sources have been Transpiled by rollup-plugin-vue
Bundling details
Bundled with Rollup
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
...
input: 'source.js',
output: {
dir: 'dist'),
format: 'esm',
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
withdeps ? resolve() : undefined,
commonjs( /* { namedExports: for React } */ ),
terser({ output: { comments: false } }),
...
If you only deliver a single
you have the full cost of the library for a single component. This is the total cost of a single component with the library included.
The bare HTMLElement component doesn't have any dependency and creates a unmatched tiny package.
Svelte is doing also very well with a very small library runtime cost primarily due to excellent tree-shaking. This also means that as the component use more of Svelte capabilities, more of the library will be included.
Vue and React libraries do poorly on tree-shake so you pretty much have the total runtime, no matter how complex your components are. Vue 3 is supposed to offer better tree-shake support — it would be interesting to see.
Some libraries bring significant value and are more feature rich than others. It's normal to see larger sizes in these cases.
Nevertheless, for a simple counter component, we would like to see more tree-shaking happening.
On the other hand, once you start having multiple components using a broad spectrum of the library capabilities, you end up with the entire library anyway.
This is an estimated size of a bundle of 30 my-counter-like components using the same library. All components will share the library code so the estimated size is calculated with: 1 bundle-with-dependencies + 29x components-without-dependencies.
It's interesting to see that some libraries managed to be smaller than bare HTMLElement. This is achieved by sharing more runtime accross the different components. Individual components are smaller and pay for the runtime. A library is not always an overhead !
On the opposite, Svelte has a super tiny runtime but the resulting components are bigger than most solutions. Only Vue 2 and Angular components are bigger.
The benchmark page is composed of 50
laid out in a single page with the library bundle code inlined.
Take into consideration that there is a margin of error of 2ms. So the first 16 libraries are moree of less equal!
Everything runs locally so the network download time is not taken into account here.
Everything runs on a relatively powerful laptop and results could be completely different on a lower-end device like a phone or a tablet.
It's hard to find so much diversity in a technical solution. It tells a lot about Web Components and the low level API provided. All the 33 variants could be on the same page if we wanted to!
On bundle size, the results are already very promising but there is still room for improvement:
Web Components are well supported in browsers now. Still, for old browsers (including IE11), polyfills are required. The bundle sizes reported here are only for modern browsers that don't need any polyfills. It was too much additional work to include polyfills in this post. Maybe later… before they become obsolete.