Leptos: фулстек на Rust без виртуального DOM

Технологии
21 сентября 2026 Время чтения 4 мин

Этот сайт собран на Leptos: страницы рендерит на Rust сервер под управлением Axum, а интерактив — квиз «Рассчитаем проект за 2 минуты», фильтры кейсов — оживает в браузере на WebAssembly. Один язык, одна система типов и одна экосистема на весь стек. Разбираемся, как устроен этот фреймворк, чем он отличается от привычных JavaScript-инструментов и в каких проектах имеет смысл.

Leptos — фулстек-фреймворк: на нём пишут и серверный рендеринг, и клиентские интерфейсы. Ключевая идея — принести в Rust тонкодробную реактивность (fine-grained reactivity), подход, который прославил SolidJS и который сами авторы Leptos называют источником вдохновения, — и дополнить её SSR, гидрацией и серверными функциями «из коробки».

Сигналы вместо виртуального DOM

В React изменение состояния запускает перерисовку компонента: виртуальный DOM сравнивается с прошлой версией, и разница применяется к странице. Leptos идёт другим путём. Состояние — это сигналы, и каждый фрагмент DOM подписан только на те сигналы, от которых зависит. Изменился сигнал — обновился ровно один текстовый узел или атрибут. Ни diffing, ни повторного выполнения компонента нет в принципе.

use leptos::prelude::*;

#[component]
pub fn Counter() -> impl IntoView {
    let (count, set_count) = signal(0);

    view! {
        <button on:click=move |_| set_count.update(|n| *n += 1)>
            "Счётчик: " {count}
        </button>
    }
}

Выражение {count} внутри view! подписывается на сигнал напрямую: при клике обновится только текст на кнопке, а не весь компонент. Благодаря макросу разметка проверяется компилятором — опечатка в атрибуте или несовпадение типов пропсов это ошибка сборки, а не баг в рантайме браузера.

Заимствованная у Solid модель даёт знакомую эргономику: сигналы, мемоизация, эффекты. Подробнее об этом подходе в JavaScript-мире — в обзоре SolidJS.

Один стек: SSR, гидрация и серверные функции

Leptos рендерит страницу на сервере, отдаёт готовый HTML и «оживляет» его в браузере — гидрация без повторного рендера. Для общения клиента с сервером есть серверные функции:

#[server]
pub async fn submit_quiz(contact: String) -> Result<bool, ServerFnError> {
    // выполняется только на сервере: БД, SMTP, секреты
    save_lead(&contact).await?;
    Ok(true)
}

Снаружи это обычная async-функция: клиент вызывает её как локальную, а компилятор генерирует RPC-обёртку. Тело функции выполняется только на сервере — там доступны база данных, отправка почты и всё, что не должно попадать в браузер. Под капотом Leptos интегрируется с Axum или Actix Web; наш сайт работает поверх Axum.

Сборка двух таргетов описывается декларативно:

[features]
hydrate = ["leptos/hydrate", "dep:wasm-bindgen"]
ssr     = ["dep:axum", "dep:leptos_axum", "leptos/ssr"]

Инструмент cargo-leptos собирает серверный бинарник и WASM-бандл для браузера. Для клиентского профиля включают opt-level = "z" и LTO — на таких настройках WASM получается компактным. А за счёт SSR и гидрации в браузер не грузится лишний JavaScript: каркас страницы приходит готовым с сервера, и на клиент не выносятся ни шаблоны, ни данные.

Сильные и слабые стороны

  • Тонкодробная реактивность: обновления DOM без diffing, быстрый отклик
  • Один язык и одна система типов для клиента и сервера — рефакторинг по всему стеку
  • SSR, SEO и серверные функции из коробки
  • Компактный рантайм: виртуальный DOM не тянется в браузер
  • Ошибки разметки и типов ловятся на этапе компиляции

Обратная сторона:

  • Экосистема заметно меньше, чем у React или Vue: меньше готовых UI-китов и интеграций
  • Порог входа выше: нужны и Rust с borrow checker, и реактивная модель мышления
  • Найм веб-разработчиков на Rust сложнее, чем на мейнстримные стеки
  • JS-библиотеки (карты, чаты, аналитика) приходится оборачивать вручную

Когда выбирать Leptos

Leptos хорош, когда проекту нужны и SEO, и живой интерфейс: лендинги с формами, SaaS-панели, админки, внутренние сервисы. Особенно выигрышен он для команд, которые уже пишут бэкенд на Rust: фулстек на одном языке убирает целый слой проблем на стыке. Если же задача — массовый продукт на готовых компонентах и рынок диктует JavaScript, зрелость экосистемы React по-прежнему перевешивает.

Заключение

Leptos — самый цельный ответ на вопрос «зачем Rust в вебе»: одна кодовая база обслуживает и сервер, и браузер, а производительность и типобезопасность перестают быть компромиссом. Фреймворк ещё молод, и его экосистема догоняет мейнстрим, — но именно за такими инструментами будущее типизированного веба.

Этот сайт — живой пример: он полностью собран на Leptos и Axum. О том, почему собственные сервисы мы пишем на Rust, — в статье Rust и Zig в привычных приложениях.

Обсудим ваш проект?

Расскажите о вашей задаче — вернёмся с оценкой сроков и стоимости в течение двух рабочих дней.

Обсудить проект