Обзор фреймворка Jaspr (Dart)
Я не нашел на хабре достойного представления фрейморка Jaspr сообществу и решил представить сам. Flutter, безусловно, хорошая магия: один код для всех платформ, в том числе и Web. Но за магию приходится платить. Платить мегабайтами загрузки, муками с SEO и ощущением, что ты принёс на пляж боулинг — вроде и весело, но как-то не к месту. Команда Flutter и сама честно говорит: Flutter Web создан для веб-приложений, а не для веб-сайтов. Для сложных дашбордов, PWA, для всего, что живёт за логином — да. Для контентного сайта, блога, лендинга — увы.
И вот, пока мы спорим, нужен ли Dart в вебе и не проще ли взять старый добрый TypeScript, из тени вышел проект, который предлагает не воевать с вебом, а подружиться с ним.
Знакомьтесь, Jaspr. Веб-фреймворк на Dart, который осознанно отказывается от канваса и пиксельной магии Flutter в пользу старого доброго HTML и CSS. Он выглядит как Flutter, ощущается как Flutter, но на выходе даёт то, что поисковики и браузеры любят и понимают: обычный HTML-документ и DOM. А попробовать на вкус его можно здесь.
Это не «ещё один фреймворк». Это другой подход. И, возможно, именно тот, которого так не хватало экосистеме Dart, чтобы наконец-то стать полноценным фулстек-инструментом.
Философский камень: в чём фундаментальное отличие от Flutter Web?
Чтобы понять Jaspr, нужно понять его главный принцип: он не абстрагируется от веба, а принимает его. Flutter Web говорит: «Неважно, что ��од капотом — браузер, десктоп или холодильник. Ты пишешь на Flutter, а я сам разберусь, как это нарисовать». Он создаёт свой мир внутри тега <canvas> и полностью контролирует каждый пиксель.
Jaspr говорит иначе: «Ты в браузере. У тебя есть DOM, есть CSS, есть семантические теги. Давай использовать их». Когда вы пишете в Jaspr компонент p([text('Hello Habr')]), он не рисует пиксели, имитирующие текст. Он генерирует нативный тег <p>Hello Habr</p>.
Это простое, но кардинальное различие меняет всё:
Производительность и SEO. Вместо многомегабайтного движка для рендеринга пользователь получает лёгкий HTML. Страница отображается заметно быстрее, поиск видит осмысленный контент, а не flutter.js и пустой <body>. Для любого контентного или коммерческого сайта это важный показатель.
Экосистема. Вы можете использовать любую CSS-библиотеку. Tailwind, Bootstrap, Bulma — что угодно. Вы можете интегрировать существующие JavaScript-библиотеки. Вы работаете с вебом, а не внутри «чёрного ящика».
Привычные инструменты. Забудьте о Row и Column. Для раскладки вы используете Flexbox и Grid — стандартные, мощные и предсказуемые инструменты CSS. Это заставляет переключить мышление с «мобильного» на «вебовое», но в долгосрочной перспективе это правильный путь.
Jaspr — это не попытка запустить мобильное приложение в браузере. Это полноценный веб-фреймворк, который просто использует очень знакомый и удобный синтаксис, вдохновлённый Flutter.
Архитектура «под капотом»: SSR, SSG, гидратация и другие страшные слова
Jaspr — это не просто библиотека для рендеринга. Это современный фулстек-фреймворк, который поддерживает все актуальные режимы работы. И всё это — на чистом Dart.
SSG (Static Site Generation). Генерация статического сайта. Вы пишете код, запускаете jaspr build, и на выходе получаете пачку HTML, CSS и JS-файлов, которые можно хостить где угодно — от GitHub Pages до любого CDN. Идеально для блогов, лендингов, сайтов-документаций. Кстати, официальные сайты dart.dev и docs.flutter.dev собираются с помощью Jaspr, что немного намекает на серьёзность проекта.
SSR (Server-Side Rendering). Рендеринг на стороне сервера. Пользователь запрашивает страницу, ваш сервер на Dart генерирует HTML и немедленно отдаёт его в браузер. Пользователь видит контент сразу, а поисковики счастливы.
Client-Side Rendering (SPA). Классический одностраничник. Сервер отдаёт минимальный HTML, а дальше всё рендерится на клиенте.
Автоматическая гидратация. Это самая мякотка. В режимах SSG и SSR, после того как пользователь получил готовый HTML, Jaspr незаметно подгружает клиентский JS, «оживляет» страницу, восстанавливает состояние компонентов и навешивает обработчики событий. Статический сайт превращается в интерактивное SPA без единого скачка или перезагрузки.
Все эти подходы можно комбинировать. Например, главную страницу отрендерить статически, а личный кабинет — на клиенте. Такая гибкость даёт огромные возможности для оптимизации.
Как это выглядит в коде? Придётся ли переучиваться?
Если вы писали на Flutter, то 80% синтаксиса Jaspr вам уже знакомы.
import 'package:jaspr/jaspr.dart'; void main() { runApp(App()); } class App extends StatefulComponent { const App({super.key}); @override State<App> createState() => _AppState(); } class _AppState extends State<App> { int count = 0; @override Component build(BuildContext context) { return div([ text('Count is $count'), button( onClick: () { setState(() => count++); }, [text('Press Me')], ), ]); } }
Что мы здесь видим?
StatelessComponentиStatefulComponent— старые добрые знакомые.setState()работает точно так же, как мы привыкли.Декларативный подход: мы описываем состояние UI, а фреймворк сам разбирается, как его обновить в DOM.
Но есть и важные отличия, продиктованные самой природой веба:
Возвращаемый тип
Iterable<Component>. Методbuildвозвращает не один виджет, а итерируемую последовательность. Это позволяет вернуть несколько компонентов на одном уровне, как это естественно для HTML (<li>Item 1</li><li>Item 2</li>). Для этого используется синтаксисsync*и ключевое словоyield.HTML-теги вместо виджетов. Вместо
Text,Container,Paddingвы используете функцииtext(),div(),p(),img(), которые напрямую соответствуют HTML-тегам.Стилизация через CSS. Стили — это не
TextStyleилиBoxDecoration. Это обычные CSS-классы или инлайн-стили, которые вы передаёте в компонент. Jaspr не навязывает вам свой способ стилизации, а даёт работать с нативными инструментами.
Dart для фулстека. Почему это имеет смысл?
Главное преимущество Jaspr — это возможность построить всё приложение, от фронтенда до бэкенда и базы данных, на одном языке. Dart для этой роли подходит идеально:
Строгая типизация и null-safety. После хаоса в мире JavaScript это как глоток свежего воздуха. Большая часть ошибок отлавливается на этапе компиляции.
Общий код. Вы можете использовать одни и те же модели данных, бизнес-логику и утилиты на клиенте и на сервере. Больше никаких проблем с синхронизацией и сериализацией.
Производительность. На сервере Dart компилируется в быстрый нативный код, а в разработке есть JIT-компиляция с хот-релоадом.
Зрелая экосистема. Большинство типичных пакетов с pub.dev (HTTP-клиенты, работа с данными, управление состоянием), не завязанных на Flutter, прекрасно работают в Jaspr-проекте.
Jaspr отлично интегрируется с серверными фреймворками на Dart, такими как Shelf, Dart Frog или Serverpod. Это позволяет строить по-настоящему монолитные (в хорошем смысле) и при этом поддерживаемые системы.
Управление состоянием: Riverpod и старые друзья
Как управлять состоянием? Так же, как вы привыкли. Поскольку Jaspr — это Dart, вы можете использовать знакомые пакеты:
jaspr_riverpod: специальная версия Riverpod для Jaspr, которая поддерживает SSR и синхронизацию состояния между сервером и клиентом.jaspr_bloc: портflutter_blocдля любителей BLoC-подхода.Provider,GetItи любые другие DI-контейнеры и стейт-менеджеры, не завязанные на Flutter, тоже будут работать.Пример RiverPod:
import 'package:jaspr/jaspr.dart'; import 'package:jaspr_riverpod/jaspr_riverpod.dart'; void main() { runApp(ProviderScope(child: App())); } final counterProvider = StateProvider((ref) => 0); class App extends StatelessComponent { const App({super.key}); @override Component build(BuildContext context) { return div([ Builder( builder: (context) { var count = context.watch(counterProvider); return text('Count is $count'); }, ), button( onClick: () { context.read(counterProvider.notifier).state++; }, [text('Press Me')], ), ]); } }
Вам не нужно учить Redux, MobX или Zustand. Вы остаётесь в привычной и комфортной экосистеме.
Ложка дёгтя: чего не хватает?
Jaspr — молодой фреймворк, и было бы нечестно говорить, что он идеален.
Нет готовых UI-компонентов. Здесь нет аналогов Material или Cupertino. Кнопки, поля ввода, модальные окна — всё это придётся стилизовать с нуля или использовать сторонние CSS-фреймворки. Это не минус, а особенность, но к этому нужно быть готовым.
Небольшое сообщество. Пока что сообщество Jaspr невелико. Найти готовое решение на Stack Overflow будет сложнее, чем для React. Зато есть активный Discord-сервер, куда зовут прямо из официальных ресурсов Jaspr — там можно получить помощь, в том числе от автора фреймворка.
Экосистема в стадии становления. Ещё не для всего есть готовые «jaspr-обёртки». Иногда придётся писать немного кода для интеграции с JS-библиотеками, используя
dart:js_interop.
Так кому и зачем нужен Jaspr?
Jaspr — это не «убийца React» и не замена Flutter Web. Это прагматичный инструмент для конкретных задач.
Jaspr — ваш выбор, если:
Вы Flutter-разработчик и вам нужен сайт: лендинг, блог, документация. Вы сделаете его на знакомом языке и сэкономите массу времени.
Вы хотите писать фулстек на Dart: шарить код между клиентом и сервером и иметь единую кодовую базу.
Вам нужен быстрый, SEO-дружелюбный сайт: новостной портал, маркетплейс, любой проект, где важна скорость первой загрузки и индексация.
Вы устали от JavaScript-фреймворков и хотите попробовать что-то новое, но при этом строго типизированное и предсказуемое.
Попробовать самому. Это проще, чем кажется
Начать работать с Jaspr невероятно просто.
Устанавливаем CLI:
dart pub global activate jaspr_cli
Создаём проект:
jaspr create my_awesome_site
CLI предложит пройти небольшой мастер и выбрать параметры проекта (в том числе режим рендеринга: static, server или client).
Запускаем в режиме разработки:
cd my_awesome_site jaspr serve
Сервер поднимется с хот-релоадом, и можно начинать творить.
А для тех, кто хочет просто «пощупать» фреймворк без установки, есть онлайн-песочница JasprPad — аналог DartPad, написанный на самом Jaspr.
Заключение: тихая революция
Jaspr не кричит о себе на каждом углу. Он просто делает свою работу: даёт Dart-разработчикам возможность создавать современные, быстрые и нативные для веба сайты. Он заполняет ту самую нишу, которую не смог (и не должен был) закрыть Flutter Web.
Это эволюционный шаг для всей экосистемы Dart — шаг от «языка для мобилок» к полноценному инструменту для фулстек-разработки. И, возможно, через пару лет, когда очередной JavaScript-фреймворк объявит о своей смерти, мы просто пожмём плечами. Ведь у нас будет свой, скучный, надёжный и очень мощный инструмент на строгоми четком языке программирования. И имя ему — Jaspr.
