Pull to refresh

Comments 57

Хватит уже ознакамливаться, пора использовать!
Полифилл с таблицей поддержки: https://github.com/WebComponents/webcomponentsjs
Описание создания компонента с использованием ES6: https://www.polymer-project.org/1.0/articles/es6.html + пример компонента на Polymer
И хотелось бы добавить, что в отличие от использования Реакта (и прочего такого) для декомпозиции интерфейса, веб-компоненты — это стандарт. То есть в один прекрасный момент вы просто выпилите полифилл из проекта и все будет хорошо. А вот слезть с иглы в виде изоморфного Реакт-приложения будет ой как непросто...

На typescript интереснее получается (там контроль типов можно использовать как контракты при обмене данными с сервером и сообщениями между элементами на странице), да и полимер не нужен, custom-elements вполне себе фреймворк, нарезаешь тегов под свой проект и половину программирования превращаешь в декларации. А реакт — да, другая философия. Все никак не соберусь потестить их вместе — реакт в custom-elements и наоборот, говорят уже допилили.
UFO just landed and posted this here
  1. Не ковыряя руками DOM — вы лишаете себя многих чудесных возможностей и становитесь зависимы от фреймоврка. Мне удавалось многократно увиличивать производительность приложения переписывая компоненты с фреймворков на прямую работу с DOM (свой рендер для данных). Магические байндинги и обсерверы хороши только до тех пор, пока вы не выяснили как они работают. Потом вам становится проще писать такие штуки самому, чем бороться с особенностями чужой реализации (при этом я конечно противник "велосипедов"). В том-же Polymer, к примеру, нельзя использовать выражения в шаблонах, а это порой очень засоряет код самого компонента.
  2. Polymer отлично уживается с ванильными веб-компонентами в одном проекте, и однажды запрототипированные компоненты легко переписываются в любое время под любые задачи и с использованием любого языка, транспилируемого в JS, в том числе и с использованием статической типизации. Прелесть Polymer — в том, что он не навешивает на вас обязательств вечно с ним дружить. А вот React — делает это жестко, при этом зависимыми становятся и клиент, и сервер и даже ваша IDE (сейчас конечно все поддерживают jsx, но еще недавно это было проблемой. Ну и не все любят jsx, что вполне справедливо).
  3. Что именно вы подразумеваете, говоря о "чудесном воркфлоу" Реакта? Жизненный цикл компонентов? Работу с данными? Саму разработку? Лично я вижу в нем только одну чудесную вещь: возможности декомпозиции UI. Но этот вопрос еще чудеснее решается веб-компонентами. И декомпозировать UI (UI, модули, лейауты, секции) по моему опыту, вообще мало кто умеет. Обычно я встречаю жуткую кашу в jsx из JS, HTML, кастомных тегов, какого-нибудь бутсрапа с трехэтажными БЭМами и попытки из этого собрать страницу целиком в одном месте.
Потом вам становится проще писать такие штуки самому, чем бороться с особенностями чужой реализации

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

Не согласен совершенно. Именно чем сложнее приложение, тем более справедливо то, что я говорю. И веб-компоненты вовсе не только для контролов, они хороши на любом уровне если приложение построено правильно. Просто компоненты должны быть четко разделены по классам задач, которые они решают: UI — для кнопочек, дропдаунов, слайдеров и т. д. (получают данные от родителя через параметы); модули — для блоков которые работают с логикой; лэйауты — для организации блоков интерфейса (расположение на экране, логика отображения); и секции — для роутинга и доступа к базовым параметрам приложения. Это конечно примерная схема, но лично я строю интерфейс приложения именно так. При этом, у вас есть возможность объединять все детали в один документ (что дает очень высокую скорость обращения и сокращает количество запросов к серверу) либо запрашивать отдельные тяжелые блоки как простой HTML с сервера и использовать их только при необходимости. Сборку модулей при этом разруливает сам браузер и вы получаете предельно гибкое и удобное для последующей поддержки решение. Ни один существующий фреймворк (не считая тех, что работают поверх веб-компонентов) вам этого не даст сделать так просто.

Это всё очевидно, данные то как биндить? Вариант с мешаниной калбеков не предлагать.

Никакой мешанины, все элемены (модули и их модели) созданы конструкторами соответсвующих классов, и узнают все необходимое друг о друге при создании. Модель знает о всех экземплярах (тех, что в данный момент отображены) связанного с ней компонента и вызывает его обновление через сеттеры или через специальный метод update(); Если компонентов несколько — обновляет все. Без лишних событий и проверок на правильного подписчика. Никаких колбэков, только прямой вызов метода. Колбек получается только один, нативный для веб-компонента, является частью его стандартного жизненного цикла, вызывает удаление связи с моделью при его удалении из DOM. А как вы думаете реализованы байндинги в фреймворках?

Модель знает о всех экземплярах связанного с ней компонента и вызывает его обновление через сеттеры

то есть у вас модель знает о компоненте и сама обновляет его? Это как-то… кхм, необычно))

Это круто, ибо просто и хорошо работает.

Ok, но я бы не стал называть это моделью, можно было бы назвать въюмоделью, если бы не "Модель знает о всех экземплярах", так это скорее какой-то ComponentManager, но, опять же, создаётся впечатление, что у вас эта штука не только рассылает данные экземплярам, но ещё и хранит их. В общем, чудо-юдо какое-то)). Может тудулист для примера сбацаете?

рассылает данные экземплярам, но ещё и хранит их

имеется ввиду, что хранит данные (хотя и сами экземпляры тоже).

Модель не рассылает данные, она их хранит, как и положено модели. Но помимо данных, нужных для вывода в компоненте, она хранит и список линков на экземпляры связанных компонентов. Есть понятия "пассивной" и "активной" модели. Я говорю про активную модель из MVC, это классический подход по большому счету.

По вашей фразе:


вызывает его обновление через сеттеры или через специальный метод update()

создаётся впечатление, что речь не о подписке на модель, а модель сама знает о сеттерах и метод update()


Ладно, здесь вроде разобрались, ещё вопрос про это:


Если компонентов несколько — обновляет все. Без лишних событий и проверок на правильного подписчика.

если обновляется всё без разбора, то что с сохранением позиций выделения/скролла (про скролл не уверен, в современных браузерах не замечал, но во всяких IE6 и флешах сталкивался)? В реакте это зашито в сам фреймворк, в вебкомпонентах ничего про это нет. Как-то решаете или не сталкивались ещё? Просто в реакте само устройство фреймворка таково, что приходится обновлять много лишнего, но зачем намеренно так делать с вебкомпонентами мне не понятно. Какой профит?


UPD: хотя понял, вместо одного model.on('change', ...) прийдётся делать множество подписок на изменения отдельных свойств (model.on('change:someprop', ...)), тут то первый раз и захочется биндингов, потому вы и не понимаете зачем они.

Правильное впечатление, я говорил не о EBA.


myModel.update();

вызовет условный


myComponent.modelChangeHandler();

Потому, что в myModel есть свойство


myModel.bindedDomInstances = [myComponent, myComponent2, myComponent3];

При этом не нужны проверки подписки со стороны компонента, не нужно беспокоиться о безопасности эвентов, не нужны никакие on change и все то, о чем я писал изначально. Ничего, как вы видите, не обновляется без разбора. Я прекрасно знаю зачем нужен биндинг и отлично использую его. Но иногда мне нужен быстрый DOM, который должен в реальном времени изменение модели вызывать (это всякие редакторы таблиц, списков с перетаскиванием, и т. д.). свой рендер работает гораздо быстрее. И, конечно, это вовсе не потому, что создатели фреймворков — говнокодеры, а просто в сложных случаях не всегда годится тот подход, который реализован для случаев общих. Как еще объяснить я уж и не знаю...

myModel.bindedDomInstances = [myComponent, myComponent2, myComponent3];

кто наполняет bindedDomInstances?


Ничего, как вы видите, не обновляется без разбора

как компонент узнаёт какие свойства модели, выводимые им, нужно обновить в dom-е?

кто наполняет bindedDomInstances?

  • Конструктор компонента. Когда получает ссылку на свою модель, сразу записывает в нее ссылку на себя.

как компонент узнаёт какие свойства модели, выводимые им, нужно обновить в dom-е?

  • Много способов, как вы сами понимаете. Можно через сеттер свойства модели реализовать, он ведь знает что именно записывает.

А в целом, модели ведь тоже декомпозируются, и друг-другу в итоге соответсвуют достаточно компактные блоки. Так что вполне можно избегать каких-то страшных глобальных обновлений DOM, там, где они не нужны.

Конструктор компонента

тогда всё норм.


через сеттер свойства модели

так модель может узнать изменилась ли она и нужно ли генерить событие, но как компонент узнает, что изменилось в модели? Тут нужны либо события типа 'change:someprop', либо какая-то инфа в объекте события. Дальше либо много подписок и обработчиков, либо огромное ветвление в единственном обработчике. Дальше опять биндинги.

Сеттер свойства знает какого свойства он сеттер. Зачем тут событие? Какие еще подписки? Я вам рассказываю о конкретной реализации, а вы меня пытаетесь убедить что так не сработает? Повторю свой старый вопрос, вы представляете как биндинги реализованы в фреймворках?

Сеттер модели знает, как компонент узнаёт?
Да.

Сорри, на этом пожалуй все, я бессилен.

Можно в виде кода попробовать разобраться. Как я понимаю у вас в упрощённом виде что-то вроде того: https://gist.github.com/Riim/6fe27c2ee69b13c9d1b41c48ff5ceabb
Мне не нравится, что при записи в online произойдёт две лишние записи в innerHTML (https://gist.github.com/Riim/a3fab035befe77a6c90ab4cccfe17818#file-app-js-L44-L45).

react, redux, immutable — внезапно это все можно завернуть в компонент и передавать параметры через аттрибуты и event-ы. У меня даже подключение к сокет-серверу через компонент идет. Компоненты общаются между собой event-ами. event-ы могут распространятся не только снизу-вверх, но и широковещательно для всех компонентов в room-е (да, сделал один раз такой компонент и использую) В общем обычное программирование, похоже на написание своего DSL.

Мне почему-то казалось, что Реакт вот прям так как вы написали здесь и работает.


И отдельно, что касается "raw html"… Мне почему-то кажется, что html вообще должен умереть. С развитием SPA js всё теснее будет интегрироваться с html, и в какой то момент html превратится в xaml — этакое чудо, лежащее только в исходниках. И в этот момент с jsx переехать в новые реалии будет очень просто.

Реакт работает так, но несет в себе кучу избыточных сущностей для обслуживания самого себя. Я про то и говорю, что те задачи, которые решает Реакт можно решать без него ни капли от этого не страдая. С веб-компонентами вы можете захостить свое приложение на GitHub, сделать его презентацией используя vulcanize (один файл без внешних зависимостей, даже картинки в SVG будут внутри), собрать одну вьюху для Electron и для веб и тд. и тп. Вам не обязательно нужен сервер, вы можете делать приложения без бекэнда и использовать только API сторонних сервисов. И так Реакт уже не работает.


А древовидный статический HTML — да, должен умереть. И в случае с веб-компонентами он используется, в основном, для определения кусков шаблона, т. е. вполне адекватно.

Мне кажется, вы всё же немного путаете Реакт с его инфраструктурой. На сегодняшний день webpack-ом собирается react вместе с css в файл мой_апупенный_апп.js, который подключается в тег script и может "хостится на гитхабе". Туда же можно подключить и react-router (хотя это не обязательно). Туда же можно подключить flux библиотеку (хотя это тоже не обязательно). Конечно, этот js и весить будет опупенно, но разговор же не об этом.
Впрочем, что касается бэкэнда, то большинство js spa фреймворков его не требуют. Или Angular, Backbone, Knockout не могут работать только на чужих апи?.


Я честно, не вижу принципиальной разницы между тем и этим. Подходы похожи, функции похожи, выбор определяется только вкусом и модой — кого-то бесит jsx, а меня, например, знак $.

Подходы разняться тем, что в одном случае вам нужен Реакт, а в другом нет. Да, в итоге мы получаем примерно одно и то-же. Но без Реакта мы не имеем дополнительных зависимостей. Слезть с Реактовских "рельс" в сложном проекте, в определенный момент станет практически невозможно. В случае с изоморфным приложением — зависимость еще сильнее, и вам уже нужно заморачиваться с кучей вопросов на сервере (выдачу придется кэшировать, рендер в реальном времени будет очень медленным). А веб-компоненты — это стандарт, который скоро будет поддерживаться всеми браузерами. И собирать компоненты будет браузер, нативно, и соответсвенно максимально быстро и оптимизированно, не в JS рантайме. Так если нет разницы в результате (условно говоря), зачем увеличивать технический долг?

Да, фигачили как-то приложение в Реакте и потом долго придумывали как реализовать кэш с Redis. На довольно мощном железе тормозило (вывод каталога по фильтрам). Бекэндом не я лично занимался, но ребята неглупые вроде.

Какая нагрузка была? Сколько рендеров, скажем, в минуту?

Точно не скажу (не я лично этим занимался, как я говорил), но нагрузка была невысокая. Вообще я довольно много встречал жалоб на тормоза Реакта в node.js, не думаю, что это какой-то особый инсайт нашей команды.

Кстати, с неделю назад 2гис запустил новый проект http://skver.2gis.ru/, сделанный как раз на реакте с изоморфностью. Пообщался с одним из разработчиков, он говорит, что одна нода спокойно держит всю нагрузку, она (нагрузка) по сравнению с основным проектом конечно небольшая совсем, но при росте ещё можно приручивать кеш и масштабировать рендеринг на несколько нод. Так что не так уж всё и плохо с реактом как вы говорите, в теории, действительно, реакт должен рендерить медленнее классических шаблонизаторов, но в прямых руках он вполне годен для таких проектов.

Queueing 3.89 ms
Stalled 7.71 ms
DNS Lookup 2.18 ms
Initial connection 10.57 ms
SSL 8.08 ms
Request/Response TIME
Request sent 0.20 ms
Waiting (TTFB) 4.09 s
Content Download 17.53 ms


Waiting (TTFB) 4.09 s!!! Вжопу такое SSR :)

В изоморфных приложениях рендерящий сервер сам ходит во все АПИ, скорей всего большая часть этого времени — как раз такие запросы, если бы сам рендеринг на реакте занимал хотя бы десятую часть этого времени, сервер бы просто лежал, но вообще да, 2gis.ru выскакивает ощутимо быстрее даже на глаз. В общем, я отправлю им ссылку на это обсуждение, может расскажут что-нибудь. В любом случае, проект считай вчера запущен, на таком этапе это нормально и причины могут быть самые разные.

В жаваскрипт комьюнити всё же договорились использовать слово «универсальные» вместо «изоморфные» :)

Я конечно люблю реакт, и достаточно плохо отношусь к спеке вебкомпонент :) Но я ещё ниразу не видел чтобы кто-то нормально реализовал SSR на реакте так чтобы это было хотябы на приемлемом уровне с точки зрения скорости, ну и особенно когда дело доходит до UX. Лет пять назад когда для решения этой же проблемы тупо писали два куска кода, один для генерации на сервере, другой на клиенте для progressive enhancement, всё было гораздо лучше. И пока с сервера приходил тяжёлый кусок жаваскрипта, с помощью маленького скрипта внедрёного прям на страницу, контролы собирали эвенты, демонстрировали какой-то фидбэк пользователю. Сейчас же все начали делать полное гавно в попытках писать универсальный код, который в итоге ещё и сложнее реализовать, тк накладывает кучу ограничений на жаваскрипт код.

И еще забыл добавить насколько "чудесны" реактовские роутеры с этими их линками...

react-router не имеет отношения к react в плане UI. Вы можете использовать react без роутеров. Или использовать react-router вместе с webcomponents. Или использовать react с любым роутером, который вы планируете использовать с webcomponents.
Да и в принципе, если использовать какой-нибудь redux можно не использовать роутинг вообще.

Ну да, все верно, но "осадочек то остался" =)

Поддержу предыдущего оратора + добавлю — в статье ничего не говорится о webcomponents, кроме заголовка. Три экрана рассуждений о стилях — и ни одного упоминания о том как они внезапно станут тегом subscribe-form. Автор — оденьте шляпу нуба и перечитайте статью — ничего не понятно. (лично мне не надо объяснять — я эту технологию активно использую)
Моя разметка и стили спрятаны внутри веб-компонента с помощью возможностей, которые предоставляет Shadow DOM спецификация.

Хотелось бы узнать, что это за возможности

UFO just landed and posted this here

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

Через параметры только строки/числа, ссылосный тип, как в реакте, уже не передать, прийдётся вызывать метод, что не так удобно.

Ну с компонентами можно общаться не только с помощью методов. События никто не отменял, а конкретно использование CustomEvents с передачей ссылки в качестве параметра.

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

Для просто передать, это избыточное решение, согласен.

Но вот когда компонентов становится много и появляется лапша между событиями, методами и callback в них, становится каша. Со временем становится понятно, что с DOM-объектом, надо общаться именно как с DOM-объектом, т.е. используя параметры и события. И custom-element является частью именно DOM. Мухи отдельно, котлеты съелиотдельно.

Но это в ситуации с нативными веб-компонентами.
UFO just landed and posted this here
Интересно узнать: а для чего вам такие компоненты?

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

Да, вы можете сделать именно так. С одним нюансом:


<article-author name="John" surname="Daw"></article-author>

Кастомные теги, в названии, должны содержать "-". Так браузер узнает что это именно веб-компонент.

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

Можно конфигурировать элементы атрибутами, причём значения могут быть числом, строкой, и даже объектом или массивом. Булевые значения тоже, они определяются наличием атрибута.

И да, итерации тоже есть
В текущее время с WebComponents(речь про нативные) есть следующие проблемы.

1. Не совсем стабильная спецификация. Это про slot-based ShadowDOM или как по другому вроде называется ShadowDOM v1. Поддержки slot-based еще нигде нет, но заявлен на нее переход. Что со старым вариантом будет, мне неизвестно. Но думаю тоже самое, что и с CSS псевдоэлементами, которые работают с ShadowDOM => т.е. deprecated.
2. Достаточно плохая производительность ShadowDOM v0, что и стало поводом для создания slot-based ShadowDOM (v1)
3. Как уже писал выше, есть серьезные проблемы с CSS и ShadowDOM в chromium-based браузерах. Причем со скоростью отрисовки.
4. В текущей реализации в chromium-based браузерах, есть ощущение того, что ShadowDOM было сделано костылем поверх текущей реализации DOM. С другой стороны, благодаря этому возможно сделать аналог обычной html-таблицы на веб-компонентах. Но это если делать сложную структуру из веб-компонентов. В 90% ситуации вы с этим не столкнетесь.

В общем, пока стоит использовать полифилл, т.к. и спецификация нестабильна и реализации не без проблем.

Но при этом всем WebComponents это реально удобная вещь.
Всё равно использовать эти компоненты еще слишком рано. Считаю, что кроссбраузерность важнее всего
>.form__item

В чем соль двойного подчеркивания?

Тогда у меня свой стиль BEM :)
Sign up to leave a comment.

Articles