Pull to refresh
1
Send message

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

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

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

ИМХО, отсутствие потокового 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-решений.

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

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) на каждом уровне.

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


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

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

Спайк — это проработка задачи до состояния понятного техзадания.
Prompt-first — следующий этап: после спайка сначала согласуем промпты для нейросети, чтобы ограничить её фантазию и не переписывать потом тонны сгенерированного кода.

Этим занимаются технари, то есть мы не прячем под ковёр использование ИИ, а выносим его в прозрачный инженерный процесс: ревьюим не только код, но и входные инструкции, от которых зависит результат.

Как раз об этом и речь в статье. Типичный пример — нейросеть вместо использования agreed stack начинает писать свои велосипеды: slugify, debounce, date utils, form manager, query cache и т.д. Аналитик или продукт это не отловят, потому что это инженерный слой. А в потоке кода от ИИ такие вещи легко тонут. Поэтому стандарты лучше задавать заранее: разрешённый пул библиотек, архитектурные ограничения, минимальный diff. Тогда ревью проверяет решение задачи, а не ищет случайно появившийся новый велосипед.

Как я понял, вы хотите реализовать SSR с парсингом JSON на сервере, а затем гидрировать это на клиенте? Если так, то такой подход довольно распространён.

Однако возникает вопрос: как в таком случае вы планируете обрабатывать динамические элементы интерфейса — такие как порталы, модалки и прочие компоненты, которые могут быть добавлены или удалены из DOM по мере взаимодействия?

Я встречал похожую реализацию, например, с BDUI на базе Next.js — так что почему бы и нет. Хотя стоит отметить, что тема SSR на Node достаточно холиварная и дискуссионная. Кому-то такой подход в принципе не подходит.

В случае с PWA мы, например, не стремимся выносить логику на сервер — зачем, если основная идея в том, что пользователь «устанавливает» приложение как аналог мобильного, а всё кешируется на уровне service worker’ов?

Как писал классик:
Если звёзды зажигаются — значит, это кому-нибудь нужно.

Вы не учли важный момент: инструменты всегда выбираются из контекста задачи.

Когда мы говорим о достаточно большом объёме JavaScript-кода, за такими решениями, как правило, стоят нетривиальные проблемы.

Давайте порассуждаем. Представим трейдинговую платформу с:

  • реалтайм-обновлениями через WebSocket,

  • REST API,

  • банковскими формами,

  • фича-флагами

  • и прочий «радостью».

Как вы собираетесь грузить такую систему с минимальным количеством кода?
И даже если каким-то чудом у вас получится — как вы будете масштабировать это решение на десяток продуктовых команд?

А теперь добавим унифицированную платформу, где вместе с вебом живёт и мобильная разработка. И разработчиков там ещё больше, потому что нужно поддерживать две кардинально разные платформы.

И тут появляется основной барьер для быстрой доставки кода — релизы.

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

Как я понял, вы ориентируетесь на замеры в локальной среде без сетевых ограничений. 15 секунд закладывается на загрузки с учётом условий мобильной сети у реальных пользователей. В таких условиях получить 1 секунду — невозможно. Указанные 30% — это показатели, снятые с мобильных устройств.

Обсуждать скорость загрузки в контексте статьи — всё равно что обсуждать сферического коня в вакууме. Всё, конечно, упирается в размер JSON и итогового JS-бандла: чем больше логики и кода, тем дольше загрузка.

Тем не менее, никого ни к чему не призываю и не пытаюсь переубедить. Было бы интересно узнать про ваш опыт с BDUI, если есть: какие цифры получались у вас и что для этого делали.

На демо-стенде показало 30% прирост к скорости. Точных цифры могут варьироваться в зависимости от реальных условий и объёма данных на живом проекте. Плюс по перфоманс профайлу есть видимость, что сборщик мусора срабатывает реже, что тоже ускоряет загрузку.

Сори, тег не туда ушёл, не уследил. Вторая статья на хабре, я только учусь)

В статье рассматривается концепция BDUI. Безусловно, подход спорный, но на практике многие компании в той или иной форме применяют его, что позволяет им существенно бустить производительность разработки.

Понятно, что если у вас чистая PWA без нативного мобильного приложения, то BDUI, скорее всего, вам не нужен. Однако в мультиплатформенной среде он может дать ощутимую выгоду.

Теперь по поводу вашего комментария. Могли бы вы подробнее рассказать, каким образом вы планируете реализовать описанную вами логику в рамках BDUI? Допустим, у вас есть JSON, описывающий интерфейс. Как именно вы собираетесь разделить этот JSON на каркас (skeleton/layout) и остальную структуру?

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

Потому что с yup/zod и прочими гораздо удобнее работать. Начиная вопроса расширения валидаторов, написания кастомных правил валилации и заканчивая поддержкой typescript-a из коробки.

Само решение подразумевает, что у вас есть кастомные валидаторы и кастомные правила валидации. Иначе в нём нет никакого смысла берёте Orval и там всё из коробки работает. На счёт того, как вы будете домен описывать, тут уже всё индивидуально. Нам хватает связки formik плюс yup, возможно вам нужно, что-то более многослойное. Вообщем без знания конкретных вводных очень тяжело что-то посоветовать.

Конкретно мы у себя используем 3.0.1 версию. Но вообще кажется, что статья подходит для любой третий версии OpenAPI.

Information

Rating
6,644-th
Registered
Activity