Comments 212
Но стиль ваших статей вызывает только негативные эмоции.
Благодарю за критику, замечу, что это всё же перевод. Вам не нравится сам стиль речи автора и моего перевода, или то, что опять часть статьи посвящена противопоставлению Svelte и React?
Думаю стиль автора, но раз вы перевели, то солидарны.
А сравнение выглядит как jQuery vs React, которое большей частью бессмысленно, разные вещи. Показывайте профит, если он есть, без поливания грязью упоминания "конкурентов" и все ок будет.
К сожалению, все кто пытаются рассказывать про Svelte, в той или иной степени опираются на сравнение с традиционными фреймворками. Иначе просто не ответить на вопрос — "А зачем нам ещё один фреймворк?" То, что сравнивают в основном с React, лишь говорит о его популярности и известности. По-моему, заголовок статьи вполне хорошо раскрыт и без излишних оскорблений React в этой области.
К сожалению, все кто пытаются рассказывать про <tech_name>, в той или иной степени опираются на сравнение с традиционными <alt_tech_name>.
Это заблуждение. Ответить на вопрос можно показав результаты бенчмарков или удобство конкретного подхода к задаче. Ну и конечно же рассказав про подводные камни. Без всего этого — это просто публицистика.
Вот пример статьи которая как раз хорошо рассказывает про технологию и рассказчик достаточно прошарен в ней, чтобы не брать конкретные примеры, а оперировать разными подходами и идеологиями из других языков не прибегая к самим яп: Знакомство с Python для камрадов, переросших «язык A vs. язык B» и другие предрассудки.
Для меня есть 2 вида статей о технологии:
- A vs B — в таких статьях обязательный бенчмарки и статистика сколько технологии лет, сколько пакетов, какое сообщество. То есть нормальное сравнение. Если тупо бенчей нет => публицистика.
- A only — в таких статьях показывается подход к задаче конкретно с помощью этой технологии. Описываются все плюсы и все минусы. Если начинают приплетать сравнение с другими подходами => публицистика.
- Публицистика — всё как в добрых старых рекламах: "Мы круче всех, но доказывать мы это не будем, потому что можете сами придти и попробовать. А ваш приход в сообщество резко поднимет нам количество людей в сообществе на 100%" Обычно в таких "статейках" начинают оперировать мнимым удобством на спичках при этом вообще не показывая минусов.
Если кратко, то вы не увидели союза "или" в моём высказывании.
— В React версию добавили div, import и отформатировали по атрибуту на каждой строке. Данные можно хранить как через хуки, так и в state. В чем разница по количеству кода — ну в React надо хендлер явно указать, а там прям какая-то магия связывания. По моему опыту — эти handler — очень малая часть кода.
В данной статье эти пара абзацев про разное количество строк кода отнюдь не главная мысль. Похоливарить на эту тему можно в предыдущей статье авторства Rich Harris.
Вот именно, что в той статье в комментариях были разумные замечания на эту тему. И здесь наступают на те же грабли.
А если опустить часть статьи про компактность кода, то аргументация статьи в целом проседает и уже не выглядит такой убедительной.
Аргументация про реактивное программирование проседает?
Все ж про более понятный код компонентов Svelte, тут в достаточно утрированном виде, для обывателей рассказано. Можно опять начать спорить, но вся конкретика уже была в упомянутой выше статье и там каждый остался при своём мнении.
Я к тому, что если у автора проседает аргументация в одном месте, то и статью целиком сложно воспринимать серьезно. Видно, что автор топит за свою любимую технологию, а значит и обзор получается предвзятым.
Я не считаю, что она проседает — поверхностна, да. Но цели углубляться в эту тему в этой статье не было. Для меня структура компонентов Svelte3 сильно лаконичнее и понятнее, чем у любого другого фреймворка. Вот интересно, если бы отписался кто-нибудь, кто не трогал ещё ни Svelte, ни другие топовые фреймворки, со времён JQuery. Какой код ему понятнее?
Если хотите прямо фактов — напишите свой канонически верный вариант на React и посчитаем символы, а не строки. Всё равно букв у вас будет больше, как ни старайтесь. Но, что это докажет вам или мне?
Прошлые статьи автора были в том числе и про React. Теперь попробовал Svelte. Так что автор не голословен, что-то для себя нашёл в Svelte, раз написал такую длинную статью.
Насколько я видел, кто работает со Svelte предпочитают решать эту проблему явным присваиванием. Например array.push(3)
пишут как array = [...array,3]
. Но я не вижу причин, почему бы не использовать ImmutableJS для этого, если кому-то так удобнее.
Так ведь суть ImmutableJS — что он предлагает неизменяемые объекты? Т.е. все преобразования выдают новый объект, который уже можно присвоить через =
.
const { Map } = require('immutable');
const map1 = Map({ a: 1, b: 2, c: 3 });
const map2 = map1.set('b', 50);
map1.get('b') + " vs. " + map2.get('b'); // 2 vs. 50
В js есть прокси, это убирает проблему setState, разработчики не хотели их вводить из за обратной совместимости, почему в Babel нет я уже и не найду. Замена кода на комп лятор в js похожа на золотой унитаз и сводит на снова в дискуссию компиляторы Vs джиты, где как известно победит aot, и окажет мы, что мы говорим о профилях кода. Ну и к вопросу dom, тоже не совсем понятно надо ли, я думаю, что нет. Компиляторы или интерпретатор должен решать проблемы кода а не тулза. Так что выбирая, лучше улучшать последний а не пытаться развернуть поудобней граф исполнения, а в крайности вообще лучше все в васм перевести да и делов
Почему Svelte постоянно сравнению с React? Я когда вижу в статьях код написанный на Svelte, не сразу отличаю его от Angular и Vue.
Во-первых, Angular играет в другой лиге. Все же это Application Framework, поэтому имеет смысл сравнивать его, например, с Ember. Svelte, React и Vue — это UI фреймворки.
Во-вторых, AoT компиляция в Angular работает только для шаблонов. В итоге компоненты все равно зависят от общего Angular core и не являются полностью stand-alone.
В-третьих, подобное сравнение уже проводилось, когда только были заявлены прекрасные характеристики Ivy. В итоге, сравнение показало что сравнивать бесполезно.
В-третьих, подобное сравнение уже проводилось, когда только были заявлены прекрасные характеристики Ivy. В итоге, сравнение показало что сравнивать бесполезно.В одном случае он сравнивает по скорости, а в другом по размеру, это не серьезно. Хотя чего можно было ожидать в свитере кроме троллинга.
<template>
<div>
<h1 style="color:red">Hello {{ name }}!</h1>
<input v-model="name">
<hr>
<button v-if="count < 10" @click="count++">
Clicks {{ count }}
</button>
<div v-else>
<p>Clicks limit overcome</p>
<button @click="count=0">Drop</button>
</div>
</div>
</template>
<h1 style="color:red">Hello {{ name }}!</h1>
<input [(value)]="name">
<hr>
<button *ngIf="count < 10; else elseBlock" (click)="count = count + 1">
Clicks {{ count }}
</button>
<ng-template #elseBlock>
<p>Clicks limit overcome</p>
<button (click)="count=0">Drop</button>
</ng-template>
<h1 style="color:red">Hello {name}!</h1>
<input bind:value={name}>
<hr>
{#if count < 10}
<button on:click={e => count++}>
Clicks {count}
</button>
{:else}
<p>Clicks limit overcome</p>
<button on:click={e => count=0}>Drop</button>
{/if}
<h1 style="color:red">Hello {{ name }}!</h1>
<h1 style="color:red">Hello {{ name }}!</h1>
<h1 style="color:red">Hello {name}!</h1>
<input v-model="name">
<input [(value)]="name">
<input bind:value={name}>
<button v-if="count < 10" @click="count++">
<button *ngIf="count < 10; else elseBlock" (click)="count = count + 1">
{#if count < 10} <button on:click={e => count++}>
<div v-else>
<ng-template #elseBlock>
{:else}
Для Вас это действительно принципиальная разница?
Принципиально другой подход, в данном случае просто слегка разные ключевые слова и синтаксис
В давние времена приходилось все делать руками, из js лесть в DOM искать нужный элемент и при изменении состояния менять его или создавать новые элементы. Сейчас все это на себя берут Angular/Vue/React. Вот между этими подходами огромная разница. А разница между тем как написать :if или *ngIf уже не существенна лично для меня
Вы тут говорите о принципе построения веб-приложений, а именно event-based approach и state-based approach
Да, это два принципиально разные подходы, об этом я и говорю, что Svelte никак принципиально не меняет разработку по сравнению с Vue
То что вы не можете отличить React/Vue/Angular/Svelte лишь говорит о том, что опыта использования этих фреймворков у вас не очень много
Я их могу отличить, но когда приходится читать много кода на разных языках, то на такие мелочи перестаешь обращать внимание
Да, это два принципиально разные подходы, об этом я и говорю, что Svelte никак принципиально не меняет разработку по сравнению с Vue
Да, все это UI фреймворки основанные на компонентном подходе и state-based моделе управления. Собственно сейчас это практически стандарт для фронтенда.
Я их могу отличить, но когда приходится читать много кода на разных языках, то на такие мелочи перестаешь обращать внимание
Сами писали, что не сразу их отличаете:
когда вижу в статьях код написанный на Svelte, не сразу отличаю его от Angular и Vue.
React с его jsx — другой подход.
Knockout, где все запихнули в data-bind — тоже не совсем такой же.
Ещё есть jquery templates, которые выглядят похоже — но основаны не на DOM, а на строковых подстановках со всеми вытекающими особенностями.
А если в процессе работы программы привязка стала не нужна?
Если структура проекта (связи между компонентами) — динамические.
Сейчас компоненты и связь между ними есть, а через какое-то время — «ведомый» компонент (тот, который получает оповещения об изменении свойств) — удаляется. Или просто — его больше не надо оповещать. Структура проекта изменилась.
В скомпилированном проекте такое возможно?
Автор не ставил целью сравнить все фреймворки в очередной раз. Автор пытался объяснить механизм работы реактивности в Svelte — что для неё не нужны какие-либо чужеродные конструкции, а только то, что есть в самом Javascript.
К слову, я бы с удовольствием почитал статью, где сравнивался бы не Svelte с Vue, а Vue со Svelte, например.
Вы совершенно правы. Можно назвать это Sveltescrypt. С $
это просто сахар, который легко запомнить и использовать. Но синтаксис сам по себе — всё еще валидный JS, и шаблоны проектирования остаются те же. Хотите переменную стейта — просто пишите let var
— как вы делаете для создания обычных переменных Javascript, а не используете "чужеродную конструкцию" для этого.
JS не валидный, синтаксис валидный.
Скорее всего это сделано, чтобы имеющийся туллинг для Javascript был готов из коробки, например подсветка синтаксиса на Хабре.
Кроме того — реактивные выражения в Svelte — это не обязательно только присваивание. Можно сделать реактивным любое выражение и даже целый блок:
let varA = 0;
$: {
console.log(varA);
console.log(varA*2);
}
// В консоли будут показываться новые значения, всякий раз, когда изменится varA
Отсюда возникает и второй вопрос: почему разработчики гуляют по тем же самым граблям?
Вот это как раз понятно: со встроенным в язык тулингом ничего хитрее Реакта не придумать, а Реакт уже придуман.
Ок, вернёмся к нашим баранам.
Ну, не весь имеющийся туллинг же, а по синтаксису. Поэтому для Svelte с первых версий сразу была годная подсветка синтаксиса и притир в любой IDE(особенно, когда компоненты были в *.html файлах ещё). Иначе, в комментариях к статьям про Svelte, только и делали бы, что жаловались на невозможность писать на Svelte где бы то ни было. Сейчас уже экосистема потихоньку обрастает. Есть плагин и для того же ESLint.
Смысл в том, что Svelte — это языки, которые вы уже знаете. HTML, CSS и JS. Т.е. если вы знакомы с этими языками — вы уже знаете 90% Svelte. В каждый из этих языков добавлено немного магии — на изучение которой хватит 15 минут чтения учебника на сайте.
В принципе эта проблема решаема. К примеру для jsx-control-statements есть плагин для eslint. Правда я не уверен, что кто-то делал это для Svelte.
Хе-хе, ну есть же динозавры, у которых не линтеров, ни подсветки синтаксиса, ни прочих удобств. У них тулинг "всегда готов" как пионер.
А если серьёзно, то всегда остаётся какая-нибудь Jet Brains (ну или аналог) со своими парсерами, анализаторами и прочим. Проблема тулинга полноценно решается только для очень крупных игроков (скажем поддержка JSX есть уже в каждой кофемолке). А для несколько менее популярного Vue только пол пути пройдено.
Вот из недавнего — prettier не умеет в новый pipe-operator в smart виде. Очень удобная штука, но пришлось от неё отказаться :(
$: value = 123
let secondNumber = square(firstNumber);
let firstNumber = 42;
Довольно спорное решение менять сам язык ради фреймворка.
Производительность
Я не буду описывать фактическую реализацию этого процесса, потому что эта статья и без того уже достаточно объемная.
Интересный факт — это самая важная часть, которую можно противопоставлять существующим фреймворкам типа Реакта. Всё остальное (включая синтаксис и кол-во строк кода) — сильно вторично.
![](https://habrastorage.org/webt/rq/sr/dx/rqsrdxfzrmx6kizavvu64dkebno.png)
Супер, спасибо.
Swap Rows прям подозрительно подозрительный. Может потому, что по факту никто не свапит именно строки? Проще на месте одной зарендерить контент второй, и на второй контент первой, не переставляя строки.
Нет, я не оправдываю Реакт, но действительно интересно почему такой результат, когда все остальные тесты ± ровно.
синтетические тесты на микрооптимизации
Я думал, речь о принципиально новом подходе, который вы использовали про создании Svelte, а не в микрооптимизациях и другом синтаксисе.
Синтетические тесты имеют смысл для сравнения и именно для этого они и существуют.
Естественно, тест на рендеринг 1000 строк никак не отобразится на реальном проекте с 1000 строк, но даст возможность оценить выигрыш перехода от одной технологии к другой. Поскольку просто так (из-за синтаксиса) никто технологии не меняет. Меняют тогда, когда с используемой технологией возникают сложности (как-то с производительностью и эффективностью используемой памяти). Работая с реактом с проектом в котором десятки тысяч строк и около сотни тысяч дом элементов (да, мы используем переиспользование строк (react-virtualize), но это скорее костыль, чем решение), мне этот вопрос куда более интересен, чем синтаксис.
Я думал, речь о принципиально новом подходе, который вы использовали про создании Svelte, а не в микрооптимизациях и другом синтаксисе.
Речь именно о другом подходе, а подобные бенчмарки — это как раз и есть микрооптимизации.
Синтетические тесты имеют смысл для сравнения и именно для этого они и существуют.
Естественно, тест на рендеринг 1000 строк никак не отобразится на реальном проекте с 1000 строк, но даст возможность оценить выигрыш перехода от одной технологии к другой.
Оценивать выигрыш на основе того, что никогда не будет на реальном проекте? Так себе идея.
Поскольку просто так (из-за синтаксиса) никто технологии не меняет. Меняют тогда, когда с используемой технологией возникают сложности (как-то с производительностью и эффективностью используемой памяти).
Именно так.
В целом, как я написал выше — если для вас это важно, бенчмарки всевозможные доступны и вы можете сравнить то, что вас интересует.
Что с TypeScript? Не сыграет ли со Svetle злую шутку то, что Svetle — компилятор? Ведь писать на чистом JS в 2019 году несколько некомфортно, а TypeScript уже чертовски хорош и улучшается семимильными шагами.
Тоже самое будет, если не указать $: в Svelte.
> Представьте, что вы только начали изучать веб-разработку. Какой код был бы для вас менее понятен? Тот, что слева, или тот, который справа?
А если не только начали и работаете в команде? Какой код будет более понятен без чтения доп мануалов?
Ну и отсутствие typescript, конечно, огромный минус…
Тоже самое будет, если не указать $: в Svelte.
Не совсем то же самое. $:
просто назначает следующее за ним выражение быть реактивным — по сути это destiny operator. Кроме него есть ещё переменные стейта let somevar;
. Тут вообще ничего не надо делать, чтобы при изменении через присваивание их значения отображались на вьюшке. А this.setState
вы обязаны вызывать каждый раз, когда собираетесь изменить данные.
А если не только начали и работаете в команде? Какой код будет более понятен без чтения доп мануалов?
А если команда работает на JQuery, а не на React?
А this.setState вы обязаны вызывать каждый раз, когда собираетесь изменить данные.
Тоже самое делает Svelte у себя внутри, только это уже никак не контролируется разработчиком. В React можно четко описывать, когда нужно делать обновление состояния (например, не всегда изменение переменной должно приводить к изменению DOM).
Хотя соглашусь, для простых случаев подход Svelte довольно удобен.
А если команда работает на JQuery, а не на React?
Эммм… и в чем проблема?...JQuery — просто библиотека… подключить ее к React не проблема…
Да нет, таки проблема. JQuery — это "просто библиотека" для манипуляций DOM. React — тоже библиотека для манипуляций DOM. Когда две разные библиотеки начинают манипулировать DOM — результат начинает зависеть от мелких деталей их реализации.
(например, не всегда изменение переменной должно приводить к изменению DOM).
А можно конкретный кейс, когда вы не хотите иметь консистентный стейт и его отражение в DOM?
Да и не важны конкретные кейсы — важно наличие возможности управления жизненным циклом элемента.
Да и не важны конкретные кейсы — важно наличие возможности управления жизненным циклом элемента.
Не до конца понимаю чем все это отличается от того, как это деалется в React и тем более Vue, где изменение стейта через this.foo также приводит к перерисовке. Давайте говорить конкретно, вы мне пример на React (или чем угодно) и почему вы считаете, что в Svelte нельзя сделать также, а я вам такой же пример на Svelte. Думаю для разработчиков язык кода наиболее доступный и понятный.
Т.е. нельзя в одном файле содержать несколько компонентов или что-то не уловил?
А пример кода такой (чисто для передачи сути):
import * as React from 'react'
export type GraphCounterProps = { percent: number}
export class GraphCounter extends React.Component<GraphCounterProps, {}> {
private _color: string[]
constructor(props: GraphCounterProps) {
super(props)
this._color = ['green', 'yellow', 'red', 'red']
}
shouldComponentUpdate(nextProps: GraphCounterProps) {
return (Math.round(this.props.percent / 30) === Math.round(nextProps.percent / 30)) ? false : true
}
render() {
return (
<span
style={{
color: this._color[Math.round(this.props.percent / 30)],
width: 100,
height: 20
}}
/>
)
}
}
C ходу не увидел метод, аналогичный render в React, но судя по философии Svelte
Зачем он, если код исполняется один раз, а не перезапускается на каждое изменение стейта?
Т.е. нельзя в одном файле содержать несколько компонентов или что-то не уловил?
Конечно нельзя. В реакт тоже нельзя, точнее можно, но за это надо по рукам бить больно.
А пример кода такой (чисто для передачи сути):
Тот же пример на Svelte:
<span style="color: {color}" />
<script>
let colors = ['green', 'yellow', 'red', 'red'],
percent = 0;
$: color = colors[Math.round(percent / 30)];
export { percent };
</script>
<style>
span { width: 100px; height: 20px; }
</style>
Не увидел никаких проблем, лишь ручные оптимизации, которые Реакт заставляет делать разработчиков, а Svelte хендлит сам.
Сравните во-первых, насколько лаконичнее и декларативнее, во-вторых, насколько меньше действий делается, чтобы осуществить обновление.
В реакт тоже нельзя, точнее можно, но за это надо по рукам бить больно.
Глупости. Это скорее напасть Vue с его .vue файлами. React то как раз очень поощряет дробление компонент на минимальные функциональные единицы, настолько маленькие что в здравом рассудке их никто выносить в отдельный файл не будет. Это способствую функциональные компоненты, которые по сути представляют из себя обыкновенную pure-function.
React поощеряет дробление на мелкие компоненты не от хорошей жизни, а от принципа своей работы — чем меньше функциональная единица, тем меньше работы выполняет Реакт. Иногда это деление настолько не логичное, что потом сидишь и пытаешься «сшить» все эти «лохмотья» в цельное приложение.
Лично я выношу даже одну функцию в отдельный файл, если она несет обособленную смысловую нагрузку
У нас есть модули и импорты, нет никаких причин мешать все в кучу, это видимо от большой любви к раннему PHP.
Ох не хотел бы я поддерживать вашу кодовую базу. Одно-двустрочники вынесенные в отдельные файлы с дублированными импортами…
Но это лирика. По факту же, когда я наблюдаю подход "1 компонент = 1 файл" я вижу вовсе не то, о чём говорят сторонники этого подхода. Никаких чудес не случается.
Я вижу длиннющие плохочитаемые плохоподдерживаемые макароны. Это я про Vue. Мне ещё не доводилось встречать примеров кода на Vue которые бы не подходили под это описание. Сколько я не смотрел реальный .vue код это портянки однообразной html-like копипасты в десятки строк. Там где я в React сделал бы 5 компонент в 1 файле с внятным названием и разграничением ответственности vue-воды пишут макароны с копипастой, т.к. подход "1 компонент = 1 файл" этому способствует самым явным образом. В случае использования какого-нибудь material-ui или другой многословной UI либы уровень мусора достигает немыслимых размеров.
Причина этому банальна. Если выносить все мелкие парустрочные сущности, обёртки, группировки и пр. в отдельные файлы, то те самые общие импорты и экспорты начинают занимать большую часть кодовой базы. В добавок к этому с огромным количеством крошечных файлов состоящих почти целиком из бойлерплейта работать гораздо менее удобно, чем с в 3-4-5 раз меньшим количеством файлов по 20-40 строк.
чем меньше функциональная единица, тем меньше работы выполняет Реакт
Обычно чем больше вы дробите, тем медленнее работает приложение. Как минимум начиная с какого-то уровня. Одна из самых странных и нелепых оптимизаций приложений заключается как раз в том, чтобы компоненты инлайнить ({comp(props)}
, вместо <Comp {...props}/>
). И это правда помогает (чуть-чуть).
То о чём вы говорите это уровень хаоса, когда человек все гребёт в один компонент явно нарушая принцип ограниченной ответственности. Но это дет сад :)
Но это лирика. По факту же, когда я наблюдаю подход «1 компонент = 1 файл» я вижу вовсе не то, о чём говорят сторонники этого подхода. Никаких чудес не случается.
Не повезло вам. Лично я не видел хорошо написанных React компонентов)
Причина этому банальна. Если выносить все мелкие парустрочные сущности, обёртки, группировки и пр. в отдельные файлы, то те самые общие импорты и экспорты начинают занимать большую часть кодовой базы.
А вы попробуйте не создавать компоненты из 1-2 строк. Они нужны только для того, чтобы реакт окончательно не задохнулся от полного отсутствия реактивности.
Обычно чем больше вы дробите, тем медленнее работает приложение. Как минимум начиная с какого-то уровня.
В реакт отсечкой для рендеринга vdom является компонент. Так как иных способов ограничить rerender/reconcile внутри не существует, в реакт вы вынуждены дробить приложение на максимально мелкие кусочки, которые как вы верно выразились, ухудшают поддержку и читабильность. Но еще хуже, когда эти мелкие кусочки сваливаются в один файл. Это финал вообще.
То о чём вы говорите это уровень хаоса, когда человек все гребёт в один компонент явно нарушая принцип ограниченной ответственности. Но это дет сад :)
Грести в один компонент не надо. Также как грести несколько компонентов в один файл. Компоненты должны иметь смысл, а 1-2х строчные компоненты редко имеют смысл, кроме отсечки рендеринга. Компоненты как раз и нужно разделять согласно single responsobility. Если никакой responsobility нет вообще, если компонент — это просто кусок шаблона, то и смысл в таких компонентах? Раньше это вообще называлось partial и даже не было полноценным шаблоном.
Я понял вашу мысль. В корне с ней не согласен. Вот прямо по всем пунктам. Но спорить не буду. Я только уточню, 1-2 строчные функции тоже зло? Если да, то и правда финиш, если же нет, то осталось только понять отчего вы считаете, что компоненты и функции чем-то серьёзно отличаются друг от друга.
Я понял вашу мысль. В корне с ней не согласен. Вот прямо по всем пунктам. Но спорить не буду.
Право ваше и спор тут не поможет конечно.
Я только уточню, 1-2 строчные функции тоже зло?
Функции это про функции, компоненты — это больше про классы. То что в Реакт компоненты прекратили в функции — это не очень здоровая идея.
Если да, то и правда финиш, если же нет, то осталось только понять отчего вы считаете, что компоненты и функции чем-то серьёзно отличаются друг от друга.
Потому что функция — это то, что вызывается с аргументами и возвращает результат, каждый раз исполняя логику внутри. Компонент — это то, что инкапсулирует стейт, логику работы с ним, а также может инстанциироваться множество раз. То есть это больше похоже на класс. Именно от того что в Реакт компоненты вдруг стали функциями и ростут все проблемы с производительностью, когда все содержимое компонента вынуждено инициализироваться каждый раз на каждое изменение входных данных. Это просто с точки зрения понимания, но совершенно не эффективно. Именно поэтому в Реакт есть костыли вроде useMemo, useCallback, useReducer, React.PureComponent, shouldComponentUpdate и так далее.
Svelte лишен необходимости в таких костылях, потому что он ведет себя не как функция. Код инициализируется полностью только один раз. Дальнейшие вычисления происходят лишь точечно и только тех частей стейта и логики, которые реально требуют пересчета.
Кроме того, я даже физически не могу представить себе компонент из 2-х строчек в Svelte. В Реакт могу, потому что он неполноценных феймворк, без работы со стилями. Например, если представить что у нас есть компонент ссылки:
<a {href} {title} class="link">{text}</a>
Типа в одну строчку, но даже он не будет таким, потому что компонент без стилей не имеет смысла:
<a {href} {title} class="link">{text}</a>
<style>
a { color: red; }
a:focus { outline: 2px solid red; }
</style>
И вот он уже не однострочный и требует отдельного файла.
То что в Реакт компоненты прекратили в функции — это не очень здоровая идея.
Возможно. Тут есть о чём поспорить. Но именно в этом и заключается react-way.
Компонент — это то, что инкапсулирует стейт, логику работы с ним, а также может инстанциироваться множество раз.
Редкий компонент stateful. Почти все как раз stateless. Ну если писать идеоматично.
Именно поэтому в Реакт есть костыли вроде useMemo, useCallback, useReducer, React.PureComponent, shouldComponentUpdate и так далее.
С этим трудно спорить. Тут много подводных камней, неочевидных моментов. И мало кто в это умеет. Но к нашему разговору это пожалуй имеет ровным счётом никакого отношения.
Типа в одну строчку, но даже он не будет таким, потому что компонент без стилей не имеет смысла:
Очень спорный момент. У меня почти все компоненты не имеют собственных стилей. Я придерживаюсь классического подхода с каскадом, и базовыми стилями. Это избавляет от необходимости писать стили повсеместно и тем более их дублировать. Но сейчас так не модно, да.
И вот он уже не однострочный и требует отдельного файла.
Не требует :) Если вышестоящий компонент состоит из 3-4 включений подобных однострочных под-компонент, то размазав их по файловой системе, вы только усложните жизнь тому, кто будет их поддерживать.
По сути говоря тут вопрос между: 5 файлами крошечного размера и 1 файлом в 10-30 строк. Работать со вторым гораздо удобнее. Что и показывает реальная практика Vue. Вместо того чтобы выносить подобные вещи в отдельные компоненты они всё инлайнят как есть в вышестоящий компонент и получают лапшу.
И вот в этом мне как раз симпатизирует React-way. Всё есть функция. Функции с телом больше 5 строк — это хороший повод задуматься о разделении её на несколько. Такая же картинка и с компонентами, ибо они тоже функции с чётко заданной ролью.
Писать таким во Vue пока нельзя :( Точнее можно, это это сильно против шерсти. С третьей версии обещают ввести. Посмотрим во что это выльется.
В спор касательно природы реактивности Svetle вступать не хочу, т.к. довольно долго работал с Knockout и знаю, что всё не так просто и радужно, как кажется на первый взгляд.
Возможно. Тут есть о чём поспорить. Но именно в этом и заключается react-way.
Ок, react-way, это мне понятно. Можно тогда сказать, что полноценные однофайловые компоненты, которых нет в реакт, это svelte-way. Необязательно только присовывать react-way повсюду, как это любят делать адепты этого замечательного фреймворка.
Редкий компонент stateful. Почти все как раз stateless. Ну если писать идеоматично.
Наоборот, редкий компонент stateless, чаще всего все же stateful. А если он все же stateless, то обычно это так называемые leaf-компоненты или dumb-компоненты, как это любят называть в реакте. Правда если уж у них вообще нет стейта, то такие компоненты даже компонентами назвать сложно. Это скорее шаблоны или partials, если совсем ко класике. Просто у современных фреймворков нет иных выразительных средств, поэтому все лепят компонентами. Но вот есть например lit-html:
const template = data => html`
<h1>Hello ${data.title}</h1>
<p>Hello ${data.description}</p>
`;
render(template(state), document.body);
Один в один реакт на функциях ведь, только нативный абсолютно. И вот незадача, ни у кого язык не поворачивается это гордо называть компонентом. Шаблон это.
С этим трудно спорить. Тут много подводных камней, неочевидных моментов. И мало кто в это умеет. Но к нашему разговору это пожалуй имеет ровным счётом никакого отношения.
Имеет, так как ноги ростут в том числе из функциональных компонентов. А смешивание их в один файл лишь добавляет «подводных камней» и «неочевидных моментов».
Очень спорный момент. У меня почти все компоненты не имеют собственных стилей.
Значит у вас не совсем полноценные и плохо переносимые компоненты. Я еще понимаю когда люди сверху крутят всякие styled-components (хоть это и адуха).
Я придерживаюсь классического подхода с каскадом, и базовыми стилями.
Если нужно, можно и глобальные стили юзать. Это ухудшает переиспользуемость и переносимость, но совершенно не мешает подходу с компонентыми стилями. Даже используя ShadowDOM можно позволить внешним стилям работать внутри компонента.
Это избавляет от необходимости писать стили повсеместно и тем более их дублировать. Но сейчас так не модно, да.
Ничего дублировать не надо. Законченный компонент не может быть без стилей иначе он не законччен. Поэтому это не просто «мода», а компонентный подход, который в Реакт, как мне кажется, все же недоработан.
Не требует :) Если вышестоящий компонент состоит из 3-4 включений подобных однострочных под-компонент,
Я же написал вам пример компонента. Он уже не однострочный, а ведь там еще 20 строк стилей. Да и разметка наврядли такая простая. Вы предлагаете все эти 3-4 20-ти строчных компонента помещать в тот же файл, что и вышестоящий компонент? Чудно как-то.
Да, я понял, что вы пишете компоненты без стилей. Только исходя из того, что я написал выше, это либо не компоненты вовсе, а шаблоны или partials. Либо это какие-то недоделанные компоненты.
размазав их по файловой системе, вы только усложните жизнь тому, кто будет их поддерживать
Первый раз за последнее время слышу, чтобы уменьшение кол-ва строк в файле и выделение логической единицы в отдельный файл приводило усложнению жизни. Помню так в начале нулевых адепты php говорили и то сейчас даже в php давно не так.
По сути говоря тут вопрос между: 5 файлами крошечного размера и 1 файлом в 10-30 строк.
Если бы вы писали полноценные компоненты, то у вас не было бы 1-2 строчных компонентов просто по определению. А значит один общий файл был бы не 10-30 строк на 5 компонентов, а уже 100-150 строк.
Работать со вторым гораздо удобнее. Что и показывает реальная практика Vue.
У нас реальная практика Vue с выхода 2-й версии и это не так. SFC — это лучшее что есть во Vue и всегда было.
Вместо того чтобы выносить подобные вещи в отдельные компоненты они всё инлайнят как есть в вышестоящий компонент и получают лапшу.
Так делают видимо те, кто пришел с реакт и любит лапшу. За это тоже надо бить по рукам. Благо Svelte изначально уберегает от этого.
И вот в этом мне как раз симпатизирует React-way. Всё есть функция. Функции с телом больше 5 строк — это хороший повод задуматься о разделении её на несколько. Такая же картинка и с компонентами, ибо они тоже функции с чётко заданной ролью.
То есть если у вас чисто HTML-макет больше 5-ти строк на одну логическую единицу, то вы ее все равно дробите на компоненты? Странно, обычно стейт компонента около 5-и строк занимает, плюс всякие там JSX примочки типа обязательного рут-элемента (+2 строчки). Ну-ка я попробую:
function Component(props) {
return <>
<h1>Hello ${props.title}</h1>
<p>Hello ${props.description}</p>
</>;
}
Хм, уже 4 строки. Получается еще одна и надо на дополнительный компонент делить?
Писать таким во Vue пока нельзя :( Точнее можно, это это сильно против шерсти. С третьей версии обещают ввести. Посмотрим во что это выльется.
Да, ох уж эти китайцы. Понахватают всего дурного и тянут в рот…
В спор касательно природы реактивности Svetle вступать не хочу, т.к. довольно долго работал с Knockout и знаю, что всё не так просто и радужно, как кажется на первый взгляд.
Насколько я знаю реактивность в Knockout реализована с помощью observerables, а в Svelte с помощью компиляции и топологического порядка исполнения. Какая связь в таком случае?
Судя по всему самые большие у нас с вами разногласия касаются стилей (да и бог с ними), и терминов (patrials, templates, ...). Чтобы не путать вас дальше, буду стараться использовать вашу терминологию.
Вот согласной вашей терминологии во Vue мне не хватает этих самых partials, чтобы избегать излишней лапши и дробить эти здоровенные куски html на внятные именованные параметризированные блоки, без создания груды лишних файлов. То что они будут stateless меня нисколько не смущает. Меня смущает сам факт того, что я не понимаю как это сделать. Вероятно я что-то упустил в документации.
Отсюда вопрос, раз уж вы упомняли, что у вас позитивный опыт с Vue и SCF, что там с partials? Беглый поиск меня привёл к тому, что до 0.12 там они и правда были. Как эту проблему решают теперь?
У меня нет никаких претензий к подходу "1 файл = 1 компонент", при удовлетворении двух пунктов: поддержка именованных переиспольуземыех параметризированных stateless блоков (partials?), вашей формулировки того что такое компонент. Наличие двух stateful компонент в одном файле и в React я считаю антипаттерном.
Теперь касательно спора Svelte vs React. Я не готов тут спорить, т.к. о Svelte я знаю чуть больше, чем ничего. Пара статей и видео презентация. Ваш аргумент про то, что это не observable вполне справедлив, ошибочка вышла, sorry.
Вот согласной вашей терминологии во Vue мне не хватает этих самых partials, чтобы избегать излишней лапши и дробить эти здоровенные куски html на внятные именованные параметризированные блоки, без создания груды лишних файлов. То что они будут stateless меня нисколько не смущает. Меня смущает сам факт того, что я не понимаю как это сделать. Вероятно я что-то упустил в документации.
Думаю способ это сделать по-другому делить приложение на компоненты. Потому что например у нас такой проблемы просто нет или она просто настолько редкая, что я не могу вспомнить. Может пример есть какой-то?
Отсюда вопрос, раз уж вы упомняли, что у вас позитивный опыт с Vue и SCF, что там с partials? Беглый поиск меня привёл к тому, что до 0.12 там они и правда были. Как эту проблему решают теперь?
Самое интересное что их оттуда выпилили на хайпе вокруг Реакт. Типа все в вашем приложении это компонент. А ведь изначально Vue их подрезал, как и все остальное, у Ractive (прямого предка Svelte). Но мода на только лишь компоненты лишила большую часть фреймворков дополнительных выразительных средств.
Наличие двух stateful компонент в одном файле и в React я считаю антипаттерном.
Ок, тут мы сошлись. Тогда может попробуем какой-то пример разобрать. Глядишь я с вами и соглашусь.
Ваш аргумент про то, что это не observable вполне справедлив, ошибочка вышла, sorry.
Принято.
Может пример есть какой-то?
Например вот такой компонент. Взял первое что под руку подвернулось. Груда html. Много-много разметки. По разметке разбросано много-много относящихся только к UI аттрибутов. В итоге код на много экранов. Стейт значение всего 1.
Что можно сделать даже не вникая в код? Ну разбить эти куски на отдельные "partials" с внятными именами. И тогда получаем иерархическую структуру где каждое звено лаконично и удобочитаемо. Когда частности не мешают читать целостную картинку и при этом доступны под рукой.
Как такое сделать во Vue? Создать 10 файлов?
Конкретно в вашем файле я вижу лишь один компонент и один фрагмент (drawer), повторяющийся аж два раза.
Его можно вынести в отдельный файл или повторить два раза, это принципиально в подобном коде ничего не изменит.
С 86 по 164 строку мы видим груду html-like лапши. Которую тяжело читать и с ней тяжело работать. Сколько раз там дублируется drawer значения не имеет. Вместо эти 80 строк визуального мусора я ожидаю увидеть суть. А нюансы (груды аттрибутов и всякие обёртки) можно вынести на следующий уровень иерархии (partials)?
В конце концов мы же не пишем так обыкновенный код. А компоненты так пишут. В случае Vue особенно часто их пишут именно так (но искать пример для вью мне было лень).
В рамках терминологии PaulMaly вся эта лапша должна быть единым компонентом, т.к. компонент должен быть stateFul. Дескать нельзя выносить stateLess части в отдельные компоненты.
Решение — выносим все эти части в stateLess "partials" и тогда код <ResponsiveDrawer/>
становится легко-читаемым и с ним становится удобно работать. Проблема — partials из Vue выпилили.
Почему вы "ожидаете увидеть суть" в Svelte, но при этом миритесь с "визуальным мусором" в React?
но при этом миритесь с "визуальным мусором" в React?
Не понял, о чём вы. Приведённый выше пример кода — пример html-like лапши. Не надо так писать :) Really. Не надо с этим "мириться". React позволяет писать по-другому.
Про Svelte я кстати не писал. Вполне вероятно что там есть "partials" и такая проблема не стоит вообще. Это во Vue их нет.
В рамках терминологии PaulMaly вся эта лапша должна быть единым компонентом, т.к. компонент должен быть stateFul. Дескать нельзя выносить stateLess части в отдельные компоненты.
Не не, это я вашу терминологию натягивать с подхода «все есть компонент», а более правильную, «не все есть компонент, а что еще и шаблон/partial». Мое же решение вашей проблемы — это иной подход к декомпозиции компонентов в принципе.
Я бы декомпозировал примерно так, если сходу:
<div class="root">
<BasicAppBar
title="Responsive drawer"
on:click={e => open = !open}
/>
<EmailDrawer {open} />
<main>
<svelte:component this={Content} />
</main>
</div>
<script>
export let open = false,
Content = null;
</script>
<style>
.root { ... }
main { ... }
</style>
Правда ведь компонент страницы стал выглядить и читаться значительно проще?
Но теперь у вас это "компоненты", хотя они и stateLess. И как бы вы не дробили, вы дойдёте до:
<IconButton
color="inherit"
aria-label="Open drawer"
edge="start"
onClick={handleDrawerToggle}
className={classes.menuButton}
>
<MenuIcon />
</IconButton>
По-хорошему такое надо вынести в отдельный компонент. Но ведь оно же stateLess. Вы выше писали:
А если он все же stateless, то обычно это так называемые leaf-компоненты или dumb-компоненты, как это любят называть в реакте. Правда если уж у них вообще нет стейта, то такие компоненты даже компонентами назвать сложно. Это скорее шаблоны или partials, если совсем ко класике.
И мы снова вернулись к partials. В примере выше практически все эти 80 строк это stateLess.
Всякие там -aria аттрибуты, разметка og:graph, нюансы вёрстки часто вынуждают писать груды объёмного stateless html.
И в случае Vue я вижу что народ не парится и всё постит в 1 файл с тонной подобного мусорного кода. Приходится сильно много парсить глазами, чтобы понять что тут почём. И важные вещи вроде -v директив теряются в этой горе мусора.
В partials их не вынести, за их отсутствием. В отдельные файлы тащить каждый такой нюанс — сильно усложнить жизнь в поддержке (такое по 100 раз на дню переделается, с грудой крошечных файлов работать неуодобно, git очень плохо умеет в переименовывание и "наследование" файлов, постоянная проблема с именованием, тонны импортов и экспортов, особенно дублирование общих зависимостей, и т.д.). Добавить к этому что даже vsCode для js всё ещё космически далёк от уровня полноценных IDE для статически типизированных языков и мы получаем боль.
В итоге пока я писал на вью (очень непродолжительное время, vue разочаровал меня не только в этом) я перешёл на string-templates в js файлах. Вместо "partials" писал компоненты которые явным образом приходилось ставить в components: { UserPanelHeader, ... }
. Вскоре я выяснил что разработка за пределами .vue файлов это вообще не vue-way и никто всерьёз её поддержкой заниматься не хочет.
Но теперь у вас это «компоненты», хотя они и stateLess. И как бы вы не дробили, вы дойдёте до:
Конечно дойду, это и будут те самые leaf-компоненты. Которые кстати тоже далеко не всегда полностью stateless, скорее их дучше назвать dumb или pure, в том смысле что результат их работы зависит от пропсов, без особой внутренней кухни.
И мы снова вернулись к partials. В примере выше практически все эти 80 строк это stateLess.
Нет не вернулись. Мы все еще говорим о том, что если композиция произведена верно, никаких 1-2 строчных недокомпонентов быть не должно. Также как не должно быть таких вот монстров из вашего примера.
Чтобы было понятно дальше, в своих проектах на Svelte делим компоненты на 3 вида: components (leaf/dumb/pure компоненты, переиспользуемые и переносимые), views (компоненты реализующие конкретную логическую единицу приложения, smart, не переносимые обычно), layouts (компоненты лейаутов).
Так вот компоненты IconButton, List, Divider, ListItem — это все компоненты. Компоненты BasicAppBar, EmailDrawer — это вьюхи, которые внутри юзают компоненты и другие вьюхи, и содержат логику этой части приложения. Ну а компонент из моего примера — это лейаут. Все четко и по полкам, никаких 1-2 строчных компонентов, никаких огромных кусков html.
И в случае Vue я вижу что народ не парится и всё постит в 1 файл с тонной подобного мусорного кода. Приходится сильно много парсить глазами, чтобы понять что тут почём. И важные вещи вроде -v директив теряются в этой горе мусора.
Далеко не все так делают, вам видимо не везло.
В итоге пока я писал на вью (очень непродолжительное время, vue разочаровал меня не только в этом) я перешёл на string-templates в js файлах.
Есть подозрение что вы пришли туда уже после опыта с React и декомпозировали приложение схожим для него образом. Но во Vue и Svelte надо делать не так.
Вскоре я выяснил что разработка за пределами .vue файлов это вообще не vue-way и никто всерьёз её поддержкой заниматься не хочет.
Да, Vue как бы поддерживает и классы, а-ля ангуляр и из реакт с JSX, но в основном все пишут SFC, потому что это удобно.
Ок, пускай это будет leaf-component. Тогда моя позиция проста: я не вижу смысла выносить мелкие однообразные leaf-компоненты в отдельные файлы, т.к. с такой разбухшей кодовой базой мне становится слишком тяжело работать. Почему? Выше в крадце описал. А других альтернатив декомпозиции Vue мне не предоставляет.
И мне пока не попадалось на глаза кодовой базы, где был бы вынос leaves в отдельные файлы. В лучшем случае так.
Не исключено, что в хороших компаниях именно так и пишут. Было бы интересно посмотреть.
<template>
<div class="md-table-pagination">
<template v-if="mdPageOptions !== false">
<span class="md-table-pagination-label">{{ mdLabel }}</span>
<select-page-size
v-model="currentPageSize"
@changed="setPageSize"
pageOptions="mdPageOptions"
<md-field>
</template>
<span>{{ currentItemCount }}-{{ currentPageCount }} {{ mdSeparator }} {{ mdTotal }}</span>
<prev-button @click="goToPrevious()" :disabled="mdPage === 1"/>
<next-button @click="goToNext()"/>
</div>
</template>
Примерно об этом говорю. Вынос prev-button
, next-button
, select-page-size
из основного тела шаблона, куда-нибудь рядом. Чтобы и идти недалеко на "нюансами", и не разбухал основной шаблон.
<md-button class="md-icon-button {classes}" {disabled} on:click>
<md-icon>{icon}</md-icon>
</md-button>
<script>
export let icon = '',
disabled = false,
classes = '';
</script>
И юзайте:
<IconButton
icon="keyboard_arrow_left"
on:click={goToPrevious}
disabled={mdPage === 1}
/>
<IconButton
icon="keyboard_arrow_right"
on:click={goToNext}
/>
Там где игра действительно стоила свеч (какие-нибудь универсальные переиспользуемые UI обёртки) — я так и делал. Но таких мест было довольно мало. Чаще всего куски были более-менее уникальными.
Честно говоря мне надоело спорить :( Мы переливаем из пустого в порожнее без всякого на то смысла. Суть: мне паталогически не хватает partials во Vue. На мой вкус и цвет SCF в нём это зло ровно до тех пор, пока "именованные параметризированные stateless блоки" туда не вернут. А до тех пор я считаю что такой подход приводит к в той или иной степени разбухшему говнокоду, на который после React смотреть без слёз нельзя. Привет php из 90-х.
Надеюсь в Svelte "partials" есть.
А до тех пор я считаю что такой подход приводит к в той или иной степени разбухшему говнокоду, на который после React смотреть без слёз нельзя. Привет php из 90-х.
Так вроде React — это как раз потомок php из 90х?
Надеюсь в Svelte «partials» есть.
Неа, нету)))) И как я писал выше, видимо не часто это нужно, раз я даже не могу придумать кейс. Вы мне тоже кейс так и не дали. Даже если он есть, но очень редкий, можно для такого редкого кейс создать один дополнительный файлик. Это не страшно.
Плюс для некоторых кейсов, можно сделать что-то вроде:
<template bind:this={tpl}>
<h1>Hello {name}</h1>
</template>
{@html welcome}
<script>
let name = 'world',
tpl;
$: welcome = name && tpl && tpl.innerHTML;
</script>
Если говорить о ключевых преимуществах Реакт, я на первое место ставлю как раз то, что компонент может быть классом. А это означает что на Реакте можно очень просто заниматься метапрограммированием — то есть не ручным кодированием компонентов, а генерированием компонентов, например, на основании схемы данных или же самих данных. Наверное именно поэтому в Реакт уже появилась библиотека по удобству близкая к Django при помощи которой можно очень быстро создавать админки marmelab.com/react-admin-demo Что-то внешне визуально похожее есть и на Vue, но там разработка на два порядка сложнее получается.
Если говорить о svelte, то я недавно обратил внимание на next-подобный фреймверк sapper см. svelte.dev/blog/sapper-towards-the-ideal-web-app-framework
Я наверное выскажу крамольную мысль. Но наверное все топ-фреймверки примерно равны по своим выразительным возможностям.
Именно так и по большей части этим всех «заразил» именно реакт. Хорошо ли это? Мое мнение не очень. Ангуляр еще пытается как-то бороться с этой модой. Все же у него есть модули и сервисы. Хотя модули вроде выпиливать будут…
Если говорить о ключевых преимуществах Реакт, я на первое место ставлю как раз то, что компонент может быть классом. А это означает что на Реакте можно очень просто заниматься метапрограммированием — то есть не ручным кодированием компонентов, а генерированием компонентов, например, на основании схемы данных или же самих данных
Кстати, после компиляции компоненты Svelte это ES6 классы со всеми вытекающими, а исходный код компонентов, который в SFC, это и есть чистой воды метапрограммирование. Я правда так не понял причем тут генерация админки на основе данных.
Наверное именно поэтому в Реакт уже появилась библиотека по удобству близкая к Django при помощи которой можно очень быстро создавать админки marmelab.com/react-admin-demo Что-то внешне визуально похожее есть и на Vue, но там разработка на два порядка сложнее получается.
На самом деле, формулировка «в Реакт уже появилась» скорее требует «еще только». Потому что первая такая админка от тех же чуваков появилась для AngularJS в далеком 2014 году: ng-admin-book.marmelab.com
Если говорить о svelte, то я недавно обратил внимание на next-подобный фреймверк sapper
Sapper конечно чуть сыроват, но нам нем уже делают сайты и некоторые в продакшн.
Про генерацию админок я ничего в своем посте не говорил. Просто был у меня один прототип (я даже сам не хотел этого делать т.к. не из тех кто пишет «свою cms» Задача была такая сделать cms которая была бы лучше чем все что было уже написано до меня и на это отводилось две недели плюс 4 часа на изучения Реакт) И там я как раз опирался на ту особенность что можно на основании данных конструировать компоненты на лету. Насколько я понимаю не все фреймерки позволяют сделать это. Например на riotjs я не смог это повотрить — быстро уперся в ограничения выразительных возможностей фреймверка. Хотя как правило это и не требуется в большинстве проектов.
Посмотрел на админку на Angular. Судя по коду проекта example кодить приходится все равно много. Хотя и разработчик (скорее фирма а не человек) тот же.
Тот тот. Тогда просто про реакт никто не слышал))
И там я как раз опирался на ту особенность что можно на основании данных конструировать компоненты на лету. Насколько я понимаю не все фреймерки позволяют сделать это. Например на riotjs я не смог это повотрить — быстро уперся в ограничения выразительных возможностей фреймверка. Хотя как правило это и не требуется в большинстве проектов.
Прям с нули конструировать компоненты в рантайме? Да, наверное Svelte так не умеет. Правда я и на реакт это не представляю как. Можете пример дать простой?
...
// Компоновка из двух блоков (1 левый + 1 правый)
if (Component.defaultProps && Component.defaultProps.isHalf) {
if (LeftHalf !== null) {
let LocalLeftHalf = LeftHalf
let localLeftHalfData = leftHalfData
var component = React.createElement(() => <section className='l-two-blocks' key={key++}>
<LocalLeftHalf {...localLeftHalfData} key={key++}/>
<Component {...block.data} key={key++}/>
</section>);
LeftHalf = null;
return component;
} else {
LeftHalf = Component;
leftHalfData = block.data;
return;
}
}
...
Вцелом Риот сейчас уже в 4-й версии наверное все возможно. Был существенно переработан. Наконец появилась возможность гидрации. так что может быть там это и можно будет сделать.
В спор касательно природы реактивности Svetle вступать не хочу, т.к. довольно долго работал с Knockout и знаю, что всё не так просто и радужно, как кажется на первый взгляд.
Knockout — довольно старая библиотека, полная архитектурных костылей. Пожалуйста, перестаньте судить по Knockout о всех других реактивных инструментах.
mayorovp, ну тут как сказать, попробовав в деле Vue2 я стал думать о KnockoutJS лучше. В KnockoutJS один ko.computed может зависеть от других ko.computed. Во Vue2 под капотом всё сводится к перекладыванию observable-leaves (что делает реализацию некоторых сложных кейсов почти невозможной). Плюс knockoutJS из коробки даёт довольно богатый инструментарий. Vue2 же даёт нам только сами компоненты. Отдельный топик работа с массивами.
Но судя по всему, во Vue3 будет много вкусных нововведений.
Разница в количестве бойлерплейта и комфорте работы с кодовой базой. Есть очень большая разница в количестве мусорного кода в этих двух подходах. Мелкие несколько-строчные компоненты шейрят между собой одни и те же импорты, методы, переменные и пр. и не требуют оных для использования себя.
Вынос их в отдельные файлы сопровождается взрывной волной бойлерплейта. Поэтому так просто никто не делает. А если так не делать, то получаем типовую vue-template-лапшу. Когда наш шаблон из простого и наглядного превращается в длинную портянку html-like кода, где понамешано всё сразу.
Суть в том, сколько раз компонент «перерисуется» при изменении percent от 0 до 100?
В моем случае обновление DOM («перерисовка» компонента) произойдет всего 4 раза.
А Svelte просто не перерисовывает DOM, если реальное значение стейта не изменилось. Понимаете? Сразу из коробки. Он внутри знает предыдущее значение color, которое является эквивалентом вашего Math.round(this.props.percent / 30), посчитаного последний раз. Далее при изменении percent или colors, Svelte автоматически пересчитывает color (эквивалент вашего Math.round(nextProps.percent / 30)) и сравнивает предыдущее значение color с новым вычисленным. Если значение реально не поменялось, то никаких перерисовок не будет. Иными словами внутри он делает что-то вроде:
changed.color = prevColor !== color;
Это вообще все вычисления необходимые для отрисовки DOM. Одно строгое сравнение. Без rerender+reconcile, без shouldComponentUpdate. Далее сама манипуляция примерно такая:
if (changed.color) {
span_1.style.color = color;
}
Где span_1 — это заранее закэшированный элемент. То есть даже querySelector по DOM не делается.
"Так же" в смысле полученного результата — да. "Так же" в смысле проведенной работы — нет.
Svelte знает, что изменение color
ведет к изменению span_1.style.color
и ни к чему более. Реакт же вызовет render()
, построит vDOM, сравнит его со старым, и только после этого узнает что кроме span_1.style.color
менять ничего не нужно.
Реакт же вызовет render()
В том то и дело, что не вызовет — именно для этого используются shouldComponentUpdate или PureComponent.
Если color изменился — то ещё как вызовет.
Ау, если нам требуется изменить DOM (color-то изменился!), то какой смысл возвращать false из shouldComponentUpdate?
Хорошо, уточняю: если percent изменился так, что теперь требуется обновить DOM — то ведь shouldComponentUpdate должен вернуть true?
И что из этого следует?
Но это не так важно. Вот вы написали вручную проверку значений в shouldComponentUpdate. Да теперь Реакт компонент НЕ будет обновлять DOM на абсолютно каждое изменение percent (понять бы вообще почему он в принципе когда-либо должен так делать, ведь кажется логичным не менять DOM если нет изменений).
Но как только проверка сработает и shouldComponentUpdate вернет true, реакт расправит крылья и как гордый сокол полетит клевать все, что попадется ему на глаза. А именно отрендерит дубликат всего vdom этого компонента и возможно подкомпонентов (зависит от того как они реализованы) и пошагово будет сравнивать все ноды/аттрибуты/значения, чтобы в итоге просто поменять цвет текста в span.
В этом примере, это не так заметно. Он всего лишь построит vdom из одной ноды с одним аттрибутом, пересчитает значения цвета (еще раз кстати), потом всего лишь соберет стили из объекта, заново применит их. Потом пошагово сравнит предыдущее дерево с новым получившимся. Сперва проверит span, потому его аттрибуты, потом выяснит какой из них изменился, потом на основе этого знания определит какую DOM операцию произвести. Просто чтобы поменять цвет.
И все это против:
if (changed.color) {
span_1.style.color = color;
}
Добрался до Svelte. Поиграл в песочнице. Интересная штука.
Сгенерированный код Svelte напоминает очень хорошо оптимизированный ручной dom-mutate-код. Там случаем нет подводных камней или ограничений когда "зависимости" устроены особенно сложным образом?
Насколько я понимаю тут вся магия заключается в том, что он вместо того чтобы рендерить шаблон целиком, рендерит только интерактивные его части и тут же сверяет их с прежним значением. Во многом напоминает этот самый vDom в React, но с меньшим количеством лишних телодвижений. А отличие от observable в том, что нет тяжеленных обвязок вокруг каждой переменной, нет сложностей с нетривиальным обновлением графа данных, и нет сильно усложнённого дебага.
На первый взгляд такой подход кажется очень перспективным. ИМХО.
Сгенерированный код Svelte напоминает очень хорошо оптимизированный ручной dom-mutate-код.
Именно так. Поэтому я называю это «писать vanillajs приложение без необходимости писать на vanillajs» )))
Там случаем нет подводных камней или ограничений когда «зависимости» устроены особенно сложным образом?
Можете попробовать. Если найдете такой кейс то велком в ишус и будем править.
Насколько я понимаю тут вся магия заключается в том, что он вместо того чтобы рендерить шаблон целиком, рендерит только интерактивные его части и тут же сверяет их с прежним значением. Во многом напоминает этот самый vDom в React, но с меньшим количеством лишних телодвижений.
Я бы не сказал что напоминает vdom. В Svelte абсолюно отсутствуют как деревья, так и реконсияция оных. А все DOM манипуляции для каждого кейс заранее подготовлены. Не вижу никакой связи с работой vdom.
А отличие от observable в том, что нет тяжеленных обвязок вокруг каждой переменной, нет сложностей с нетривиальным обновлением графа данных, и нет сильно усложнённого дебага.
Да, только статический анализ на этапе комплиции и топологический порядок.
На первый взгляд такой подход кажется очень перспективным. ИМХО.
Ждем вас в наших рядах: t.me/sveltejs ;-)
В Svelte абсолюно отсутствуют как деревья
В #for
я вижу циклы. Чем вам не деревья?
так и реконсияция оных.
Ну проверка changed.{anything}
очень схожа с той самой реконсиляцией. Те же яйца, только сбоку. В React асимптотика решения зависит от числа DOM-звеньев, в Svelte от числа реактивных вставок. Второе, на первый взгляд, должно быть быстрее (не ручаюсь).
Не вижу никакой связи с работой vdom.
^^^ А теперь? :)
^^^ А теперь? :)
Не-а)))
В #for я вижу циклы. Чем вам не деревья?
Хотя бы тем, что циклы плоские.)))
Ну проверка changed.{anything} очень схожа с той самой реконсиляцией. Те же яйца, только сбоку.
Я вот такой плохой человек, поэтому люблю говорить на примерах:
<div class="foo">
<h1>Hello world</h1>
<p class="text">Lorem ipsum</p>
<form action="/login" method="post">
<input type="email" placeholder="Enter email">
<input type="password" placeholder="Enter password">
<button>Login</button>
<button type="reset">Clear</button>
</form>
</div>
Вот такой компонент на React и Svelte (пишу на svelte, думаю сможете в уме на реакт портировать). И вот такой код:
// react
this.setState({
email: 'example@mail.com'
});
//svelte
email = 'example@mail.com';
Сколько операций сравнения сделает React с его vdom? Более 20ти по грубым подсчетам и это только реконсиляция.
Сколько операций должно быть выполнено? Ноль. Сколько делает Svelte? Ноль
Сколько операций в DOM должно быть сделано? Ноль
Добавим динамики:
...
<input value={email} type="email" placeholder="Enter email">
...
Сколько операций сравнения сделает React с его vdom? Все также более 20-ти.
Сколько реально требуется? Одну.
Сколько сделает Svelte? Одну.
Сколко манипуляций в DOM? Одна.
Только в случае с реактом, насколько я понимаю, будет также выполнена операция получения реального DOM элемента (querySelector), а в Svelte просто:
if (changed.email) {
input0.value = ctx.email;
}
Все это только операция сравнения или реконсиляция. Не считая того, что каждый раз будет построено все дерево в памяти.
Разница более чем существенная, а ваше обобщение «мол все одно» слишком уж масштабное.
Хотя бы тем, что циклы плоские.)))
Не очень понял вас. #for в #for не создаст вложенного цикла?
Сколько сделает Svelte? Одну.
Svelte сделает столько сравнений сколько у вас {}. В этом и параллель. Я выше об этом и писал. Асимптотика зависит от разных вещей. Вариант со Svelte быстрее. Можете условно считать что у Svelte вместо vdom vexpressions. Аналог реконсиляции находится там где проходят проверки на changed.{anything}
Не очень понял вас. #for в #for не создаст вложенного цикла?
Может я не понял, но в Svelte нет #for. Есть #each но какое отношение это имеет в деревьям vdom все равно не ясно.
Svelte сделает столько сравнений сколько у вас {}. В этом и параллель. Я выше об этом и писал.
Просто это не так)) Видимо пример придется все же продолжить, чтобы вы разобрались.
Добавим еще чуть динамики:
...
<h1>Hello {email}</h1>
...
Сколько операций сравнения Реакт? Все еще более 20-ти.
Сколько операций сравнения надо? Одну.
Сколько сделает Svelte? Одну.
Сколько операций в DOM? Две.
Можете условно считать что у Svelte вместо vdom vexpressions. Аналог реконсиляции находится там где проходят проверки на changed.{anything}
Вы серьезно думаете что вот это аналог реконсиляции vdom?:
if (changed.email) {
set_data(t1, ctx.email); // внутри хелпера: t1.data = ctx.email
input0.name = ctx.email;
}
Ну тогда получается что все фреймворки работают по сути как AngularJS. У всех есть своеобразная форма change detection. Все одно и тоже. Зачем тогда нам с AngularJS вообще было слезать? Писали бы на нем и радовались жизни )))))
Вы серьезно думаете что вот это аналог реконсиляции vdom?
Ну да. А что вас в этом смущает?
Все одно и тоже
Наличие аналогий не говорит о том, что это одно и тоже. На деле подходы очень разные и их разнообразие меня радует. С чего вы вообще взяли, что я считаю это всё одинаковым?
Я столкнулся уже как минимум с 4 разными способами обеспечить "реактивность". У Svelte довольно оригинальный подход.
Ну да. А что вас в этом смущает?
Эм, ну тогда ладно)
С чего вы вообще взяли, что я считаю это всё одинаковым?
Хм, ну даже не знаю… Может быть поэтому?:
Насколько я понимаю тут вся магия заключается в том, что он вместо того чтобы рендерить шаблон целиком, рендерит только интерактивные его части и тут же сверяет их с прежним значением.
Svelte ничего не рендерит перед проверкой, только после. Реакт сперва рендерит vdom, потом проверяет, потом рендерит dom.
Во многом напоминает этот самый vDom в React, но с меньшим количеством лишних телодвижений.
Тогда можно было написать, «Svelte во многом напоминает вообще все что только можно, потому что у всех есть аналог cd». Да и вообще, человечество еще не придумало способа сравнить что-то, кроме как сравнить, то есть все очень похоже и напоминает друг друга))))
Я столкнулся уже как минимум с 4 разными способами обеспечить «реактивность». У Svelte довольно оригинальный подход.
Вот тут вы правы, просто без компиляции и мета-программирования это не получилось бы. Поэтому столько упора делается на то, что svelte — это компилятор.
Svelte ничего не рендерит перед проверкой, только после. Реакт сперва рендерит vdom, потом проверяет, потом рендерит dom
Да, да, всё так. Мне стоило вычитать тот комментарий перед отправкой. Sorry что запутал.
Тогда можно было написать, «Svelte во многом напоминает вообще все что только можно
Отнюдь. Судите сами: он совсем не напоминает KnockoutJS или Vue. Там ведь нет никаких сравнений. Мы просто обновляем значение, и, после этого, уведомляем всех подписчиков. Какой ценой — отдельная песня, но суть вещей другая.
А здесь мы последовательно пробегаем по всем возможным включениям, сверяясь изменилось ли наше поле или нет.
что svelte — это компилятор
Вспомнился Imba. Тоже компилятор.
Отнюдь. Судите сами: он совсем не напоминает KnockoutJS или Vue. Там ведь нет никаких сравнений. Мы просто обновляем значение, и, после этого, уведомляем всех подписчиков. Какой ценой — отдельная песня, но суть вещей другая.
Опять же не уверен как это в KnockoutJS, но в Vue все тот же vdom, что и в реакт. Разница лишь в том, что Vue кладет изменение в очередь и обновляет их в конце текущего тика, то есть изменени просходят асинхронно, а не синхронно как в React. Сам принцип Vdom при этом никак не меняется.
А здесь мы последовательно пробегаем по всем возможным включениям, сверяясь изменилось ли наше поле или нет.
Последовательно «по всем значениеям» это очень далеко от «последовательно по всему дереву».
Вспомнился Imba. Тоже компилятор.
Да есть такой: twitter.com/Rich_Harris/status/1065992585095929857
Кстати да, Vue использует vDom. Совершенно вылетело из головы. Несмотря на то, что у них observer под капотом. Не знаю, что их побудило к этому, но наверное на то были причины. В knockout же мы имеем множество функций вида val => domNode.setAttribute('title', val)
, которые вызываются при изменении значения observable. А у Vue, да, гибридный подход. Совсем забыл про это. Надо будет нарыть — зачем оно там.
Последовательно «по всем значениеям» это очень далеко от «последовательно по всему дереву».
С этим сложно спорить. Поэтому в ваших бенчмарках Svelte и показывают большую производительность.
Да есть такой: twitter.com/Rich_Harris/status/1065992585095929857
У него тут неплохой результат кстати. Надеюсь это не тот самый бенчмарк который они учудили ранее (там совершенно отвратно написанные React и Vue решения, которые ну просто никак не могут не тормозить).
Может я не понял, но в Svelte нет #for. Есть #each но какое отношение это имеет в деревьям vdom все равно не ясно.
Не к vDom, а к деревьям. Впрочем не суть. Мы опять углубляемся в скучные дебри терминологии.
Ну и опять же, как в примеру выше применить React.PureComponent? Он же сам имплементирует shouldComponentUpdate, но только для стейта и пропсов. То есть придется вводить такой же color, как я ввел в примере на Svelte и тогда везде императивно связывать percent (пропс) и color (внутренний), то есть при каждом изменении percent заново вычислять color. Как по-другому то? В реакт же нет реактивности. Получается мы избавимся от ручной проверки в shouldComponentUpdate, но получим какой-нить componentWillReceiveProps. Короче все равно не то.
А вот Svelte насколько я понимаю не позволяет использвать 3-files-component модель разработки которая по моему мнению предпочтительна.
Позволяет, можно делать так, после установки специального препроцессора:
<template src="template.html"></template>
<script src="script.js"></script>
<style src="style.css"></style>
Только обычно это не нужно и не удобно. Если компонент радумается, что хочется разделить его, то скорее всего был нарушен принцип single responsibility и компонент следует отрефакторить.
Если компонент радумается, что хочется разделить его, то скорее всего был нарушен принцип single responsibility и компонент следует отрефакторить.Разделение ведь нужно не потому что файл раздувается, а чтобы самый различный туллинг мог работать с файлами. Но если на то пошло, то как раз все мешать в один файл и есть нарушение принципа single responsibility. Что в Vue что в Svelte какая-то нездоровая мода.
Разделение ведь нужно не потому что файл раздувается, а чтобы самый различный туллинг мог работать с файлами.
Тулинг можно доработать. Все фреймворки требуют кастомного туллинга в любом случае: в React изначально не было туллинга для jsx, во Vue для SFC, в Angular тоже полно кастомных вещей, те же декораторы и TS. Все это в какой-то момент времени требовало доработки туллинга. Отказывать в удобстве разработки из-за временного несовершенства туллинга довольно глупо.
Но если на то пошло, то как раз все мешать в один файл и есть нарушение принципа single responsibility. Что в Vue что в Svelte какая-то нездоровая мода.
Странно вы делите приложение по responsibility. Для меня single responsibility — это про фукнционал, а не про деление на языки. В этом смысле единый, инкапсулированный компонент, решающий одну функциональную задачу — это вполне себе single responsibility.
Если вы придерживаетесь другого мнения — я написал выше как можно разделить на отдельные файлы.
Как раз по той же причине по которой и у свелти, все эти поделки пропагандируют SFC, а React еще доверху намешал кода с шаблонами в своем JSX (фирменнный PHP спагетти-стиль 15 летней давности).
> Все фреймворки требуют кастомного туллинга в любом случае
Это не так. Если все в отделных файлах, то доработки никакие не нужны, тулы просто сканирут файл и все.
Это не так. Если все в отделных файлах, то доработки никакие не нужны, тулы просто сканирут файл и все.
Я писал про фреймворки. Давайте уже без «воды». Назовите фреймвок, который не требует костомного туллинга?
Я писал про фреймворки. Давайте уже без «воды». Назовите фреймвок, который не требует костомного туллинга?Когда у тебя код во внешних файлах типового формата, то типовые тулы будут работать вне зависимости от фреймворка потому что это ведь просто JS/TS/CSS/SCSS/HTML/итд файлы которые не нужно кастомным образом выколупывать из SFC для анализа или какой-либо post обработки.
Просто нужно понимать что исходный код не требует некой логической группировки (SFC) и даже наоборот лучше делить код на мелкие части (даже например просто банально потому что будет меньше вероятность конфликтов при мерже). Но группировка может быть нужна потребителю кода или при дистрибуции кода и вот там уже имеет смыслы делать некую логическую группировку и компоненты.
Когда у тебя код во внешних файлах типового формата, то типовые тулы будут работать вне зависимости от фреймворка потому что это ведь просто JS/TS/CSS/SCSS/HTML/итд
Что есть типовой формат и почему TS/SCSS вдруг стали типовыми? Для них сразу тулзы были написаны? А раз нет, тогда почему вы считаете что SFC не станет точно также типовым. Да и сейчас уже SFC в Svelte это тоже вполне себе типовой формат, HTML называется. За исключением языка шаблонов HTMLx, все остальное вполне себе поддается стандартному для HTML файлов туллингу.
файлы которые не нужно кастомным образом выколупывать из SFC для анализа или какой-либо post обработки.
Ничего «выколупывать» самому и не надо. Есть препроцессоры, которые как раз делают это за нас.
Просто нужно понимать что исходный код не требует некой логической группировки (SFC) и даже наоборот лучше делить код на мелкие части (даже например просто банально потому что будет меньше вероятность конфликтов при мерже). Но группировка может быть нужна потребителю кода или при дистрибуции кода и вот там уже имеет смыслы делать некую логическую группировку и компоненты.
Не согласен тут. Значительно удобнее работать с компонентом как с единой единицей. Нужно вынести отдельно? Писал выше как.
Да и сейчас уже SFC в Svelte это тоже вполне себе типовой формат, HTML называется. За исключением языка шаблонов HTMLx, все остальное вполне себе поддается стандартному для HTML файлов туллингу.
Лично меня очень интересует именно TS-тулинг. То есть такая штука, которая подскажет мне, у какой переменной какие свойства имеются.
И вот его-то в Svelte и нету...
А HTML-тулинг как раз особо и не нужен, разве что закрывающие тэги автоматом проставлять.
Лично меня очень интересует именно TS-тулинг. То есть такая штука, которая подскажет мне, у какой переменной какие свойства имеются.
И вот его-то в Svelte и нету…
Есть такое, да, но речь как раз о том, что все это вещи которые нарабатываются со временем силами сообщества. Сейчас минимально это выглядит так:
![](https://habrastorage.org/webt/z8/7t/no/z87tnodow9lty5edn-7ydc-j7te.png)
Да, не густо, но ребята из русскоязычного сообщества пилят поддержку например вот такой штуки:
marketplace.visualstudio.com/items?itemName=ardenivanov.svelte-intellisense
Это уже поинтереснее.
php-style 15-ти летней давностиJSX пропагандируемый реактом и есть 15-ти летней давности спагетти-код-стайл, видимо потому что в FB изначально было много PHP кодеров и дос сих пор таковые диктуют правила игры имея огромные рычаги маркетингового влияния.
Код на любом языке может быть как более высокоуровневым, так и более низкоуровневым для этого языка. Речь не про сам язык, а про то как писать код на нем. Прямые манипуляции в DOM очевидно более низкоуровневое использование JS, чем декларативное изменение состояние с последующей синхронизацией с DOM.
Ок, я согласен, действительно, я достаточно стар поэтому сравниваю «низко/высокоуровневость» целиком языками (помните С/С++/Asm?) а не в рамках одного языка, что как вечно замечено также вполне приемлемо.
Верю вам на слово, что вы старее меня))) Однако, я в свое время тоже 4 года писал на С/С++ и все же стараюсь отделять мух от котлет.
Относительно компиляции, в той или иной мере это все современные фреймфорки делают (SFC в Vue, и даже если взять тот же jsx в реакте — здесь тоже нужна компиляция)
Боюсь что вы путаете компиляцию и транспиляцию. Никакой JSX и даже SFC во Vue и близко не делают то, что делает Svelte. Первый по сути превращает декларативные определения <Component /> в императивные вызовы React.createElement(). Второй всего лишь другой вид записи new Vue(options).
По моему личному мнению Svelte выглядит ближе к jquery чем к к современным фреймворкам, а это шаг назад а не вперед (и фанатики с пеной у рта доказывающие его превосходство над все сущим только добавляют негатива).
Интересное умозаключение. Поделитесь на чем оно основано? Jquery — это низкоуровневая библиотека-обертка над императивными манипуляциями в DOM, которая склоняла нас писать в event-based стиле. Svelte — это высокоуровневый компилятор SFC в ванильные компоненты без зависимостей, который склоняет к использованию реактивного декларативного state-based программирования. Я бы хотел узнать цепочку рассуждений, которая склонила вас полагать, что Svelte ближе к Jquery, нежели к React/Vue/Angular.
c() {
h1 = element("h1");
t0 = text("Hello ");
t1 = text(name);
t2 = text("!");
},
m(target, anchor) {
insert(target, h1, anchor);
append(h1, t0);
append(h1, t1);
append(h1, t2);
},
Вопрос — зачем? Если элемент статический и долгоживущий — почему на этапе компиляции не создать его один раз и потом не менять только содержимое, храня только ссылку на единожды созданный элемент?
Если постоянно динамически это делать, это серьезный удар по производительности (если, конечно, это не контент который меняется раз в сто лет), не говоря уже о размере кода который нужен для создания всех элементов (если их много).
Собственно сам browser намного быстрее всё отрендерит и построит из html, чем из js-кода, изменения только контента намного быстрее чем полное пересоздание элементов.
Пока же, увы, тенденция такова что темплейты в html просто тупо транслируются в js, фактически убивая всё то хорошее ради чего был создан собственно html (попробуйте ради интереса сделать в свелте <div>static text<div> — получите тоже кусок js).
Да, оно работает, в большинстве случаев достаточно быстро чтобы пользователи не видели разницы, но это всё равно неэффективно — как по использованию процессора, так и памяти.
Вопрос — зачем? Если элемент статический и долгоживущий — почему на этапе компиляции не создать его один раз и потом не менять только содержимое, храня только ссылку на единожды созданный элемент?
m — это операция mount, она выполняется только 1 раз. Смотрите функцию update, там всё именно так как вы хотели!
Нет, не будет:
p(changed, ctx) {
if (changed.name) {
set_data(t1, ctx.name);
}
},
Если вы сомневаетесь по поводу set_data — вот её реализация:
export function set_data(text, data) {
data = '' + data;
if (text.data !== data) text.data = data;
}
<div>static text</div>
создается посредством js: div = element("div");
div.textContent = "static text";
т.е. для сравнительного большого темплейта будет куча кода. А куча кода это куча кода — даже если он выполняется один раз.Зачем такой огород если можно просто скормить браузеру собственно html с нужными вставками?
Банальный <div>static text</div>
на самом деле не так уж прост. Браузер создаст все те же DOM-элементы внутри, что и мы сами руками, но при этом у нас не будет возможности переиспользовать div и обновить только textContent.
Еще есть вот такой доклад, например, в котором рассказывается об этом больше: https://habr.com/en/company/oleg-bunin/blog/310868/
Совсем нет. Существует ссылка на текстовую ноду — в нашем случае t1
. Эта нода и обновляется, нет необходимости заново рисовать весь компонент:
...
if (changed.name) {
set_data(t1, ctx.name);
}
...
PS: долго писал… уже объяснили
Я рад, что кто-то смотрит на скомпилированный код, прежде чем теоретизировать по поводу работы Svelte. Тот фрагмент кода, что вы указали, выполняется один раз при инициализации экземпляра данного компонента. Далее работа ведётся уже точечно с нужными нодами, обычно с текстовыми(напомню, что сам текст в элементе — это отдельная нода). Эти функции просто сокращения нативных функций Javascript для прямой работы с DOM: append(h1,t0)
это не что иное, как h1.appendChild(t0)
.
Если использовать в лоб node.innerHTML('...')
, то потом всё равно придется распарсивать DOM, чтобы получить ссылки на ноды(иначе как работать фреймворку?). Поэтому используется метод document.createDocumentFragment()
— тоже достаточно производительный и все ссылки имеются сразу.
Ещё можно использовать SSR с гидратацией. Это Svelte тоже умеет.
чтобы получить ссылки на ноды(иначе как работать фреймворку?)
getElementById() же, нет? Темплейт в слегка переработанном виде отдаётся браузеру, где надо расставляются id, по этим id один раз (при инициализации) берутся объекты, а дальше меняется только то что должно, без репарсинга. Компилятор ведь всё равно разбирает темплейт, так что создать эффективный код не должно быть проблемой.
Для любых контейнеров где внутри нет HTML достаточно будет менять innerText, а не innerHTML, можно даже делать это более эффективно, если «добавить воды»:
<div>Hello, {name}!</div>
транслируется в что-то типа:
<div>Hello, <span id="var-name" ></span></div>
после чего меняется только innerText в #var-name (адрес которого берется один раз).
И в любом случае, браузер гораздо быстрее и эффективнее разберет фрагмент html чем вы «вручную» будете его создавать в js посредством манипуляции DOM. Проведите эксперимент — создайте динамически (js) таблицу с большим количеством элементов, а потом её же но уже через установку innerHTML — разница будет ощутима.
Это хороший способ когда в разметке много статического содержимого. А вот если там, как и должно быть в компоненте, преимущественно динамика — выигрыш будет уже не таким заметным, если вообще будет.
. Проведите эксперимент — создайте динамически (js) таблицу с большим количеством элементов, а потом её же но уже через установку innerHTML — разница будет ощутима.
Не поленился — провёл. Вставка 1000 Div
. Мои результаты: innerHTML — 4ms, fragment — 9ms. Вы правы — разница более 2 раз не в пользу fragment. Но есть пара моментов:
- Бенчмарк не учитывает последующую работу с getElementById() в случае innerHTML
- После фрагмента у нас уже есть ссылки на все ноды в документе и не надо выдумывать ничего с getElementById() — что тоже заняло бы какое-то время.
- 9 мс это реально очень-очень-очень мало.
И да, 9 ms это конечно мало — но и элементов всего 1000. А если их 1000 и в каждом ещё по два десятка вложенных (если это табличка с расчётом на модификацию значений пользователем)?
А теперь представьте что это выполняется не на топовом железе а на средненьком мобильном или просто нетбуке — эти 9 ms легко могут превратиться во все 100 ms.
Мне кажется, если бы девелоперов заставить тестировать продукцию на слабом железе с ограниченными ресурсами, то ситуация с оптимизацией резко бы изменилась, но сейчас, увы, тенденция — наращивание мощности процессоров и памяти…
Тестируйте, пожалуйста, на всех моих устройствах результаты меняются в пределах погрешности.
А вот насчёт 1000 строк — это зависит. К примеру, когда я просматриваю события системы мониторинга или журналы — то бывает и по 10 тыс. строк, это гораздо удобней чем листать по 100. Опыт показывает что отдача браузеру маркапа (созданного либо на сервере либо в самом js) существенно ускоряет рендеринг.
Я думаю если появится такой «вумный» компилятор-фреймворк который всё оптимизирует примерно так как я описываю (код только там где невозможно обойтись html) — он очень быстро захватит мир.
В случае же если хочется их смотреть оффлайн — всё равно придётся вытащить всё сразу, все 10 тыс, так почему бы сразу их и не показать, благо скроллинг и поиск встроены и шустрее любой реализации на js?
Впрочем, речь не только о больших таблицах, посмотрите на любой гуглосайт (типа почты) — там при адекватном подходе количество кода (и маркапа) можно сократить минимум на порядок.
Да или просто первая страница яндекса — всё влезает на один экран, но там только одого js уже 500 кб (причём минимизированного) — вот о чём речь.
Простая, банальная страница после «фреймворкизации» превращается в монстра с кучей кода и горой модифицированных и распухших элементов, каждый из которых получает кучу классов и прочих атрибутов.
Может, вы привыкли смотреть страницы на чём-то с процом типа i8700 и 32GB памяти, но есть масса людей у которых всего 2G (из них половина сожрана системой, и ещё четверть всякой служебной фигнёй) и нечто вроде атома/арма — там всё это вызывает большую боль.
С этой точки зрения, Svelte выглядит более оптимальным вариантом, чем тот же react, но слегка жаль что не продолжает идею более глубокой оптимизации. Впрочем, возможно это и появится позже.
Есть предположение, что это скрипты яндексовской рекламы и фреймворки тут ни при чём.
Рекламные фреймворки там кушают не более трети, судя по всему. К тому же, я назвал размер с учётом адблока, явно грузится меньше чем могло бы.
Гора элементов с кучей классов и атрибутов не имеет никакого отношения к фреймворкам.
Я так думаю, это зависит от фреймворка. Некотоые из них явно сгенерированные, так что не вижу кто ещё мог это сделать.
Вы хотите обвинить меня в том, что я пишу неоптимизированные приложения?
Извините, ничего личного — речь шла об абстрактном «вы».
Большую часть кода в сложном приложении займут шаблоны компонентов, бизнес-логика и библиотеки зависимостей.
Какая бизнес-логика? Это UI, клиентская часть — там не должно быть бизнес-логики, разве что минимальная валидация. Задача браузера — это быстро и эффективно отображать UI, с учётом динамического изменения элементов — всё. Любой js который к нему отправляется должен решать только эту задачу, не более. Конечно, SPA/WebApp слегка другой вопрос, но фреймворки в основном используются не для SPA, и логика всё равно на стороне сервера.
А есть сравнение с Preact?
Он компактый и шустрый. Интересно, насколько тяжел Svelte в случае десятка компонент?
Настоящее реактивное программирование в Svelte 3.0