Комментарии 90
Ещё одна проблема, ставшая для меня наиболее болезненной — колбеки жизненного цикла в Edge срабатывают асинхронно, во всех остальных браузерах синхронно. На первый взгляд мелочь, но когда на веб-компонентах написаны не просто кнопочки/селекты, а всё приложение (и довольно не маленькое), тогда эта мелочь начинает периодически вылазить в виде разных хитрых багов. И самое неприятное, что баги эти чинятся только оборачиванием нужного куска кода в setTimeout(..., 0)
, что добавляет ещё больше асинхронности продолжая цепочку багов.
Решал на уровне фреймворка продублировав часть механизмов для Edge и заставив колбеки в нём работать синхронно. Проблему с разным порядком инициализации из-за разного порядка вызова define тоже решил, всё инициализируется в порядке вложенности вне зависимости от других условий.
Ещё одна неприятная мелочь — при перемещении элемента происходит вызов disconnected+connected. Если, например, это сортировка большого списка, каждый элемент которого компонент, то происходит совершенно бессмысленное срабатывание огромной кучи отписок+подписок. Опять же решил на уровне фреймворка: disconnected хоть и срабатывают друг за другом синхронно, но перед ними всеми ставится один nextTick (в этом месте он совершенно не мешает) и если до его срабатывания элемент возвращается в документ, то вместо пары elementDisconnected+elementConnected срабатывает elementMoved. То есть и на перемещение элемента по-прежнему можно отреагировать и лишние отписки/подписки не гоняются туда-сюда.
Проблема с кнопкой в форме легко решается созданием компонента формы автоматически подставляющего невидимую кнопку отправки — пустой класс и три строчки кода в шаблоне.
Проблемы с label не было так как изначально благоразумно отказался от использования ShadowDOM (по этой же причине вряд ли будут проблемы с CSP). Но вот слоты мне понравились, продублировал их в виде компонента без ShadowDOM.
В общем, там ещё много разных шишек набил, зато последние года три кайфую.
Спасибо за комментарий!
Во-первых, странно что у вас веб-компоненты в Edge вообще работали, потому что caniuse и MDN показывают что поддержка только начиная с версии 79, который Chromium и от него не должен отличаться в принципе. Или у вас есть другая информация?
А по остальной части комментария я соглашусь – всегда можно завернуть код в свои абстракции, которые работают нормально. Но есть один нюанс: изначально вся эта затея с веб-компонентами начиналась во имя избавления от лишних слоёв и фреймворков, чтобы все было просто и нативно. А тут вся выгода куда-то исчезает.
странно что у вас веб-компоненты в Edge вообще работали
вот этот полифил с самого начала использую: document-register-element.
— ваша форма не отправляется потому, что вы отнаследовали свой компонент от div, а не от button. Сделайте правильное наследование и будет вам счастье
— CSP не запрещает использовать inline-styles, это гибко настраивается, можете точечно разрешать или запрещать любое ограничение безопасности. Складывается ощущение, что автор ни разу не использовал CSP, раз пишет такую чушь
— по поводу порядка вызовов, он не гарантируется спецификацией, соответственно в каждом браузере может быть реализован по разному. Не забывайте, это фронтенд, а не безопасный контролируемый бекенд, мы программируем под 100500 устройств и программ одновременно, поэтому завязываться на недокументированное поведение — очень плохая идея в любом случае. Кроме того, как источник этого поведения вы приводите даже не браузер, а полифил, написанный энтузиастами, в котором может быть сколько угодно багов. Если вам не нравится его работа — используйте другой полифил или напишите свой, хотя в этом сейчас почти нет нужды, ведь веб-компоненты уже поддерживаются всеми последними версиями основных браузеров
ваша форма не отправляется потому, что вы отнаследовали свой компонент от div, а не от button. Сделайте правильное наследование и будет вам счастье
Одного наследования не хватит, надо будет ещё и использовать компонент по особому: <button is="my-button">
. А тут уже и до <button class="my-button">
недалеко. Какая тогда вообще тут польза от использования веб-компонентов?
CSP не запрещает использовать inline-styles, это гибко настраивается
Что значит "гибко настраивается"? Чтобы использовать inline-styles нужно прописать 'usafe-inline', что убивает изначальную пользу от внедрения CSP в целом. Вот тут на MDN об этом предупреждение есть.
Не забывайте, это фронтенд
Не забывать, что он кактус и колючий? В чём тогда смысл его есть и колоться? Тем более что альтернативы есть, и работают они на порядок лучше, и граблей с ними меньше.
Вводим текст, нажимаем Enter, данные отправляются на сервер, никакого JavaScript. При желании можно избежать перезагрузки страницы, и сделать отправку данных через AJAX, но и в этом случае количество JS будет минимальным.
если вы используете свою кнопку зарегистрированную customElements, значит без JS уже не обошлось. api браузерных элементов закрыт для изменений, но открыт для расширения. Формы можно программно сабмитить с помощью FormData. Если у вас своя кнопка, то компонент формы тоже может быть целесообразно создать свой.
Вот только при подходе "раз без JS уже не обошлось, можно сделать свою форму" зачем вообще нужны веб-компоненты?
в частном у элементов использующих Validation API есть например такая особенность, что если вы задали валидатор то он сразу срабатывает, т.е. делает пустое поле невалидным если оно должно быть заполненным, т.е. сходу подсвечивает ошибкой если они у вас подсвечиваются. Вот эту проблему используя свою форму можно обойти без танцев и костылей с цсс и жс например.
Что-то я не уверен насчёт "менее вычурного способа", в моём понимании как раз фреймворки выходят более простыми, хотя бы потому что их как раз для упрощения и делают.
Веб-компоненты же нужны для создания независимых от фреймворка переиспользуемых компонентов, и вот как раз эту независимость и переиспользумость и убивает необходимость использования особой формы.
«Использование особой формы» позволит вам сделать, все что требуется более изящно и управляемо и это как раз сильная сторона веб-компонентов, что вы любой кусок страницы можете завернуть в кастомный тег и закрепить за ним класс с жизненным циклом. Т.е. можно было самбит формы сделать добавив onclick и onkeypress обработчики прямо в глобальном скоупе тега скрипт, но это будет выглядеть как костыли, а завернутое в кастом элемент уже не будет.
«Использование особой формы» позволит вам сделать, все что требуется более изящно и управляемо и это как раз сильная сторона веб-компонентов, что вы любой кусок страницы можете завернуть в кастомный тег и закрепить за ним класс с жизненным циклом.
Неа, не могу: надо ещё и вокруг этого куска по-плясать, форм там кастомных наставить.
Если бы оно работало без "обвеса" — это было бы одно, а с "обвесом" я и на jquery чужие компоненты использовал, довольно успешно...
есть какой-то специальный способ дорабатывать стандартные элементы навроде аттрибута is, но я не пробовал с ним работать и не уверен, что это правильный подход. В прошлом были фреймворки навроде prototype, которые прямо патчили браузерное апи, но дело с ними как-то не пошло
Ну да, там вообще ничего нет, но это не мешает делать компоненты, которые работают с минимальным "обвесом".
я бы сказал что у вас приведены типичные ошибки разработчиков, а не технологии
Я с этим и не спорю. Хороший разработчик сможет решить эти проблемы. Более того, у меня в статье приводятся варианты решения для каждой. Но еще более хороший разработчик подумает, зачем ему сдалась технология, в которой ему нужно заново переопределять функциональность базового HTML, и откажется от этой технологии.
В этой ситуации два веб-компонента должны взаимодействовать друг с другом. Обычно это делается в connectedCallback. Веб-компонент подключается в DOM и осматривается вокруг. В случае подобных композитных компонентов может иметь значение, на каком компоненте этот метод вызовется первым. Проведем тест:
просто надо учитывать, что html это динамическая среда, компоненты могут не только произвольно появляться, но и также исчезать из контекста браузера, поэтому они должны быть друг от друга максимально независимы, даже если образуют иерархию и взаимодействовать несвязывающими способами
Оказывается, порядок регистрации элементов влияет на порядок вызова connectedCallback. В практическом смысле это означает то, что мы не можем знать порядок вызова методов, и наш код должен быть готов обработать оба варианта. С вариантом «нас вызвали слишком рано» все просто, добавляем window.setTimeout делаем нашу инициализацию попозже. В случае «нас вызвали слишком поздно» ситуация хуже, мы уже не сможем отменить начатые операции. Поэтому на веб-компонентах не получится сделать нормально работающий компонент спойлера
компоненты могут выбрасывать эвенты вида «я загрузил данные», другие компоненты могут на них подписываться и начинать работать только вовремя без таймаутов. Технологии вебкомпонентов как раз хороши в том, что оно впервые за 20 лет развития фронтенда позволяет добиться такой работы без setTimeout.
они должны быть друг от друга максимально независимы
Проблема в том, что у этой независимости есть цена. Там, где с нормальным порядком коллбеков понадобится один проход чтобы отрендерить всю страницу, в случае случайно возникающих коллбеков понадобятся дополнительные обработчики на каждый connectedCallback случившийся внутри DOM-дерева, чтобы проверить, не нужно ли нам обновиться ещё раз
А что, содержимое веб-компонентов не требуется рендерить?
Ну так "рантайм для жизненного цикла" — это наиболее простая часть фреймворков, которая как раз и не требует никаких диких ресурсов.
Как будто то, что реализовано на уровне платформы, ресурсов не требует...
А можете напомнить, в каком году в рякте последний раз менялась "шина"?
Это уже не "раз в год", но тем не менее — а что вы, простите, понимаете под "шиной"?
В реакте касательно биндинга данных к элементам за последние годы ничего особо не поменялось. Добавились хуки, но это не «поменялось», в том значении, которое вы подразумевали.
Возможно вы имели в виду, что в экосистеме реакта меняли подходы к организации дата-флоу?
Можно сказать и так. Но они менялись и для других фреймфорков (vuex, ng-rx и т.д.). Не реакт эти изменения инициирует, не на нем одном эти изменения и отражаются.
Вот ангуляром можно было пользоваться без ng-rx разрабатывая полноценные приложения, потому что там просто сервисы и инжектор, которые проблему интеропа между компонентами решали. Vue скорее всего тоже как-нибудь зажмурившись. А вот как наладить взаимодействие между компонентами и переиспользование компонентов бизнес-логики в реакте без подсистем что я перечислял?
никто же не использовал реакт без этих подсистем
Это неправда.
А вот как наладить взаимодействие между компонентами и переиспользование компонентов бизнес-логики в реакте без подсистем что я перечислял?
Но вы же сами упомянули React.Context.
React.Context появился в фокусе массового применения по моим оценкам за последние год-два. А до того я видел множество проектов и шатаний с одной технологии из списка что я привел на другую. Причем, насколько я понял, контекст достаточно убог, т к принуждает к древовидной иерархичности и при использовании нескольких зависимостей приходится заворачивать их друг в друга. Это редкостное уродство, поэтому скоро думаю ещё что-нибудь появится. Все лишь бы браузерными эвентами и диай нормальным не пользоваться)
насколько я понял
Вы неправильно поняли.
Сам редакс, собственно, работает через тот же контекст. И его контекст никак не принудил что-то заворачивать и использовать какую-либо иерархичность))
Можете организовывать данные так, как хотите, контекст реакта это просто шина, как вы её описали.
по моим оценкам
Ваши оценки неправильны.
Контекстом пользовались до редакса, сам редакс использует контекст, параллельно с редаксом используют контекст.
Возможно вас ввели в заблуждение куча докладов, курсов и вакансий, где «React» не пишется без "+Redux" (что действительно породило много разработчиков, которые на собеседованиях на вопрос «зачем вы использовали редакс в вашем проекте?» отвечают «не знаю»).
Но это больше «хайп», так скажем. Много менее заметных людей обходятся без этого.
не видел
Что никак не указывает, что их не было.
самоуверенно все это туманное прошлое отрицается
Люди совершают ошибки и вполне нормально перестать их совершать. Лично меня это совсем не удивляет, мы должны были прийти к этому, учитывая, что в самом туториале редакса уже достаточно давно написано:
Not all apps need Redux. Take some time to think about the kind of app you're building, and decide what tools would be best to help solve the problems you're working on.
+ Статья от Дэна от 2016 года про это:
medium.com/@dan_abramov/you-might-not-need-redux-be46360cf367
когда вы заворачиваете один сервис в другой что-бы предоставить компоненту который будет в них завернут два сервиса
У вас остается полное право ничего не заворачивать. Я слабо понимаю, как это связано с контекстом реакта.
полностью динамически и нетипизированно связываемом коде
У вас остается полное право использовать TypeScript. Я слабо понимаю, как это связано с контекстом реакта.
У вас остается полное право ничего не заворачивать.
как тогда получать доступ к методам и данным сервисов?
У вас остается полное право использовать TypeScript.
даже вендорлок на технологию микрософта тут не очень поможет, пример ниже это просто хешмап (нетипизированная структура) уязвимый к ошибкам неконсистентности:
const MyContext = React.createContext(/* some value */);
MyContext.displayName = 'MyDisplayName';
как тогда получать доступ к методам сервисов?
ru.reactjs.org/docs/hooks-reference.html#usecontext
const MyContext = React.createContext(/* some value */);
MyContext.displayName = 'MyDisplayName';
Я не понял, что вы хотите показать этим примером. Я думаю, что вам нужно ознакомиться с тем, как пользоваться контекстом реакта.
Покажете это демо?
html это динамическая среда, а вы опять лезете туда городить компиляторы, инлайнинг стилей создает проблемы для их переопределения, поэтому как и другие ресурсы типа картинок, стили лучше подключать из css файлов прямо в теневое дерево элемента.
Речь идет не про <div style="...">
а про <style>...</style>
. Unsafe-inline запрещает оба.
Почему не подключают внешние файлы в ShadowDOM, вопрос хороший, но ни один из популярных веб-компонентных фреймворков так не делает. Все пользуются <style>...</style>
Мой пример показывает, что динамические стили тоже запрещает: https://fish-hail-fernleaf.glitch.me
Именно на этом и спотыкаются LitElement и Stencil.
Я не встречал ни одной проблемы, которая не имела бы простого решения. Я не встречал ни одного непреодолимого препятствия.
Я тоже. На все проблемы находилось решение. А в конце я подвел общий итог, сколько костылей у меня получилось по сравнению с обычным HTML/CSS/JS без веб-компонентов. И веб-компоненты проиграли. Нет ни одной объективной причины их использовать, кроме желания поиграться с этой технологией.
Хорошая попытка, но это решение работает только в Хроме. В остальные браузеры (Firefox, Safari) еще не завезли.
В статье скорее обзор реальной ситуации. Стандарту уже 8 лет, а мы все так же сидим и ждем браузерной поддержки как и в 2012 году. И нет никакой гарантии, что после фикса form-associated-custom-elements не выползет чего-то ещё.
Стандарту веб-компонентов в целом. Я отсчитываю от даты этого документа: https://www.w3.org/TR/2012/WD-components-intro-20120522/
Изначальный анонс веб-компонентов и начало хайпа было в 11 году. Вот видео: https://vimeo.com/33430613
Я понимаю, что стандарт с тех пор сильно поменялся, но отправная точка этой идеи "все эти фреймворки вам не нужны, потому что у вас будет нативное API" начались именно тогда.
1. ранние веб-компоненты были уродливы, там было много ошибок включая html imports, когда весь код компонента заворачивался в один хтмл файл и старомодный стиль кода на хешмапах (обжектах) вместо классов и модулей. Поэтому это все пресеклось вместе со смертью полимера. Правда многие другие фрефмворки успели понахватать анти-практик.
2. Одновременно с веб-компонентами появилась мощная компания на продвижение тогде еще только реакта, когда на каждой конференци все слоты были заняты докладами про рекат и в компаниях все ринались все на нем переписывать. Благодаря усилиям ее сторонников эти фреймворки разработанные поперек веб-компонентов заняли весь рынок фронтенд разработки. Т.е. там были локальные завихреня типа фейла ангуряра1 который сделал реакт монополистом и не очень удающихся попыток продвинуть убогий vue.
нынешние веб компоненты v1 это вместе с современным джаваскриптом это совсем не те вебкомпоненты что были ранее, они отличаются также как ангуляр2 от первого
Я на протяжении уже двух статей рассказываю о недоработках этого стандарта, привожу ссылки на Github issues, то есть недостатки официально подтверждены авторами.
И каким образом существование других фреймворков мешает авторам веб-компонентов работать над улучшением своего стандарта, чтобы сделать его более конкуретноспособным?
Веб-компоненты в реальном мире (часть 2)