Галоўная / Артыкулы

Стан URL, стан сервера і BFF: каскад Vite для внутрашніх додатакаў на React

Чаму аутентыфікованая внутршняя платформа на React може краща працаваць з Vite, TanStack Router, TanStack Query і окольным BFF, чым з Next.js, і калі гэта перестае быць правдой.

Выдавец: REACTAPP.TOP10 хв чытання2310 слоў

Крыніцы: Next.js is excellent. That’s exactly why you **shouldn’t** use it everywhere.

Калі пачынаецца новы проект на React, на запитанне «Чы гэта трэба использоваць Next.js?» зазвычай адпавядаюць «так», яшчэ перш чым хто-небудзь описае сам прыемлак. Для публічных сайтаў з великай колькасцю контэнту такая падходзь часта ўсуне. Аднак для платформы для аператывных задач, дзе корыстувальнікі весь час фільтруюць табелі і рэдагуюць данныя пасля абмовкі, багато з найсильнейшых функцыяй гэтага фрэймворку рашаюць проблемы, якіх у самам прыемлаку няма. У гэтым артыкуле расказваецца пра архітэктуру, якая на самай працоўцы трэбуе такой платформе, паказваецца, як компонуемы набор React, Vite, TanStack Router, TanStack Query і backend-for-frontend (BFF) падходзіць да ўсьго гэтага, і заканчваецца чарточкай для выбору, калі Next.js нарэшце будзе лепшым выборам.

Няма нічога, што падкрывае тэзу, чы что Next.js ў слабай форме. Це адны з найлепшых фреймворкаў React, якія існуюць. Аргументы спрыводзяцца проты ўжытку яго за замовчаннем, без пераканальствася, чы яго можлівасці падходзяць да выканання задакоў.

Конкрэтны сценарый

Разглядзім маленькую команду з пяці інжынераў, якія ствараюць внутршняю платформу з болейш чым 100 маршрутаў, болейш чым 300 точаках API і прыблізна мільйонам запытанняў API на месцы. Яны моглі бы стварыць яе з Next.js. Узамест таго яны выбралі React з Vite, TanStack Router для маршрутацыі, TanStack Query для обробкі дадзеных і окалічны BFF межы фронтэндам і бэкэнд-сервісамі. Чырэх месцаў пасля пачатку роботы гэты выбор застаецца актуальным, не таму, што Next.js не падыходзіў, а таму, што платформа ледве задзейнаецца ў тых сферах, дзе Next.js выказвае высокія якосці.

Для болей шырокага паяравання двух падходаў для разных типаў проектаў, адзірніце Next.js або просты React: падбіранне фрэймворку па вашаму проекту. Акцэнт тут болей вузкі: што патрэбна аплікацыі, якая працуе з большай колькасцю дадзэнняў і мае аутентыкацыю, з кожнага слоя.

Апісайце аплікацыю пры выборы фрэймворку

Next.js стаў стандартным рашэнням, таму што ён аб’едначае так много функцыяй: маршрутызацыю і лэйауты на адной заснове файлоў, SSR і Server Components, слой кэшавання, мідлвары, код бэкенду ў аднам проекте, оптымізаваныя зображэння і велікую экасистему. Для багато продуктов такое аб’едначэнне ўсёг яе ідеальна. Аднак болей корыстным першым пытаннем є тое, які тип аплікацыі вы ствараеце. Две аплікацыі на React можуць практычна не мятць нічага спаканнага з точкі зору архітектуры.

Публічны інтерфейс

Тыповая публічная інтернет-магазіна мае:

  • тыячы сторанак, якіе можа адкрыць кожны
  • трафік, які прыходзіць з пошуковых сэрвісаў
  • практычныя трэбаванні SEO
  • сторанкі продуктам, калі контэнт якіх павыгадвае ад обробкі на серверы
  • URL-адрысы, якія можна паводзіць, і аператыўныя прэвью ў соціальных меражах
  • большая частка статычнага або медленна змінююцагася контэнту

Внутршняя платформа для аператыў

Внутршній інструмент зазвычай мае:

  • практычна кожны экран пасля автанацыі
  • пошук кляўэнтав, фільтры і таблы з паградуваннем
  • формы, панелі керавання і перакрычэння прав
  • частыя змены і даны майже у рэальны час
  • вялікі об’ём стану сервера
  • высока інтэрактыўная інтарфейс
  • шар API або BFF, які вялікай меры ўжо існуе

Оба являюцься дапытамі на React, але яны рашаюць разныя проблемы, і архітектура павинна гэта відбіваць.

Корыстувальнікі керуюць дапамогай, а не проста чытаюцы яе

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

SEO больш не ўваходзіць у прыямоўкі

Вазьміце маршрут на кшталт /customers/12345, які паказвае запис абонента, які прыняў автанацію, з чулымі дадзеннямі. Вы яшчэ больш не хачаце, каб пошуковыя системы індексавалі яго. Не ёсць патрэбы, каб краблеры яго знаходзілі, і не патрэбна, каб першы HTML-адказ быў прыемным для краблероў. Старонка ценная таму, што з яёю взаімаецца аўтарызаваны корыстнік, а не таму, што яе можна знайсці. Аднойчы з галоўных прычын выбору Next.js таму мае малая значымасць. Гэта несупаданне трэбаванняў, а не недагоднасць фреймворку.

Дзе падходяць серверныя компаненты, а дзе — ні

Серверныя компаненты ўсё-такі ёсць практычна корыстным модэлем, таму гэта пытанне заслуговае на адказ. Уявіце старонку керавання абонентамі з калькама роздзелаў:

Customer
├── Profile
├── Loans
├── Payments
├── Transactions
├── Documents
└── Activity

Як толькі старонка заваносится, корыстнік пачынае яе меняць. Напрыклад, ён фільтруе спіс платэжаў:

Status: Failed
Type: ACH
Date: Last 30 days

Потым яны переглядаюць сторні, сортаваюць, шукаюць, пачынаюць транзакцыю і рэдагуюць якісь данні. Відображэнне постаўна зменяецца пад вплывам дадзенаў корыстніка і новых дадзенняў сэрвера. Домінантны патэрн — гэта не цыкл у стылі дакумента:

Request → Render document → Read document

Гэта больш супамінае цыкл взаімадзеяў:

User interaction
       ↓
Application state
       ↓
Server state
       ↓
API
       ↓
Updated UI

Чым больш вашы экраны налягаюць на другі дыяграм, тым больш архітектура кліента вялічыць якасць: як зберагаецца стан, як кэшуюцься данні і як UI реагуе на змяны. Компаненты сэрвера все ўсё можу атрыбутаваць часткі такой сторні, але гэта не пазбавляе нас патрэбы ў моцным шаре дадзенняў на боку кліента.

Адносленне да URL як да стану прыемлівання

Падазроўваю, што корыстнік аперацый знаходзіцца на вікні з платамі кліента:

/customer/12345/payments

Яны застаўляюць набор фільтраў:

status=failed
type=ach
amountMin=500
page=2

Якщо гэтыя фільтры закодаваны ў адресе, URL стае такім:

/customer/12345/payments
  ?status=failed
  &type=ach
  &amountMin=500
  &page=2

У такі моменты URL не ўсьмо толькі засоб для навігацыі; ён являе сабою частку стану прыкладнення. Адны інжынер можа пераклацці яго своему колеге, і той потрапляе на таго ж кліента, у тую ж вкладку, з тымі ж фільтрамі і на тую ж сторунку рэзультатаў. Ён таксама застаецца пасля перзавантажэння і змушвае кнопку «Назад» працаваць так, як чакаюць корыстувальнікі. Толькі правильна реалізацыя гэтага на багацько экранаў і є прычыной, чаму рутэр з падтрымкай типаў становіць сабою неабходнасць.

Што дагаўляе TanStack Router

TanStack Router спрэцыявае рутаванне як важлівую частку дизайну. Маршруты, параметры шляха і параметры пошуку можна выразіць у системе типаў, што мае значэнне, калі прыкладнення мае больш чым сто маршрутаў. Пры такой колькасці рутаванне вже не ўсьмо проста «які компонент будзе атрыбутаваны тут»; гэта частка архітектуры. Для маршруту на канцэ парады:

/customer/$customerId/payments

Вы хочаце:

  • чыста апісаныя, типаваныя параметры шляха
  • Параметры пошуку, які перавернуты і маюць прыгадныя типы
  • Выклікі навігацыі, якія пераглядаесяй кампайлером; таму змена назвы параметра спяшчае збірку, а не стварэнне лінка
  • Станы завантажэння і адзінакоў, прызначаныя для кожнага маршруту
  • Захаванні аутэнтыкацыі на рэвэле маршруту
  • Глыбокія лінкі, якія працуюць ўсё час
  • Важна зазначыць, што нічога з гэтага не залежыць ад таго, чы рэндаруецца сторанка на сервере. Для внутранняй аплікацыі, якая цэлкам працуе ў браузеры, гэта ідеальна падходжанне.

    Стан сервера — гэта справжняя важылка

    Большая частка большай внутранняй аплікацыі стосуецца не столькі сторанак, сколькі даўняых дадзеных. Энтыты, якія вона постаўляе і запісвае, выглядаюць так:

    Customers
    Loans
    Payments
    Transactions
    Documents
    Users
    Accounts
    Reports
    

    Для кожнага з іх фронтэнд должен адпаведзець на тыя ж пытанні:

    • Чы гэтыя дадзеныя вже ў памяці?
    • Чы яны сталі застарэлымі?
    • Чы трэба іх зноў запрашаць, і калі?
  • Што паказвае інтэрфейс пад час завантажэння?
  • Што адзначаецца, калі запит не выйшоў?
  • Чы можа іншы компонент выкарыстоўваць гэты рэзультат?
  • Што зміняецца пасля мутацыі, і якія запиты трэба анулюваць?
  • Што павінна апынуцца на экране момантальна, калі корыстнік вяртаецца?
  • Чы можа інтэрфейс апдэйтавацца оптымістычна?
  • Это і є калектываванне стану сервера, і самэ гэта ёсць проблема, для якой створаны TanStack Query: кэш, ключаваны запитамі, фонова перзапрашоўка, адмыванне ідэнтычных запитоў, хукі мутацый і цялевая анулявання. Калі рутэр керуе станам URL, а Query — станом сервера, кожны слой мае чыстаю адпаведальнасць, а стан локальных компонентоў скарачваецца да практычна локальных пытанняў інтэрфейса, такіх як чы відкрыты дыялог.

    Заліквідаванне BFF як межы API

    У такій схеме фронтэнд не запошчае дзесяткі мікросервісаў безпасяродна. Ён вялічыцца з BFF, які у свою чаргу вялічыцца з сервісамі. Такое раздзеленне не дазволяе фронтэнду знаць пра деталі реалізацыі бэкенду, уключаючы тое, чы рэспанс складаецца з адного сервіса чы з пяці. BFF керуе контрактом API.

    Гэта таксама дапамагае стварыць чыстую структуру размешчэння. Фронтэнд — це статычныя ресурсы, якія выдаюцца з CDN чы статычнага хоста:

    Frontend
       ↓
    CDN / static hosting
    

    тады калі BFF працюе як самастоятельны сервіс перад мікросервісамі:

    BFF
       ↓
    Microservices
    

    Кожную частыню можна ствараць і запускать незалежна. Next.js абсалютна можа быть размешчаная празаўсёды разам з BFF. Справжній пытанне — чы роўнасабліва ваша фронтэнд-фрамворк таксама павінна выступаць як серверны межа. Калі ў організацыі вялікі час уже існуе бэкенд-шар, який забезпечвае гэтую межу, дадаць другі шар унутры фронтэнд-фрамворка прыводзіць да дуплікацыі адпаведнасцяў.

    Аутэнтыкацыя застаецца на серверной стороне

    Процес аутэнтыкацыі таксама паследуе гэтае раздзеленне. Пользователь нажымае «Увайсі» і пераправляецца на Okta. Пасля успешнага заходжання адбываецца калебак, які падае на бэкенд, який зберагае токен доступу на серверной стороне, а Redis адпаведна керуе збераганнем сесій. Браузер проста зберагае ідэнтыфікатор сесіі ў захіщанай куку. Канцэптуальна:

    Browser
       │
       │ Sign in
       ▼
     Okta
       │
       │ Callback
       ▼
     BFF / Backend
       │
       ▼
     Redis
    

    Рэакт-дзялоў не ёсць там, дзе знаходзіцца архітектура аутантыкацыі; яго задача — кераваць продуктам, тады как BFF абавяраеся безпекай і контрактам API. Корыстны пасляэфект — токены доступу ніколі не прабрацоўваюцца ў JavaScript браузера, што зменшае вплыв баго XSS. Выкананне гэтага ўнутрь Next.js не ёсць прыродна горшым, але калі такая архітектура вялікі час вучыцца ў організацыі, яе заставленне праза фронтэндам ёсць простым і ясным.

    Так, Next.js можа зрабіць усё гэта

    Ён можа. Вы можете стварыць дзялоў з Next.js, выкарыстоўваючы кліентскія компаненты, ў яму можна выкарыстоўваць TanStack Query, налаштавіць аутантыкацыю, пад’ясніць яе да BFF і разместіць як хочаце. Магчымасці не ёсць проблемай. Кращы вопыт — гэта, насколькі з фреймворку вы на самай працоўваце. Якщо большая частка дзялова будзе выглядаць так:

    'use client'
            ↓
    Client-side interactions
            ↓
    API calls
            ↓
    TanStack Query
    

    Тады варта на момент зупініцца і запытацца, чы рэштаеўнікі сяроджонка сервера прабачаюць выбіранне Next.js як межы вашай аплікацыі, з усімі яе стандартамі, часам выконання і можлівасцямі апдэйта.

    Кожны элемент складовай структуры мае свою задачу

    Для такіх аплікацый разумны стандартны набор – React, Vite, TanStack Router і TanStack Query, а таксама BFF. Оось не значыць проста склеюванне бібліятакаў пакуль вы випадкова не створыце сабе сопны фрэймворк. Кожны элемент мае чыста визначаную ролю:

    • Vite забезпечвае інструменты для кампіляцыі та сервер развіцця.
    • React атрыбуе інтерфейс.
    • TanStack Router керуе маршрутацыяй і станам URL.
    • TanStack Query керуе станом на серверы.
    • BFF являе сабою межу API та безпекі.

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

    Недзеянкі з таго, калі не выкарыстоўваць Next.js

    Композабельныя маршруты маюць своія наследкі. Вы тырчыце можлівасць выкарыстоўваць готавыя рашэння і самі прымайце рашэнні, якія зазвычай выкарыстоўвае Next.js: структуру проекта, правілы роздзелення коду, спосаб, яким статычны хост обрабоцвае маршруты з боку кліента, а таксама неабходнасць супяроўнавання колькіх бібліятэкаў адразу. Таксама можу змяніцца і спектар трэбаванняў. Якщо пазней палова дапрацоўкі будзе трэбавацца зробіць публічной, а SEO стане важлівым, Next.js стае значна прываблівей. Тое ж сама паслужыць прычыной, якщо вам трэбае сутэйна обробка на серверы або стварэнне статычных версіяў, якщо серверныя компаненты дадаюць рэальную ценнасць вашаму дизайну, або якщо вы насправды хочаце, каб код фронтэнда і сервера быў намерна з’едынены ў адной дапрацоўцы. Таму рашэнне не ў тым, "Next.js чы React", а ў тым, якая архітектура падходзіць для данай дапрацоўкі.

    Спіс пунктав для выбору

    Перад тым, як прыняць рашэнне, разглядзіце наступныя пытанні:

    • Чы гэны ўжоць мае значны адкрытыя інтэфейсы? Гэта сильная сторона Next.js.
    • Чы важна SEO? Next.js становіцца ўсё прываблівей.
    • Чы вам патрэбна обработка на сервере чы статычная генерацыя? У гэтым таксама виграе Next.js.
    • Чы Server Components чы Server Actions можа сутэйна паспрыяць пакращэнню дизайна? Тады трэба серьёзна рассмотріць Next.js.
    • Чы ўжоць пераважна аутентифікуецца і є высока інтэрактыўнасць? Кращэ выбраць React з Vite.
    • Чы організацыя вже выкарыстоўвае шар BFF чы API? Вартуе рассмотрзець самастоятельны кліентскі ўжоць, які размешчаецца окрема.
    • Чы стан сервера ёсьць главным проблемам? TanStack Query становіцца дужа прываблівым выборам.
    • Чы стан URL і складная маршрутазацыя є ключовымі аспектамі? TanStack Router таксама становіцца дужа прываблівым выборам.

    З гэтых адказоў выліваецца простая правіла-памятка. Калі аплікацыя мае значны публічны інтерфейс, трэба серйозна рассмотрыць варыянт Next.js. Калі ж аплікацыя пераважна аутентифікуеся, боўш чым усё — цэна ўнутранняя або адміністратыўная платформа, трэба запускаться з React і Vite, дадаючы толькі тыя элементы, якія неабходны. Ні адна з гэтых стакоў не є кращай у загальным сенсе; адна з іх болей падходзіць для конкрэтнай задачы, а гэтае разлічэнне лёгка забываецца, калі фреймворк становіцца стандартным рашэнням.

    Заключанне

    Найлепшая архітектура — гэта не тая, якая мае самы дзьвінкі список функцый, а тая, чыя функцыйны рашаюць проблемы, якія у вас насправдзе ёсць. Для інструмента для аператыў, які працюе праз входзенне і мае сэрвысны шар, значны стан сервера, інтэнсыўныя взаімадзеі і мінімум публічнага кантэнту, React з Vite, TanStack Router і TanStack Query — гэта не компроміс; гэта свядомы выбор.

    • Спачатку класіфікуюце прыемлень: сайт з адміністрацыйным кантэнтам чы робітка, якая выконвае аутентыкацыю.
    • URL і данні сервера лячуце двума галоўными істочнікамі стану, і для кожнага з іх трэба выдзеліць спецыяльны інструмент.
    • Зберагачуце межы безпекі і API там, дзе ў вашай організацыі яны вялікі.
    • Перазглянуце гэта рашэнне, якщо публічныя старонкі, SEO чы рэндэраванне на сервере стануць рэальнымі трэбованнямі.