Pull to refresh

Comments 20

Спасибо за еще один фреймворк

Здравствуйте! На практике нет так уж много фреймворков в реальности используют. По сути сейчас реакт-фулстек потребности закрывают React Router, Next.js, TanStack Start, на сколько я знаю. Остальные очень ситуативные. Так что, если Point0 удастся реально занять эту нишу по причине того, что он окажется в чём-то удобнее для разработчиков, то будет хорошо 🙂

А чем не угодил последний Angular? Один из самых удобных и "все из коробки" фреймворков

Здравствуйте, по третьей строчке кода узнал вас 🙂, проходил курс.
Удачи с развитием фреймворка!

Здравствуйте! Спасибо большое! 🙂

Я конечно все понимаю, но личный сайт не работает. Либо что-то-там-украина-европа-блокировки-пшел-я-на-х.

Починил. Большое спасибо, что подсветили. Включал CDN через bunny net, и видимо оно иногда убивает доступы из РФ

Очень крутая идея и реализация. Сначала подумал "еще один фреймворк", но когда увидел схожесть с trpc, когда увидел простые примеры и настолько читаемые, то был в восторге)

Но эта статья - документация. Если хочется продвигать библиотеку, кажется нужно показать меньше примеров, но которые бьют в самое сердце)

Спасибо большое! Мне согрел душу ваш комментарий 🙂 Я просто не знал как вообще описать фреймворк коротко, но чтобы стало понятно какой он. Потому что там будто бы одно за другое цепляется, и у меня глаза разбегаются, не знаю что показать, и остановиться. В итоге психанул и всё показал)

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

Планирую скоро выложить уже короткие статьи:
- Сравнение подхода к разработке с tRPC на банальных примерах, с объяснением выгод
- Бенчмарки в сравнении с Next.js и TanStack Start
- Как сделать MVP хабра на Point0 (как раз это будет коротенькая статья в которой всё видно)

фреймворк сопоставимый по функционалу с Next.js


Не нашёл в вашем коде реализацию SRC. Без неё утверждение, на мой взгляд, сомнительное.

И следом вопрос: в чём преимущество вашего решения в плане DX по сравнению с тем же Waku?

Здравствуйте! И Waku, и ваш вопрос про RSC говорят об одном: для вас RSC важная вещь, и, как я понял, Waku на него полностью и ориентирован. В случае Point0 в RSC, как мне пока кажется, буквально нет смысла, потому что у нас все компоненты клиентские, то есть в каждом доступны нормальные хуки и все прочие прелести клиентских компонентов. При этом каждая страница и так подгружает только те компоненты, которые ей нужны. А при переходе между страницами мы вообще не грузим лишний HTML: только недостающие JS-чанки и сырые данные с сервера — это заметно меньше байтов. И всё, что грузится с сервера для страниц, — это react-query: оно отлично кешируется и полностью управляемо по стандартам react-query. Кроме того у нас каждый компонент может обладать своими лоадерами или встроенными в него кверями, а эти компоненты как угодно могут быть встроены в любые страницы. Кроме того мы можем быть полностью SPA приложением если захотим, или частично, отрубая SSR на каждой отделдьной странице.

Технически я мог бы разрешить возвращать React-компонент прямо из лоадера и получился бы аналог RSC. Но я искренне не понимаю, что это дало бы поверх того, что уже есть. RSC продают как способ гонять меньше на клиент. Но на навигации выходит наоборот: RSC пересылает отрендеренную разметку заново, как flight-payload, а дата-лоадер шлёт только данные. В моём бенчмарке на переходе «дашборд → дашборд» Next возит 1 355 байт на клик против 474 у Point0 — примерно втрое больше, потому что переотправляет разметку, которая у клиента уже есть. То есть ровно на той оси, где RSC должен выигрывать, дата-лоадер его обходит. Это не баг Next, это архитектура RSC, просто на SaaS-навигации она проигрывает.

«Сопоставим с Next» — это про объём возможностей, а не про одну фичу. RSC одна из стратегий реализации, которую Next выбрал в 2023-м, а не определение фулстек-фреймворка. Next был Next-ом и до RSC. Сопоставимость по функционалу — это страницы, лэйауты, типизированный роутер, SSR, head, ассеты, MDX, env, OpenAPI, деплой. Всё это есть. Наличие конкретно RSC отдельный вопрос, и те задачи, что решает RSC, у меня уже решены другими средствами.

Про Waku конкретно (по DX). Waku минималистичный фреймворк, но он построен вокруг RSC: файловый роутинг, async-серверные компоненты, а когда клиентскому компоненту нужны данные — он руками делает fetch('/api/...') и сам парсит JSON, сам держит loading/error. Сквозной типизации клиент↔сервер и слоя кеширования из коробки там нет. У Point0 данные между клиентом и сервером типизированы насквозь без кодогенерации, всё едет на react-query с кешем, инвалидацией и SSR-гидрацией из коробки, и файловый роутинг не обязателен, состояние загрузки и ошибки также обрабатывает фреймворк и вы это полностью кастомизируете. Разница философская: Waku — минимальный RSC-first фреймворк, Point0 — ол-инклюзив вокруг типизированного слоя данных (в духе tRPC), а не вокруг RSC.

Кстати, только сегодня доделал бенчмарки против Next.js и TanStack Start https://github.com/1gr14/point0-benchmarks (там все цифры, скоро бует статья отдельная по бенчмаркам) Если коротко по скорости DX: HMR на клиенте у Point0 в 3 раза быстрее, чем у Next.js, и более чем в 10 раз быстрее, чем у TanStack Start (15 мс против 45 и 164), и етсь ещё преимущества, но и отставания тоже кое-где есть.

И ещё: мне ближе сравнивать себя по DX не с Next, а с tRPC. Все единицы кода — просто билдеры, всё ощущается очень просто. Никаких соглашений и файлового роутинга: мутации, квери, страницы и прочее можно объявлять хоть в одном файле. Удобно бить код по модулям, а не держать все страницы в одной папке, а все API-запросы — в другой.

Если у вас есть конкретный кейс, где именно RSC решает то, что у нас решается хуже, я буду прямо рад и узнать, и с точным пониманием дела интегрировать RSC в Point0. И спасибо вам больше за комментарий! Я очень ждал вопросов по делу 🙂

Как я вижу, у некста будет из коробки преимущество по сравнению с текущем подходом:

1. SSR + Streaming + вложенные Suspense

Сервер стримит HTML по мере готовности данных. 

Тяжёлая страница с 10 блоками не ждёт, пока отрезолвятся все запросы, каждый блок прилетает отдельным чанком через Suspense. 

Клиент видит шелл мгновенно (FCP), а контент подтягивается частями.

В Point0 с клиентскими компонентами это эмулировать можно, но это либо общий лоадер страницы, либо куча ручной обвязки. 

И всё равно лишний round-trip: сначала JS-чанк + гидратация, потом запросы за данными.

2. Многоуровневое кэширование

Тут сейчас один слой react-query на клиенте (кэш сырых данных). 

В Next.js — 6 слоёв, каждый настраивается отдельно:

Request Memoization: дедупликация fetch внутри одного рендера (то что даёт react-query из коробки).

Data Cache: кэш результатов на сервере между запросами.

Full Route Cache: кэш готового HTML + RSC-пейлоада маршрута.

Router Cache: клиентский кэш RSC-пейлоадов (бэки/форварды без повторных запросов).

Static Assets Cache: браузерный кэш статики.

Edge/CDN Cache: кэш на уровне CDN (без nginx перед node вообще всё ляжет на более-менее серьёзных нагрузках).

Плюс в Next.js есть директива 'use cache' 

То есть в Next.js кэшируются не только данные, но и готовый HTML, сериализованный поток и состояние роутера — с гибкой ревалидацией (ISR, on-demand, time-based) на каждом уровне.

Про SSR, стриминг и Suspense.

Тут вы правы в сути. Классического потокового SSR, когда сервер отдаёт HTML блок за блоком по мере готовности каждого запроса в одном ответе, у нас сейчас нет. Рендерер под капотом потоковый, поэтому шелл улетает клиенту сразу. Но модель данных другая. По умолчанию фреймворк сначала находит все квери страницы, грузит их, и только потом рендерит. Данные готовы до финального рендера, а не прилетают кусками через Suspense.

Что есть вместо этого. На любой компонент можно повесить .clientOnly(() => <Spinner/>). Тогда он не участвует в SSR. Страница возвращается сразу, с шеллом и всем остальным контентом уже отрендеренным, а этот блок показывает лоадинг и догружает данные на клиенте. Мгновенный шелл и прогрессивная подгрузка тяжёлых блоков получаются, только по-компонентно и осознанно, а не автоматически через Suspense.

И честный минус ровно тот, что вы назвали. Это клиентский round-trip. Данные блока едут отдельным запросом после гидрации, а не в том же HTML. Для контентной страницы, где важны SEO и первый рендер, это хуже стриминга. Для SaaS-дашборда за авторизацией, где SEO не нужен, это обычно ровно то поведение, что и хочется, а запрос дешёвый, потому что мы шлём только данные, сотни байт, а не разметку. Настоящий поблочный стриминг это разумно добавить позже, рендерер и так уже потоковый. Пока его нет, говорю как есть.

Про многоуровневое кэширование.

Тут я разверну рамку. Шесть слоёв в Next это во многом следствие RSC. Как только вы кэшируете сериализованный RSC-пейлоад и готовые роуты, нужна целая иерархия, чтобы всем этим управлять. И она путаная настолько, что автоматическое кэширование удивляло людей. У нас типов артефактов для кэша меньше, поэтому и слоёв меньше. По вашим пунктам.

Request Memoization. Есть. Это react-query, дедупликация одинаковых квери в одном рендере из коробки, вы сами отметили.

Router Cache для back и forward. По сути тоже есть. Данные лежат в react-query на клиенте, назад и вперёд ничего не перезапрашивают, если не протухло, а JS-чанки уже загружены. Просто это не отдельный слой, а тот же react-query, и он целиком под вашим контролем через staleTime и прочее.

Static Assets Cache и CDN. Это вообще не про фреймворк. Заголовки кэша вешаются мидлварой, CDN ставится сверху у любого провайдера, гзип и что угодно настраивается произвольно. Одинаково у всех.

Full Route Cache, готовый HTML плюс RSC-пейлоад. RSC у нас нет, значит и пейлоада нет. А сам HTTP-ответ для того, что кэшируемо, кэшируется мидлварой или на CDN, как на любом сервере. Для динамической страницы под конкретного юзера Full Route Cache и в Next не спасает.

Data Cache, use cache, ISR. Это поятьже просто реализуется в самом лоадере делаете request.state.cache = true (просто произвольное название переменной в стэйте), ловите мидлварой, елси там тру, тогда кешируете, если не тру, не кешируете. То есть это всё очень простоые штуки, которые не стоит прятать во фреймворк, это всё можно сделать под каждый проект как угодно. В плоть до просто сверки объёма возвращаемых аднных или часто ты их запросап, без разницы.

Итого по кэшу это не один слой против шести. Это скорее так: фреймворк не навязывает вам иерархию кэшей, а даёт кэшировать ровно то, что меняется, то есть данные на react-query. Всё остальное это стандартное веб-кэширование, которое вы вешаете мидлварой там, где хотите, и контролируете на каждом этапе. Причём одну и ту же функцию кэша можно переиспользовать между проектами, а не настраивать шесть слоёв заново.

Я не пытался сделать новый Next.js который будет лучше старого Next.js. Я хотел сделать приниципиально новую штуку с точки зрения ощущения собственного кода в момент разработки, которую я ощущаю как глоток свежего воздуха, и просто радуюсь писать на ней код. Сам код я считаю получается красивым, читаемым, простым и прямым.

В целом удовлетворённость (не популярность, а удовольствие от использования) Next.js среди разработчиков ежегодно падает, и уже вообще скатилась до 55% https://share.devographics.com/share/prerendered?localeId=so-SO&surveyId=state_of_js&editionId=js2025&blockId=meta_frameworks_ratios&params=&sectionId=libraries&subSectionId=meta_frameworks Но всё что хорошего в нём есть, Point0 способен впитать (по сути если я просто добавлю в лоадеры возможность вернуть React Compoennt и добавлю флаг в нстройки грузить всё до отдачи HTML или грузить через Suspense, то всё что мы обсуждали сразу пояится и в Point0)

ИМХО, отсутствие потокового SSR, использование .clientOnly(), кэширование через react-query и кастомные мидлвари, по сути, откат к архитектуре Next.js 13 (Pages Router) до эры RSC. Просто старая добрая SPA/SSR модель.

Если мы говорим про реальное, а не косметическое ускорение на клиенте и сервере, то оптимизировать Node.js и react-query, кажется тупиковый путь. Сам Node.js объективно узкое место.

Если хочется выйти на новый уровень производительности, стоит смотреть в сторону отказа от Node.js в пользу системных языков. Например, проект Rari (https://rari.build), который пошел именно по этому пути: HTTP-сервер, роутер и рендерер RSC написаны на Rust (с встроенным снепшотом V8 для выполнения JS). По бенчмаркам это даёт ~58x ускорение на статике и ~550x на fetch по сравнению с Next.js (https://github.com/jarick/rari-vs-nextjs/blob/main/docs/article.md). За счет того, что тяжелая инфраструктурная часть работает на нативном коде, а не на асинхронном event-loop Node.js, показывается кратный рост пропускной способности и скорости отклика.

Но если развить эту идею до логического предела, то возникает еще более радикальный вопрос: а нужен ли нам вообще V8 на бэкенде? Мы платим за гибкость JS: Garbage Collection, оверхед на event-loop, проблемы с потреблением памяти на каждый запрос.

Если представить следующую эволюцию, в моём понимании это собственный AOT-компилятор (Ahead-of-Time) для React/JSX, который компилирует серверные компоненты и Server Actions напрямую в машинный код. В такой архитектуре для рендеринга на сервере вообще не нужен тяжелый JS-рантайм. Нет GC, нет event-loop, нет проблем с памятью. Сервер просто выполняет скомпилированные функции, собирает HTML/поток и отдает его с околонулевой задержкой.

При этом если говорить про DX, то лично моё мнение: у RSC и директивы ‘use cache’ он на порядок выше, чем у middleware-решений.

Я думаю ваш ход мысли в сторону скорости загрузки, оптимизаций, точно верный. Я просто в целом из другого лагеря, мне (как разарботчику который использует фреймворк для своих проектов, а не как разработчику самого фреймворка) всё равно будет сайт грузить в 100 раз быстрее или 100 раз медленне, учитывая что речь идёт про 0,001ms vs 0,1ms а по факту рядом с ними сядет 15ms запрос в бд, и ещё сеть, и вообще не будет никакой разницы. Я просто хочу писать красивые DSL конструкции, мешать код бэка с кодом фронта на одном и том же языке, и наслаждаться кодом своих проектов.

Я вообще начинал когда фреймворк делать, я просто хотел чтобы работали DSL конструкции мои, а оказалось, что чтобы они реально здорово работали надо фреймворк написать. Я думал я вообще за 2–3 недели всё накидаю, ну максимум месяц, а получилось все 10...

Эта логика работает только в том случае, если нет нагрузки. Если сайтом пользуются активно, то BFF на Node.js может легко стать узким местом. Именно поэтому DevOps-ы недолюбливают Node на серверах.

Next.js весьма сложен внутри. Там под капотом свой сборщик (Turbopack на Rust), свои плагины для SWC под директиву use cache. Parallel Routes и Intercepting Routes вообще крайне сложные штуки по своей сути в реализации. Его пилит выделенная команда фултайм. Так что сделать свою замену, которой начнут пользоваться ... прямо скажем, прыгнуть сильно выше головы. Для этого нужны явные преимущества перед Next.js.

По сути, из всех попыток можно отметить только Waku, но там автор мягко говоря непростой, и за ним стоит огромное комьюнити.

Ну у нас всё же не Node.js а Bun, это другое. И Tanner Linsley тоже сделал свой TanStack Start, а он просто крутой разраб, но он не компания. Я светло верю, что Point0 найдёт свою аудиторию. Я точно буду рад им пользоваться для своих проектов. И тем более сейчас становится меньше разработчиков в крупных компаниях, которым нужны все эти низкоуровневые заморочки для нереального трафика, потому что их увольняют и усиливают условно лучших разрабов ИИ инструментами. В тоже время разработчиков, которые работают в маленьких компаниях становится больше, потому что маленьких компаний организующих у себя разработку становится больше, благодаря удешевлению стоимости разработки. А там как раз и нужны прикольные инструменты, с ккоторыми приятно работать и легко поддерживать. Я хочу к этим ребятам. А там того и гляди, чего крупным игрокам не хватет, со временем в Point0 донесу, и ГГ ВП.

Самый лучший и самый удобный фреймворк сейчас это последний Angular... Хоть что то с классами, нормальным DI итд

Честно похоже на франвенштейн. Зачем смешивать бакенд и фронтенд вместе? Конфликты у команд будут. Что там насчет масштабируемости и отказоустойчивости как это потом расширять? И я как фронт не должен знать код бэка и обратно.

Здравствуйте! Если вы только фронтендер, вы можете сделать себе BFF на Point0. Или вы можете использовать его как чисто клиентский фреймворк. Просто замените во всех местах .loader() на .clientLoader(). Ну и в целом это фулстек фреймворк, если вы не фулстек, то вполне может быть, что вам не нужен фулстек фреймворк. А расширяется наоборот удобно, у вас вся логика ваших фич или модулей живёт рядом друг с другом, и вы можете плодить сколько угодно модулей и как угодно их между собой перевязывать.

Я думаю если у вас вообще есть команды бэкендеров и фронтендеров высока вероятность, что у вас бэкендеры вообще не тайпскрипте пишут. В первую очередь этот фреймворк делался для фулстеков, которые пилят фичи от и до самостоятельно, а нам как раз удобно иметь такие конструкции. Мы например любим tRPC, а Point0 это как бы tRPC на стероидах в формате фреймворка

Sign up to leave a comment.

Articles