Что такое Svelte: фреймворк, который исчезает

Svelte — это не библиотека, которая работает в браузере. Это компилятор, который исчезает к моменту запуска.

«Svelte — это фреймворк без фреймворка: вы пишете компоненты, а на выходе получаете чистый, хирургически точный JavaScript, который напрямую трогает DOM.»

Когда вы впервые слышите слово «фреймворк», вы представляете большую библиотеку, которую браузер загружает и которая крутится в фоне, управляя вашим интерфейсом. React, Vue, Angular — все они работают именно так: вы отправляете пользователю и свой код, и движок фреймворка. Svelte ломает эту модель. Он делает основную работу не в браузере пользователя, а на вашем компьютере — во время сборки. Это сдвигает вычисления с устройства тысяч пользователей на ваш единственный CI-сервер.

Идея проста и радикальна одновременно. Вместо того чтобы отгружать в браузер универсальный движок, который умеет рендерить любой возможный интерфейс, Svelte анализирует именно ваши компоненты и генерирует ровно тот код, который нужен ровно вашему приложению. Если у вас есть счётчик, который увеличивается по клику, Svelte сгенерирует функцию, которая буквально говорит: «поменяй текст вот этого конкретного узла на новое число». Никаких абстракций поверх — только адресные операции с DOM.

Почему это важно для вас как для разработчика? Во-первых, итоговый бандл меньше: пользователю не нужно скачивать движок фреймворка, потому что его попросту нет в рантайме (точнее, он крошечный). Во-вторых, код быстрее, потому что между вашим состоянием и DOM нет посредника, который должен на каждое изменение пересчитывать виртуальное дерево. В-третьих — и это часто недооценивают — сам код, который вы пишете, короче и читается ближе к обычному JavaScript. Вы пишете count += 1, и интерфейс обновляется. Не нужно вызывать setState, не нужно оборачивать значение в хук.

Svelte создал Рич Харрис, разработчик из The New York Times, которому надоело, что интерактивные графики на сайте газеты тормозят на слабых телефонах читателей. Его наблюдение было точным: большую часть работы фреймворка можно сделать заранее, до того как код попадёт к пользователю. Эту идею он назвал «исчезающим фреймворком». Svelte 5, вышедший в конце 2024 года, довёл идею до зрелости, добавив систему рун — явных примитивов реактивности, о которых мы поговорим в следующем разделе.

Как это работает под капотом

Чтобы прочувствовать разницу, представим, что делает обычный фреймворк с виртуальным DOM при изменении одного числа, и что делает Svelte. Виртуальный DOM строит полную копию дерева в памяти, сравнивает её со старой копией (это называется диффинг), находит различия и применяет их. Svelte же на этапе компиляции уже знает, какой узел зависит от какого значения, и генерирует прямой вызов обновления.

  ОБЫЧНЫЙ ФРЕЙМВОРК (Virtual DOM)        SVELTE (компилятор)
  --------------------------------       --------------------------
  count++                                count++
     |                                      |
     v                                      v
  построить новое vDOM-дерево            update_node(text, count)
     |                                      |
     v                                      v
  diff(старое, новое)                    textNode.data = count
     |                                   (один точечный вызов)
     v
  применить различия к DOM

Обратите внимание: справа нет ни построения дерева, ни сравнения. Компилятор заранее проследил связь между переменной и узлом и вписал в код прямое присваивание. Это и есть «хирургические обновления» — термин, который вы будете часто встречать в мире Svelte.

Частые ошибки

  • Думать, что Svelte — это рантайм-библиотека. Это в первую очередь компилятор. Большая часть магии происходит при npm run build, а не в браузере.
  • Считать, что «ноль рантайма» — это буквально. У Svelte 5 есть небольшой рантайм для координации сигналов и эффектов. Он крошечный по сравнению с React, но он есть.
  • Сравнивать Svelte с React по размеру «hello world». Преимущество в размере проявляется на реальных приложениях, где движок фреймворка перестаёт окупаться.

Best practices

  • Воспринимайте .svelte-файл как описание, которое будет скомпилировано. Не пытайтесь запускать его как обычный JS.
  • Когда отлаживаете производительность, помните: узкое место обычно не в Svelte, а в вашей логике или сети.
  • Изучите вывод компилятора хотя бы раз — это снимает мистику и помогает понимать, что происходит.

Почему это важно на практике

Разница между компилятором и рантайм-библиотекой ощущается не в учебных примерах, а на реальных проектах. Когда вы выкатываете приложение на тысячи пользователей со слабыми телефонами и медленным интернетом, каждый килобайт движка фреймворка превращается в задержку загрузки и расход батареи. Svelte отгружает только то, что нужно вашему конкретному приложению, поэтому стартовый бандл получается компактным, а время до интерактивности — коротким. Это особенно заметно на встраиваемых виджетах, лендингах и приложениях для развивающихся рынков, где сеть нестабильна. По сути, вы платите за оптимизацию один раз — на этапе сборки, — а выигрыш получают все пользователи на каждой загрузке. Именно это сочетание малого размера, высокой скорости и приятного авторского опыта и сделало Svelte популярным выбором для проектов, где производительность не роскошь, а требование.

Итог: Svelte — это компилятор, превращающий декларативные компоненты в адресный императивный код. Он сдвигает работу с устройства пользователя на этап сборки, поэтому приложения получаются маленькими и быстрыми, а код, который вы пишете, остаётся близким к обычному JavaScript.

Проверьте себя
1. Чем Svelte принципиально отличается от React по способу работы?
ASvelte рендерит только на сервере
BSvelte — компилятор: основная работа происходит при сборке, а не в браузере
CSvelte использует более крупный виртуальный DOM
DSvelte вообще не поддерживает компоненты
2. Что означает фраза «хирургические обновления DOM» в контексте Svelte?
AПолная перерисовка страницы при каждом изменении
BПостроение копии дерева и его сравнение со старой версией
CПрямое адресное изменение конкретного узла, зависящего от изменившегося значения
DОбновление DOM раз в секунду по таймеру