Современный фронтенд шагнул далеко вперед со времен jQuery и обычных HTML страничек. У нас появились сборщики, менеджеры пакетов, компонентный подход, SPA, SSR и много еще чего.
Кажется, что у нас есть все, что нужно для счастья. Но индустрия двигается вперед. Я хочу вам рассказать о компилируемом фреймворке Svelte, и какие преимущества у него есть перед аналогами.
Автор изображения Andrew Walpole
Google Trends
Для понимания текущей ситуации во фронтенде я проанализировал популярность запросов в Google Trends по ключевым словам React, jQuery, Vue, Angular в России за последние 5 лет.
Google Trends
За последние 5 лет количество запросов, связанных с jQuery значительно сократилось, уступив место компонентным фреймворкам. Хотя jQuery и сдал позиции, он до сих пор остается популярным средством разработки.
Из этого графика можно сделать вывод, что компонентные библиотеки победили во фронтенде, а лидером в России является React.
Рынок труда
Мы пишем код не только для себя, но и за деньги. В основном за деньги. Поэтому рассматривать популярность фреймворков в отрыве от рынка труда глупо.
По количеству вакансий на hh первое место занимает React, за ним следует jQuery и другие компонентные библиотеки. Если мы посмотрим на количество соискателей, которые указали в ключевых навыках рассматриваемые библиотеки, то jQuery знают в 5 раз больше соискателей, чем React. И в 15 раз больше, чем Angular.
Рынок труда
Из этого графика можно сделать следующие выводы:
- Компонентные фреймворки являются самыми востребованными среди работодателей, наиболее популярный среди них React.
- Среди соискателей самой распространенной библиотекой является jQuery.
Итак, компонентные фреймворки победили. Фронтенд решил проблемы, которые стояли перед разработчиками во времена jQuery. Но новые подходы порождают новые неприятности. Какие проблемы вижу я?
- Производительность.
В январе этого года Google анонсировал возможность публикации PWA приложений в google play, открыв дорогу javascript в магазин нативных приложений. Это накладывает определенную ответственность на разработчиков, ведь пользователи ожидают производительность нативных приложений, для потребителя не должно быть разницы.
Еще Javascript покоряет low powered devices. Это смарт TV, часы, IoT. На таких устройствах ограниченный бюджет памяти и процессора, поэтому разработчики не могут себе позволить расточительно обращаться с ресурсами пользователя.
У нас на работе есть опыт запуска React приложения на интернет хабе. Вышло так себе. - Высокий порог входа.
Как мы видели выше, большинство соискателей указывают в навыках jQuery, а не react. Освоить концепции React гораздо сложнее, чем подключить на страницу jQuery и начать творить. - Зависимость от фреймворка.
Если у вас есть библиотека компонентов, написанная на React, вы вряд ли сможете ее переиспользовать в проекте на Vue или Angular. Вы становитесь заложником экосистемы.
Svelte. Vanilla flavored.
В апреле этого года вышла третья версия компилируемого фреймворка Svelte.
Svelte предлагает разработчикам возможность писать высокоуровневый декларативный код, который после компиляции превращается в низкоуровневый императивный код. Еще это дает возможность делать эффективный tree shaking, и в итоге позволяет отправлять клиенту минимальный бандл.
Давайте посмотрим, какие решения Svelte предлагает для озвученных проблем
Поскольку React является самой популярной библиотекой на территории России, дальнейшие примеры будут на React.
1. Производительность
Если вы начинаете знакомство с новой библиотекой, то скорее всего начнете тур с ToDo листа. Это достаточно простая задача, которую, зачастую, проще написать на ваниле. Если вы хотите углубиться во фреймворк, то отличным выбором будет обзор Real World Application. Это блог, который, по сути, является клоном Medium. Здесь есть регистрация, авторизация, создание постов, комментирование, лайки. Специалисты по фреймворку пишут реализацию функционала и добавляют в коллекцию Real World Application.
На FreeCodeCamp вышла статья о сравнении Real World Application, написанных на разных фреймворках.
Если мы посмотрим на размер итогового бандла, то Svelte выигрывает у конкурентов. Клиенту отправляется всего лишь 9.7кб кода. Как результат, это меньше времени на передачу данных, парсинг и обработку вашего кода.
Сравнение размера бандла Real World Application
А еще самый лучший код — это не написанный код.
Если мы посмотрим на количество строк кода, которые необходимы для написания функционала приложения, то на Svelte потребуется около 1 000 строк, а на React около 2 000. Чем меньше кода в вашем приложении, тем меньше в нем багов и проще поддержка.
Сравнение размера объема кода Real World Application
Давайте посмотрим на производительность. js-framework-benchmark предлагает сравнение производительности рендеринга среди фронтенд фреймворков. Тест заключается в отрисовке таблицы с большим количеством строк. Далее производятся манипуляции с этой таблицей: частичное или полное обновление, создание, очистка, удаление строк.
По времени обновления Svelte показывает лучшее, либо сопоставимое время. Svelte очень сбалансирован, нет перекосов при выполнении разных типов операций.
Сравнение времени выполнения обновления, мс
Если мы посмотрим на объем потребляемой памяти, то Svelte является наименее прожорливым среди рассматриваемых библиотек.
Сравнение объема потребляемой памяти, мб
Я не привык верить на слово и решил проверить все сам. Я нашел реализацию бенчмарка DBMonster для фронтенда и переписал реализацию на React 16.8 и Svelte 3. Тест заключается в рендеринге таблицы и последующим обновлении строк.
Как выглядит тест DBMonster
В ходе теста Svelte потреблял на 10мб памяти меньше и производил обновления на 10 мс быстрее, чем React.
Svelte / React
Приведенные тесты являются синтетическими, но из них можно сделать вывод, что при разработке на Svelte из коробки вы получите:
- Меньший размер бандла
- Меньшее потребление памяти
- Более быстрые отрисовки.
2. Высокий порог входа
Если мы посмотрим на самый простой компонент на React, то вам потребуется импортировать сам React, написать функцию, которая вернет разметку и экспортировать ваш компонент. Итого 3 строчки кода.
import React from 'react';
const Component = () => (<div>Hello</div>);
export default Component;
Если мы посмотрим на самый простой пример компонента на svelte, то вы просто пишете разметку. Итого 1 строка кода.
<div>Hello</div>
Строго говоря, самый простой Svelte компонент — это пустой файл. Это дает возможность создать шаблон вашего приложения из пустых файлов, а затем начать разработку. При этом ничего не сломается.
Еще вы можете брать верстку, полученную от верстальщика, и сразу использовать ее как Svelte компонент без дополнительных преобразований. Валидный html является Svelte компонентом.
Хочу поделиться примером с собеседования на позицию middle react developer.
setFilter() {
this.switchFlag = !this.switchFlag
}
...
<button onClick={setFilter}>Filter</button>
Кандидат пытался сохранить состояние кнопки фильтрации напрямую в свойство класса. React, несмотря на свое название, недостаточно реактивный, чтобы реагировать на такие изменения. Это говорит о том, что даже middle разработчику сложно даются паттерны обновления состояния, которые использует React.
Давайте разберем пример кнопки, которая по клику увеличивает счетчик.
На React вам потребуется переменная для хранения состояния и функция, которая умеет обновлять состояние. Далее на саму кнопку нужно назначить обработчик для обновления. Итого у меня получилось 8 строк кода.
import React from 'react';
const Component = () => {
const [count, setCount] = React.useState(0)
return <button onClick={() => setCount(count + 1)}>
Clicked {count}
</button>
}
export default Component;
Для решения аналогичной задачи на Svelte вам потребуется переменная для хранения состояния. Далее в обработчике вы просто изменяете значение этой переменной. Итого 6 строк кода.
<script>
let count = 0;
</script>
<button on:click={()=>count+=1}>
Clicked {count}
</button>
Немного усложним пример. Допустим, нам нужно поле ввода, которое рядом выводит свое состояние
На React нам все так же потребуется переменная и функция для обновления состояния. Затем в поле ввода необходимо передать текущее значение и назначить обработчик на изменения. У меня в итоге получилось 11 строк кода.
import React from 'react';
const App = () => {
const [value, setValue] = React.useState('');
return (
<React.Fragment>
<input value={value} onChange={e => setValue(e.target.value)} />
{value}
</React.Fragment>
);
}
export default App;
Для решения этой задачи на Svelte вам потребуется переменная, которая хранит состояние, а затем просто сделать двустороннюю привязку в поле ввода. Итого 5 строк кода.
<script>
let value = '';
</script>
<input bind:value={value}/>
{value}
Если вам доводилось анимировать удаление элемента из DOM на React, то я вам сочувствую. На React потребуется либо враппер, который будет откладывать удаление элемента из DOM и производить анимацию, либо сам элемент остается в DOM, но анимация потребует управления свойством display или других манипуляций, чтобы элемент не занимал место.
Я пытался найти самую простую реализацию на React, в итоге получилось 35 строк кода. Если у вас есть решение проще, поделитесь в комментариях.
import React from "react";
import "./style.css";
const App = () => {
const [visible, setVisible] = React.useState(true);
return (
<React.Fragment>
<button onClick={() => setVisible(!visible)}>toggle</button>
<div className={visible ? "visible" : "invisible"}>Hello</div>
</React.Fragment>
);
};
export default App;
.visible {
animation: fadeIn 0.5s linear forwards;
}
.invisible {
animation: fadeOut 0.5s linear forwards;
}
@keyframes fadeOut {
0% {
opacity: 1;
}
100% {
opacity: 0;
display: none;
}
}
@keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
На Svelte аналогичный компонент требует всего 8 строк кода. В Svelte есть встроенный модуль для управления анимациями. Вы импортируете требуемый вид анимации, а затем говорите, как анимировать ваш компонент при добавлении и удалении.
<script>
import { fade } from 'svelte/transition';
let visible = true;
</script>
<button on:click={()=>visible=!visible}>toggle</button>
{#if visible}
<div transition:fade>Hello</div>
{/if}
Компилируемость позволяет Svelte предоставлять разработчику крутые абстракции. И если вы их не используете, они не попадут в итоговый бандл.
Например, в модуле transition есть крутой функционал crossfade, который позволяет анимировать компонент при переходе из одного DOM узла в другой. С помощью него можно сделать такой переход задач в ToDo листе.
Еще одним примером классных абстракций может служить директива use:. Она позволяет назначить кастомный обработчик на DOM элемент. В примере ниже производится обработка событий нажатия и перемещения, а также тач события с использованием всего одной функции.
После знакомства со Svelte, мои друзья обычно говорят, что они не испытывали такого удовольствия от фронтенд разработки со времен jQuery.
3. Зависимость от фреймворка
Когда появился React, в сети было большое количество виджетов на jQuery. Найти нужный компонент на React было сложно. Затем начали появлятся врапперы для jQuery виджетов, которые умели синхронизировать React и jQuery. После этого уже начали появлятся компоненты, написанные на самом React.
Сейчас подобная ситуация с самим React. Есть куча готовых решений и библиотек, которые не позволяют пересесть на другой фреймворк без боли.
Что предлагает Svelte? После компиляции ваш код превращается в обычный JS, который не требует рантайма. Это дает возможность использовать Svelte компонент в других фреймворках. Вам всего лишь потребуется один универсальный враппер. Например, адаптер для React и Vue svelte-adapter. Обернув компонент в адаптер, вы сможете использовать элемент, как обычный компонент.
import React from "react";
import SvelteSpinner from "svelte-spinner";
import toReact from "svelte-adapter/react";
const Spinner = toReact(SvelteSpinner, {}, "div");
const App = () => <Spinner size={50} />
Svelte поддерживает компиляцию в custom element, что еще больше расширяет границы применения компонентов. Посмотреть поддержку custom element различными фреймворками можно на custom-elements-everywhere.
Личный опыт
На работе писать на Svelte я пока не могу, поскольку мы плотно сидим на экосистеме React, но у меня есть личные проекты.
Ранее я писал, как опубликовал свое приложение Metalz в Google Play.
По моим ощущениям, Svelte позволяет писать более лаконичный и понятный код, при этом предоставляя широкий инструментарий для упрощения реализации.
Минусы
Как у любого молодого фреймворка, у Svelte небольшая экосистема готовых решений и мало статей, где можно найти лучшие практики. Поэтому сразу брать Svelte для больших проектов я бы не рекомендовал, поскольку можно в итоге зайти в архитектурный тупик.
Попробуйте Svelte на небольших проектах, уверен, вам понравится.