Обновить
4
Vladimir@replicate_1

Пользователь

0,9
Рейтинг
Отправить сообщение

У меня - все...

Открою вам потрясающий секрет: в реальном ИТ-мире помимо нейронок и ботов существует такое понятие, как коллеги.

Когда вам по делу больше ответить нечего, в ход идут универсальные заглушки про "нейрослоп" и "это все боты". Забавно, что вы вообще рассуждаете о "дне" на фоне того, что вы пришли хамить всем подряд и проявляете поразительно аномальную активность в негативном ключе исключительно к одному автору во всех ветках.

Если в этом треде и есть подозрительные персонажи, чье поведение стоит изучить модераторам - так это вы и те, кто тут спамит ссылками на свой проект и откровенно неадекватными скриншотами.

https://habr.com/ru/articles/1019030/#comment_29772660

вы свой мол лучше почините, не отвлекайтесь на подтасовки

Я смотрю, у вас заготовлены ссылки на все случаи жизни. Вы на Хабре работаете как глобальный полифилл - в каждой ветке затычка. Видимо, дела у моля совсем плохи, раз вы выбрали такую стратегию продвижения...

Видимо, у вас синдром избирательной слепоты к веб-стандартам? Раз уж вы заговорили про таблицы совместимости MDN и мое контекстное окно.

Вот официальная поддержка для ::part() и CustomStateSet (:state), которые решают вашу "фундаментальную проблему" лоскутного одеяла

Они зеленые во всех современных браузерах. Ответьте на один простой вопрос: какое именно из моих утверждений по этим двум API вы считаете ошибочным?

Я вам напомню про вашу чушь:

  1. “регистрации глобальны… рассчитывать на них в ближайшие несколько десятков лет не приходится” - чушь

  2. “любой перенос - удаление и вставка, каскадные вызовы коллбэков” - чушь

  3. “сторонний компонент должен выглядеть в своем стиле, лоскутное одеяло” - чушь

  4. “принципиально недостижимая для веб-компонент эффективность” вашего фреймворка - читерство на виртуализации, запрещенной правилами бенчмарка

Опровержения с ссылками на MDN выше по ветке. Ни одного контраргумента от вас так и не поступило - вы лишь переходите на личности.

Тяжелые вычисления WASM конечно же логичнее выносить в Worker. Пример был концептуальным и иллюстрировал саму возможность интеграции технологий внутри Web Component. Показательно, что ни Scoped Registries, ни moveBefore(), ни правила бенчмарка вы так и не оспорили. Спорить с MDN объективно сложнее, чем с недочетами в примере кода.

И еще про виртуализацию. Вы подаете ее как уникальную фичу, но виртуализацию давно прикручивают к чему угодно: react-window, @lit-labs/virtualizer, @tanstack/virtual - все это работает из коробки. Разница только в том, что вы встроили ее по умолчанию и используете для накрутки бенчмарков, которые явно запрещают виртуализацию.

И к слову, про свободу стека. Web Component - это нативный контейнер всей веб-платформы. Один компонент бесшовно связывает WASM, Workers, Canvas и любой Web API:

class LiveAnalyzer extends HTMLElement {
  async connectedCallback() {
    // C++ скорость - WASM для тяжелых вычислений
    const { instance } = await WebAssembly.instantiateStreaming(fetch('dsp.wasm'));
    // Параллельность - Web Worker
    const worker = new Worker('pipeline.js', { type: 'module' });
    // Рендер - нативный Canvas
    const ctx = this.querySelector('canvas').getContext('2d');

    worker.onmessage = ({ data }) => {
      const ptr = instance.exports.process(data);
      const pixels = new Uint8ClampedArray(instance.exports.memory.buffer, ptr, 512 * 512 * 4);
      ctx.putImageData(new ImageData(pixels, 512, 512), 0, 0);
    };
  }
}
customElements.define('live-analyzer', LiveAnalyzer);

Пример архитектурный, но суть в том, что <live-analyzer></live-analyzer> встраивается в любой фреймворк, любой проект, без единой зависимости. Это и есть стандарт.

В целом, я понял ваши намерения. Дальше я отвечаю не вам, а читателям, потому что кто-то может принять ваши фантазии всерьез.

Писать свой проект и развивать собственный фреймворк - прекрасно. Но зачем продвигать его, обвешивая чужие технологии фейками? Разоблачение ваших подтасовок из статьи (где вы намеренно опираетесь на устаревшую или несуществующую информацию) вы предпочли проигнорировать. Вы прекрасно понимаете, что делаете. Что ж, продолжим по фактам.

Вы упрекаете авторов бенчмарка Lit в том, что они обернули всю таблицу в один <main-element>, а не создали 10 000 отдельных компонентов для каждой ячейки. Это классическая подмена понятий. В профессиональной разработке это называется разумным балансом. Web Components полностью развязывает руки инженеру: хочешь монолитный виджет для скорости на плоских данных - пожалуйста. Нужны 10 000 изолированных компонентов со своим стейтом? Стандарты W3C позволяют создать 10 000 таких компонентов за ~7ms - это один кадр при 60fps. Достаточно прямых мутаций Light DOM без VDOM:

class FastRow extends HTMLElement {
  set data(item) {
    this.textContent = item.title; 
  }
}
customElements.define('fast-row', FastRow);
const row = document.createElement('fast-row');
row.data = rowData;

Теперь про ваши “рекорды”. Вы ссылаетесь на “недостижимую эффективность” и заявляете, что бизнесу “не нужны честные 100K DOM-элементов”. Но правила js-framework-benchmark явно запрещают виртуализацию - каждая строка должна быть честно отрендерена в реальный DOM. Протаскивать туда программную виртуализацию (скрывая узлы вне экрана) в нарушение правил бенчмарка, а потом выдавать этот фокус за победу над Web Components - это банальное читерство. Любой фреймворк получит космические метрики, если не будет рендерить интерфейс целиком.

Какими жертвами достигаются эти “преимущества”? Ваша базовая абстракция - классы, генерирующие обертки из обычных <div>, полностью замкнутые внутрь вашей экосистемы. Ради приукрашенных лабораторных рекордов разработчик получает абсолютный vendor lock-in, отказ от нативной интероперабельности и привязку к маргинальному синтаксису, игнорирующему стандарты W3C. Когда инженеры уходят от React - они ищут стандарт платформы, а не очередной проприетарный фреймворк с кастомным синтаксисом и новым vendor lock-in. Сравнивать проприетарные <div>-обертки с полноценными платформенными абстракциями, доказывая их мнимую мощь нечестными бенчмарками - это попытка ввести сообщество в заблуждение.

В индустрии могут параллельно жить разные подходы. Отрицать это - обычный снобизм.

У свидетелей веб-компонент универсальные ответы… Проще говоря: не используйте веб-компоненты, иначе получите тормоза даже на таком тривиальном интерфейсе, как у Ютуба.

Называть инженеров, опирающихся на стандарты W3C, “сектой” - довольно дешевый манипулятивный прием. Особенно когда цель всего этого выпада - просто увести читателей Хабра в свой Telegram-канал и продать им свой личный фреймворк ($mol). Вы обвиняете стандарт в проблемах масштабирования YouTube, но в качестве доказательства “недостижимой эффективности” вашего инструмента приводите откровенную подтасовку.

Иронично, что собственно компоненты там [в бенчмарке Lit] и не используются, если не считать однократный бутстрап приложения… Да и нашли на кого ровняться - вот вам принципиально недостижимая для веб-компонент эффективность (ссылка на Telegram)

Если пройти по вашей ссылке-воронке в Telegram, там прямым текстом написано, что секрет вашей скорости - автоматическая виртуализация рендеринга.

Вы берете свой фреймворк (который программно прячет узлы за пределами экрана) и сравниваете его с Lit или Vue (которые по правилам бенчмарка честно рендерят в реальный DOM все 10 000 строк). Это чистая подмена понятий. Если прикрутить виртуализацию к таблице на Lit, метрики станут такими же мгновенными, потому что тормозит перерисовка гигантского DOM-дерева в браузере, а не Web Components.

К слову, разработчики Lit в js-framework-benchmark написали абсолютно грамотный код: они создают один <main-element>, а внутри мапят стейт через нативные шаблоны html. Плодить тысячи ShadowRoot для простых текстовых ячеек - это производительный суицид (аналогично созданию тысяч State-компонентов в React). Вы пытаетесь выдать следование архитектурным best practices за слабость стандарта.

Навязывать свой “велосипед” через агрессию и синтетические тесты с виртуализацией - это грязный маркетинг. В реальной коммерческой разработке бизнесу нужны не лабораторные рекорды, а предсказуемая стоимость найма, отсутствие жесткого вендор-лока и стабильный фундамент платформы. Именно поэтому архитекторы выбирают стандарты W3C, а не закрытые экосистемы с кастомным синтаксисом и огромными счетами за онбординг.

Извиняюсь, были проблемы с первой публикацией.

Вы описываете ряд проблем Web Components как фундаментальные. Но многие из них уже закрыты стандартами платформы - с документацией на MDN и поддержкой браузеров. Пройдемся по конкретным пунктам.

Если нужны другие типы данных, то нужно прикручивать какую-нибудь сериализацию, чтобы поместить их в атрибут, десерелиализацию, чтобы доставать их обратно

Здесь смешаны атрибуты (HTML-разметка, всегда строки) и свойства (JS-рантайм, любые типы). Web Component - инстанс JS-класса. Сложные объекты передаются по ссылке через свойства:

document.querySelector('my-widget').data = { user: 'Habr', roles: [1, 2] };

Как пишет open-wc: “A great benefit of properties is that they can accept any javascript value, including complex objects and arrays”.

у нас же подражание HTML, а значит ничего, кроме строк и DOM элементов передать нельзя. Сам компонент должен взять откуда-то снаружи стайлшит и пропихнуть его в свой Shadow DOM через adoptedStyleSheets. Откуда и как — ну придумайте как-нибудь, чо как маленькие.

В компонент передается любой ссылочный тип, не только строки. Стандарт Constructable Stylesheets появился в Chrome в 2019-м, с марта 2023-го работает везде (Safari 16.4+). CSS парсится один раз, инстансам раздается ссылка на CSSStyleSheet:

const sheet = new CSSStyleSheet();
sheet.replaceSync('.btn { color: red }');
shadowRoot.adoptedStyleSheets = [sheet];

Документация: adoptedStyleSheets (MDN), Constructable Stylesheets (web.dev).

Любой перенос — это удаление и вставка, поэтому disconnectedCallback и затем connectedCallback… Будут каскадные вызовы этих колбэков на всём поддереве компонент… запуск сотен-тысяч этих задач на ровном месте — штука не бесплатная.

JS-инстанс при отрыве от DOM не уничтожается, стейт сохраняется. Повторную инициализацию можно предотвратить guard-флагом:

connectedCallback() {
  if (this.initialized) return;
  this.initialized = true;
}

А платформа уже пошла дальше: Element.moveBefore() и connectedMoveCallback() решают эту задачу нативно - перенос узла без вызова disconnectedCallback/connectedCallback. MDN прямо пишет: “You could add an empty connectedMoveCallback() to stop the other two callbacks running”. Поддержка: Chrome 133+, Firefox 144+ (Safari пока нет). Документация: Element.moveBefore() (MDN).

И все эти регистрации глобальны. Кто первый встал - того и тапки… заполифилить эти реестры для современных браузеров не получится, так что особо рассчитывать на них в ближайшие несколько десятков лет не приходится.

Scoped Custom Element Registries уже реализованы и документированы на MDN. Конструктор new CustomElementRegistry() позволяет создавать изолированные реестры, привязанные к конкретному Shadow Root:

const myRegistry = new CustomElementRegistry();
myRegistry.define('my-button', MyButton);
host.attachShadow({ mode: 'open', customElementRegistry: myRegistry });

Разные shadow-деревья могут использовать одинаковые имена без конфликтов. Причем первым эту фичу зашипил именно Safari (v26) - исторически самый консервативный из браузеров. Scoped Registries включены в программу Interop 2026 (Apple, Google, Microsoft, Mozilla), так что Firefox - вопрос времени. Поддержка: Chrome 146+, Safari 26+ (Firefox пока нет, есть полифил). Документация: Scoped registries (MDN).

если вставляешь сторонний компонент в свою страницу, то он должен выглядеть не в стиле твоего приложения, а в каком-то своём уникальном, превращая всё приложение в лоскутное одеяло

Платформа добавила CustomStateSet и CSS-псевдокласс :state(). Компонент экспортирует внутреннее состояние наружу, потребитель стилизует через обычный CSS:

labeled-checkbox:state(checked) { border: solid; }

Плюс ::part() для таргетирования конкретных частей Shadow DOM снаружи. Оба API поддерживаются всеми браузерами: ::part() с 2020 года (96%+ пользователей), :state() - Chrome 90+, Firefox 126+, Safari 17.4+. Документация: CustomStateSet (MDN), ::part() (MDN).

Реальные ограничения у Web Components есть (работа с формами, например), но перечисленные в вашей статье пункты платформа уже закрыла.

Продолжу разбор остальных утверждений из статьи.

В качестве примера бойлерплейта приводится сырой HTMLElement, из чего делается вывод о переусложненности всего стандарта. Но это все равно что судить о разработке интерфейсов на чистом JS по document.createElement и ручной вставке нод в DOM - так уже давно никто не пишет.

Текущие инструменты вроде Lit решают проблему рутинного кода, добавляя реактивность и работу с шаблонами в очень тонкой обертке (порядка 6KB gzip). А новые декораторы из спецификации TC39 (закреплены в Stage 3, базовая поддержка в движках стартовала в 2024 году) позволяют убрать лишний код вообще на уровне самого языка:

class MyWidget extends LitElement {
  @property() name = '';
  render() { return html`<p>Hello, ${this.name}</p>`; }
}

Бойлерплейт raw API - не аргумент против технологии, иначе raw WebGL “доказывает”, что 3D в браузере невозможен.

создание веб-компонента на 3 порядка медленнее обычного JS-объекта… 124 байта против 16

Методологически странно сравнивать DOM-элемент с plain JS-объектом. С тем же успехом можно сказать, что document.createElement('div') “на порядки медленнее” пустого {} - это не баг <div>, а природа работы с DOM.

Корректное сравнение - Web Component против компонента React или Vue. Абстракции фреймворков (виртуальное дерево, замыкания хуков) вместе с реальным DOM-элементом занимают сопоставимый объем памяти, просто затраты спрятаны под капотом. В эталонном бенчмарке js-framework-benchmark реализация на Lit стабильно идет рядом с React и Vue по скорости рендеринга.

Что касается статической типизации, о которой “можно не мечтать” (аргумент про нетипизированные строки) - это верно только для HTML-атрибутов. Свойства Web Component - это обычные поля ES-класса. Они типизируются ровно так же, как любой другой TypeScript-код, и работа с компонентами из JS идет именно через свойства:

class MyWidget extends HTMLElement {
  data: UserProfile | null = null;
  set count(v: number) { /* ... */ }
}

Инструменты вроде Stencil вообще компилируют .tsx в нативные Web Components с полными типами.

Наконец, называть “мертворожденным” и “не снискавшим популярности” стандарт, на котором работает почти весь фронтенд GitHub (на базе Catalyst), интерфейсы YouTube, Spectrum Web Components от Adobe, Salesforce (Lightning Web Components) и даже дашборды SpaceX Crew Dragon - довольно смело. Если это критерии “мертворожденности”, то непонятно, какой тогда должен быть порог успешности технологии.

Вы описываете ряд проблем Web Components как фундаментальные. Но многие из них уже закрыты стандартами платформы - с документацией на MDN и поддержкой браузеров.

Если нужны другие типы данных, то нужно прикручивать какую-нибудь сериализацию, чтобы поместить их в атрибут, десерелиализацию, чтобы доставать их обратно

Здесь смешаны атрибуты (HTML-разметка, всегда строки) и свойства (JS-рантайм, любые типы). Web Component - инстанс JS-класса. Сложные объекты передаются по ссылке через свойства:

document.querySelector('my-widget').data = { user: 'Habr', roles: [1, 2] };

Как пишет open-wc: “A great benefit of properties is that they can accept any javascript value, including complex objects and arrays”.

у нас же подражание HTML, а значит ничего, кроме строк и DOM элементов передать нельзя. Сам компонент должен взять откуда-то снаружи стайлшит и пропихнуть его в свой Shadow DOM через adoptedStyleSheets. Откуда и как — ну придумайте как-нибудь, чо как маленькие.

В компонент передается любой ссылочный тип, не только строки. Стандарт Constructable Stylesheets появился в Chrome в 2019-м, с марта 2023-го работает везде (Safari 16.4+). CSS парсится один раз, инстансам раздается ссылка на CSSStyleSheet:

const sheet = new CSSStyleSheet();
sheet.replaceSync('.btn { color: red }');
shadowRoot.adoptedStyleSheets = [sheet];

Документация: adoptedStyleSheets (MDN), Constructable Stylesheets (web.dev).

Любой перенос — это удаление и вставка, поэтому disconnectedCallback и затем connectedCallback… Будут каскадные вызовы этих колбэков на всём поддереве компонент… запуск сотен-тысяч этих задач на ровном месте — штука не бесплатная.

JS-инстанс при отрыве от DOM не уничтожается, стейт сохраняется. Повторную инициализацию можно предотвратить guard-флагом:

connectedCallback() {
  if (this.initialized) return;
  this.initialized = true;
}

А платформа уже пошла дальше: Element.moveBefore() и connectedMoveCallback() решают эту задачу нативно - перенос узла без вызова disconnectedCallback/connectedCallback. MDN прямо пишет: “You could add an empty connectedMoveCallback() to stop the other two callbacks running”. Поддержка: Chrome 133+, Firefox 144+ (Safari пока нет). Документация: Element.moveBefore() (MDN).

И все эти регистрации глобальны. Кто первый встал - того и тапки… заполифилить эти реестры для современных браузеров не получится, так что особо рассчитывать на них в ближайшие несколько десятков лет не приходится.

Scoped Custom Element Registries уже реализованы и документированы на MDN. Конструктор new CustomElementRegistry() позволяет создавать изолированные реестры, привязанные к конкретному Shadow Root:

const myRegistry = new CustomElementRegistry();
myRegistry.define('my-button', MyButton);
host.attachShadow({ mode: 'open', customElementRegistry: myRegistry });

Разные shadow-деревья могут использовать одинаковые имена без конфликтов. Причем первым эту фичу зашипил именно Safari (v26), Scoped Registries включены в программу Interop 2026 (Apple, Google, Microsoft, Mozilla), так что Firefox - вопрос времени. Поддержка: Chrome 146+, Safari 26+ (Firefox пока нет, есть полифил). Документация: Scoped registries (MDN).

если вставляешь сторонний компонент в свою страницу, то он должен выглядеть не в стиле твоего приложения, а в каком-то своём уникальном, превращая всё приложение в лоскутное одеяло

Платформа добавила CustomStateSet и CSS-псевдокласс :state(). Компонент экспортирует внутреннее состояние наружу, потребитель стилизует через обычный CSS:

labeled-checkbox:state(checked) { border: solid; }

Плюс ::part() для таргетирования конкретных частей Shadow DOM снаружи. Оба API поддерживаются всеми браузерами: ::part() с 2020 года, :state() - Chrome 90+, Firefox 126+, Safari 17.4+. Документация: CustomStateSet (MDN), ::part() (MDN).

Реальные ограничения у Web Components есть (работа с формами, например), но основные пункты перечисленные в вашей статье платформа уже закрыла.

Информация

В рейтинге
2 218-й
Зарегистрирован
Активность

Специализация

Фулстек разработчик, Архитектор программного обеспечения
Ведущий
От 8 000 $
Git
PostgreSQL
Python
Docker
JavaScript
TypeScript
Node.js