Pull to refresh

Comments 16

результатом ее работы является не специальный объект (как в lit), а именно HTML, в виде строки.
Это должно дико тормозить, разве нет?

Нет, все наоборот. Императивное создание элементов работает существенно медленнее чем парсинг HTML, если вы об этом. Помимо этого, парсинг шаблона компонента и его репликация при создании экземпляра - это разные этапы работы.

Пример абсолютно ненаглядный: разница в 10 строк практически не заметна. При этом в глаза бросается магия в виде init$, this.$.foo и тому подобное, а также невозможность выразить эти конвенции в Typescript.

Пример абсолютно ненаглядный

Всем не угодишь. Вы можете ткнуть в любой пример из песочницы Lit, а я приведу вам аналогичный пример на Symbiote.

На сайте Lit, сразу же на главной странице есть пример с декораторами. Что по ощущениям, должно сильно снижать количество бойлерплейта в подобных примерах.

Хороший аргумент. Декораторы действительно очень помогают в борьбе с бойлерплейтом. Но, мне кажется, что разработчики Lit не используют декораторы в своей песочнице ровно по той-же причине, по которой их пока нет в Симбиоте - они не поддерживаются в браузерах. Для их поддержки вам необходим TypeScript или Babel. А так как Симбиот позиционируется как библиотека для создания встраиваемых решений, это означает, автоматически, наличие дополнительных требований к окружениям разработки и средам интеграции. Поэтому, Симбиот остается агностиком по максимуму, в этом и есть главная идея его философии.

Забавный факт: сейчас проверил, у Симбиота без декораторов строк получается +/- столько-же, сколько у Lit с декораторами.

В Ваших примерах, количество строк на таком объеме сильно зависит от стиля написания кода, что как бы не совсем объективное сравнение.

Правда одно из существенных отличий в этих примерах я вижу в том как объявляются шаблоны. Метод render в Lit обладает контекстом this и следовательно для него будет работать типизация, подсказки редактора, линтеры и все прочее. Помимо этого, это также снимает сразу множество вопросов по композиции шаблонов.

Для шаблонов в Symbiote без какого-то дополнительного туллинга, как у того же angular, может стать больно. И совсем не очевидно как составлять сложные компоненты, с условиями, списками и т. д. То есть порог входа как-будто становится сильно больше чем у Lit. Но тут вопрос конечно в дизайне, и в том какую проблему этим решали.

Но это так, просто мнение после первого взгляда. В целом спасибо за статью, было интересно ознакомиться.

сильно зависит от стиля написания кода, что как бы не совсем объективное сравнение

Ну блин, ну серьезно, я способен воспроизвести стиль кода, это не какая-то сверхзадача. Вполне объективно. А если вы о объеме кода всего приложения - то в статье об этом есть отдельное упоминание. Но ок, не верите мне - проверьте сами.

Метод render в Lit обладает контекстом this

В своей статья я буквально заявляю, что для меня это недостаток, а не достоинство. Но невозможно в одном материале сделать акцент сразу на всем и в деталях раскрыть почему именно. В общих чертах я попытался это сделать. Я довольно много работал с Lit, чтобы говорить об этом. У абстрактных шаблонов больше преимуществ в тех контекстах, с которыми я сталкиваюсь на практике, об этом я тоже написал. С другой стороны, функция html имеет свою сигнатуру и типизацию, а, соответственно, и подсказки редактора, линтеры и все прочее... Вопрос с выводом типов стейта - более сложный, поскольку в Симбиоте это динамический объект. Здесь также две чаши весов, со своими преимуществами и недостатками, как у слабо-связанной и сильно-связанной архитектуры.

Для шаблонов в Symbiote без какого-то дополнительного туллинга, как у того же angular, может стать больно. И совсем не очевидно как составлять сложные компоненты, с условиями, списками и т. д.

Не понятно с чего вы это взяли. Что сложного в композиции шаблонного литерала? Что сложного в списках:

MyComponent.template = html`
  <div itemize="userList">
    <div>{{firstName}}</div>
    <div>{{secondName}}</div>
  </div>
`;

История Симбиота начинается с тех времен, когда у Lit был еще экспериментальный статус. Тогда основным мотивом того, чтобы попробовать пойти своим путем, было то, что либа-прородитель Симбиота показывала существенное преимущество в производительности: ~ 30% быстрее при первичной отрисовке UI и ~ 50% при обновлении данных. Потом фокус был смещен с производительности на возможности композиции в рамках DOM. Я это к тому, что вся цепочка решений в эволюции Симбиота была с постоянной оглядкой на то, что происходит с Lit и другими либами. И вопрос DX никогда не выходил из рамок базового фокуса.

LitElement

Я бы всё же заменил LitElement на Lit. Потому что LitElement - это конкретная сущность из Lit, класс-обёртка над HTMLElement. Помимо этого есть и другие сущности, которые все вместе объединены в библиотеку. В статье речь идёт именно о сравнении с библиотекой в совокупности, а не с конкретной сущностью.

Согласен. Я название LitElement использовал, наверное, по инерции, когда он только появился, еще во времена Polymer, авторы так сами называли либу.

LitElement использует Shadow DOM для всех компонентов по умолчанию. Это поведение можно отключить, но функции определения внешнего верхнеуровневого теневого корня и добавления стилей в него, у него нет.

Не до конца понял мысль. Но если речь про добавление стилей на элемент, который содержит теневой корень, то это можно сделать как через статическое свойство styles при помощи селекторов :host и :host-context, так и при помощи интерфейса AdoptedStylesheet.

В Symbiote.js, как и в LitElement, есть функция-тег (html), для использования с шаблонными литералами, но, результатом ее работы является не специальный объект (как в lit), а именно HTML, в виде строки.

В Lit этот объект создаётся для хранения информации и точечного обновления DOM, поскольку Lit не использует механизмы Virtual DOM. Это позволяет при изменении данных менять их точечно, без перерисовки всего компонента. Если Symbiote возвращает строку, как там обстоят дела с перерисовками?

шаблоны Симбиота абстрактны, они не привязаны к контексту самого компонента и вы легко можете писать их в отдельных файлах

У рабочей группы веб-компонентов как раз есть идеи HTML Module Script и DOM Parts, чтобы можно было вынести шаблоны в отдельные файлы и работать с ними в браузерах без дополнительных абстракций. А пока Lit придерживается React-like стиля с размещением всего логики в JS. Хотя те же стили можно вынести в отдельный файл и использовать Import assertion для получения объекта StyleSheet.

В пакете Lit - три основные зависимости: lit-html, lit-element и @lit/reactive-element.

С аргументом про лишние зависимости согласен. Но у Lit всего 3 зависимости, и все они относятся к самому Lit и поддерживаются одной командой, то есть это не внешние сторонние зависимости. И сделано это для того, чтобы их можно было использовать в standalone-режиме, без подключения Lit. Мне кажется, что в данном конкретном случае ничего плохого в трёх зависимостях нет.

Симбиот умеет инициализировать свойства из значений CSS переменных.

А вот это интересно.

 Симбиот-компоненты умеют подключаться напрямую к контекстам данных компонентов верхнего уровня в иерархии

Если я ничего не путаю, то у Lit для этого есть пакет @lit/context, который делает что-то похожее. Но это отдельный пакет, да.

Не до конца понял мысль. Но если речь про добавление стилей на элемент, который содержит теневой корень

Нет, речь о добавлении стилей в родительский, по отношению к элементу скоуп. Это может быть как верхнеуровневый shadow root так и сам документ. Симбиот умеет работать с изолированными и внешними, по отношению к точке интеграции, стилями одновременно, и под капотом, как и Lit, использует adoptedStyleSheets.

В Lit этот объект создаётся для хранения информации и точечного обновления DOM

Symbiote, конечно-же, тоже не использует VDOM, он создает виртуальный элемент template из строки при создании самого класса компонента, и потом уже создает подписки на свойства при его репликации (создании экземпляра). То есть, все изменения вносятся максимально эффективно, без каких-либо лишних перерисовок. Проверить это можно в песочнице, открыв девтулз: https://symbiotejs.org/2x/playground/basic/ - в этом примере, меняется только содержимое текстовой ноды.

У рабочей группы веб-компонентов как раз есть идеи HTML Module Script и DOM Parts

Пока у рабочей группы есть идеи, Симбот уже поддерживает это из коробки. Не сам черновик спецификации конечно, а вещи концептуально очень похожие. То есть, буквально, поддерживает шаблоны переданные в общем документе, как HTML. Когда появится поддержка нативного API, Симбиот на него переедет.

А вот это интересно.

Да, например, можно делать вот так: https://symbiotejs.org/2x/playground/css-data/

Если я ничего не путаю, то у Lit для этого есть пакет @lit/context

С Симбиотом такого рода взаимосвязи задаются просто в шаблоне, с помощью одного-единственного токена `^`, определяющего, что свойство определено в каскадном контексте. Напрмер:

let template = html`
  <button ${{onclick: '^upperLevelClickHandler'}}>Click me!</button>
`;

Или, аналогично, в HTML:

<button bind="onclick: ^upperLevelClickHandler">Click me!</button>

Никакие дополнительные пакеты не нужны. Установка связей между компонентами, причем сложных связей, даже между компонентами от разных поставщиков - это и есть смысл существования этой библиотеки.

Нет, речь о добавлении стилей в родительский, по отношению к элементу скоуп. Это может быть как верхнеуровневый shadow root так и сам документ. Симбиот умеет работать с изолированными и внешними, по отношению к точке интеграции, стилями одновременно

Технически, в Lit тоже можно так сделать.

  1. Отключить у компонента Shadow DOM через переопределение createRenderRoot

  2. Добавить в разметку компонента <style> с селектором :host, :root { ... }

Таким образом стили применятся к ближайшему теневому корню или документу. Справедливости ради, это выглядит как костыль, тем не менее, так можно сделать. Однако пока мне не понятна практическая область применения этой фичи. Обычно компоненту не нужно стилизовать что-то на уровне выше себя. Но, возможно, есть какие-то узкие кейсы.

он создает виртуальный элемент template из строки при создании самого класса компонента, и потом уже создает подписки на свойства при его репликации (создании экземпляра). То есть, все изменения вносятся максимально эффективно, без каких-либо лишних перерисовок.

Примерно так же работает и Lit, он тоже создаёт виртуальный <template> под капотом. Тут лишь разница в реализации.

Пока у рабочей группы есть идеи, Симбот уже поддерживает это из коробки. Не сам черновик спецификации конечно, а вещи концептуально очень похожие. То есть, буквально, поддерживает шаблоны переданные в общем документе, как HTML.

Symbiote сейчас реализует какие-то дополнительные механизмы по обработке шаблонов из отдельных файлов и гидрации готовой разметки? Потому что вынести разметку в отдельные файлы можно и в Lit при помощи дополнительных лоадеров, я думаю. А гидрация разметки с сервера возможна благодаря Declarative Shadow DOM (с тонким полифиллом на 20 строк для Firefox). Говоря о стандартах, я имел ввиду, что со временем это будет возможно в браузере нативно, без дополнительных обвязок.

Когда появится поддержка нативного API, Симбиот на него переедет.

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

С Симбиотом такого рода взаимосвязи задаются просто в шаблоне, с помощью одного-единственного токена `^`, определяющего, что свойство определено в каскадном контексте.

Похожего поведения можно добиться в Lit при помощи нативного методаgetRootNode() и свойства host. Это можно спрятать в какой-нибудь небольшой хелпер и использовать его внутри шаблонов. Однако соглашусь, что один символ куда удобнее.

Установка связей между компонентами, причем сложных связей, даже между компонентами от разных поставщиков - это и есть смысл существования этой библиотеки.

Мне кажется, что в комплексных приложениях для этого будут использоваться менеджеры состояний или разные Pub-Sub, шины событий и т.д.

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

Все просто: лишние shadow root для каждого интерфейсного примитива (типа кнопки или иконки) - это лишний оверхед. Создание Shadow DOM - штука не бесплатная, можете попробовать создать в цикле много элементов с Shadow DOM и без, увидите очевидную разницу в скорости и потреблении памяти на страницу. Помимо этого, это вносит свои нюансы в сами подходы к стилизации. Однако, если у ваших примитивов не создается Shadow DOM, это не значит, что их нет выше. Более того, абстрактные библиотечные элементы не знают в каком именно контексте документа они используются и что там выше по иерархии. Если вы делаете UI-kit, виджет или микрофронт - вам понадобится изоляция, но только "по верхней границе". Соответственно, у вас должна быть возможность добавить стили только в соответствующий изолированный скоуп. Селектор :root в этом случае, не может быть использован для этих целей в общих стилях документа. Не думаю, что это очень узкие кейсы.

Примерно так же работает и Lit, он тоже создаёт виртуальный <template> под капотом. Тут лишь разница в реализации.

Да, но формат самого темплейта - это разница принципиальная, в одном случае вы можете использовать HTML вне, непосредственно, JS рантайма, а в другом - нет.

Потому что вынести разметку в отдельные файлы можно и в Lit при помощи дополнительных лоадеров, я думаю. А гидрация разметки с сервера возможна благодаря Declarative Shadow DOM (с тонким полифиллом на 20 строк для Firefox). Говоря о стандартах, я имел ввиду, что со временем это будет возможно в браузере нативно, без дополнительных обвязок.

Declarative Shadow DOM это не совсем та гидрация. Гидрация - это когда браузер создает DOM на этапе парсинга HTML-документа, и с уже созданными элементами вы взаимодействуете полноценно в рамках логики своих компонентов, без каких-либо лишних перерисовок. То есть, в очередной раз, речь идет о формате описания биндингов, основанном на атрибутах, для которых вообще не нужен JS-рантайм.

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

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

Symbiote - это не полифил, у него нет цели ранней адаптации черновиков стандартов. Но при этом, вы имеете почти 100%-ю гарантию, что сможете использовать как нативные возможности так и симбиотовские API, как по отдельности так и одновременно.

Мне кажется, что в комплексных приложениях для этого будут использоваться менеджеры состояний или разные Pub-Sub, шины событий и т.д.

В Symbiote.js встроенный Pub/Sub для этих целей и используется. Как для локальных данных компонентов так и для любых абстрактных. Вполне достаточно для сложных приложений, где структура данных представляет собой динамической граф, например.

Дополню про :host-context() : это очень похоже на то, как работает интерфейс rootStyles в Symbiote.js. Отличие в том, что `rootStyles`, может работать без Shadow DOM, как основной метод стилизации, в общем случае. И поддерживается во всех современных браузерах, а не только в Chrome.

Sign up to leave a comment.

Articles