Галоўная / Артыкулы / Браузер, сервер чы роцэ стварэння: карта выбору для архітектур фронтэнду

Браузер, сервер чы роцэ стварэння: карта выбору для архітектур фронтэнду

Паглядзіце, як SSG, SSR, стрімінг, серверныя компаненты, BFF-ы, рэндарынг на краю, модульныя моналіты і мікро-фронтэнды кожны адпаведзя на аднае пытанне: дзе трэба выконваць работу?

2588 слоў

У дыялогах па тэму архітектуры, і ў спецыяльна ў адборах для ролі вышэйшага фронтэнд-разработчыка, рэдка калі значыць тое, што вы створылі. Їх цікавіць тое, чаму вы створылі гэта самакаў спосабом, і фраза «гэта тое, што ўжо было у команды» не ёсць адпаведзеннем. Хорашая новіна ў тым, што практычна кожны шаблон архітектуры фронтэнда адпавядае на тое ж самае основнае пытанне: сколькі роботы трэба выконваць у браузере, сколькі на серверы, і сколькі пад час стварэння? Калі вы пабачыце SSR, Server Components, backends-for-frontends і micro-frontends як разныя способы практычнага выдзелення гэтай межы, выбір між імі та абаранэнне гэтага выбору стане значна простым.

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

Як зместылася межа між кліентам і серверам

Спачатку веб быў просты. Статычныя файлы HTML завантажваліся практычна мгновенна і майже не мелі таго, што могла бы зламацца.

Пасля чаго фрэймворкі MVC з баку сервера, такія як Django, Rails і ASP.NET, пачалі генераваць HTML за кожны запит. Тепер сторанкі моглі паказваць дынамічныя даны, але кожны клік значыў павна перзагрузку сторанкі.

Аплікацыі з адной сторанкай, створаныя за дапамою React, Vue чыра Angular, сильна змінілі ситуацыю на працоўны бак. Браузер перадаў на сябе адпаведальнасць за маршрутызацыю, стан дадзеных, пераканальванне, а іноды нават аутэнтыфікацыю. Рэзультатам быў інтерфейс, які здаецца мгновенным, але толькі пасля таго, як ён завантажыўся. Гэтае айсамліве ёст кантракцыя: вялікія пакеты JavaScript, спадзяльны час першага атрымання зместу на экран і горшая можлівасць яго аднаходжэння. Google дзе-ткі выкананае JavaScript, але рэндарынг на вялікіх сайтах можа запаздзіць індексаванне, а багатыя іншые краулеры, укладаючы боты для прадзіроўкаў у соцыяльных меражах і багатыя AI-краулеры, вообща не выкананяюць скрыпты. Контэнт, які ўжо не можна эфектыва побачыць, для яных проста не існуе.

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

Backend-for-Frontend: перакаштовванне адной API на кожнага кліента

У конфігурацыі Backend-for-Frontend (BFF) команда фронтэнду запускае савой танкі служба прымоўна да рэальных служб бэкэнду. Гэтая служба выканае адну задачу: перакладае даны бэкэнду у тое, што абавесці ўсё, што патрэбна аднаму кліенту.

Гэты патэрн зазвычай выводзіцца з SoundCloud. Адносна у 2013 году, калі компанія ператварала моноліт на мікросервісы, яна з’явілася, што кліенты для веба, iOS і Android змагаліся за адну спяльную API, яка не падходзіла нікому з іх. Кожны кліент отрымаў свой сабэйнд, прызначаны яму спецыяльна і лёгкі. Філ Кальсадо, яны працаваў над гэтым перайзом, пазней дакладна описаў яго історыю, а статыя Сэма Ньюмана ператворыла яе на шырока цітаваны опис патэрна, які і даў яму гэта назва. Netflix самастаятельна дасягла падобнага рашэння за дапамогою шароў-адаптараў, прызначаных для конкрэтных прыстроёў, адтолькі що дапыткі для тэлевізора і телефона трэбуюць абсалютна разных пакетаў дадзеных.

Разглянем конкрэтны прыклад. Мобільныя дапрынкі патрабуюць назву продукту, цэну і мініатюру. Веб-дапрынкі дадаўна патрабуюць таксама адзінакі, уровень залягоўкі і супаўзялёвыя тавары. Адны спаканены канец падае мобільным дапрынкам занадта много інфармацыі, а веб-дапрынкам — занадта мало, і команды вынушеныя дагаўляць параметры запитоў, каб гэта компенсаваць.

BFF рашае гэтыя проблемы, даўаючы кожнаму дапрынку адпаведную, спецыяльна падобраную адпаведь. Наведзены нижэй сервіс Express, які выкарыстоўвае fetch з Node 18 і новейшых версіях, вызывае API продукту і вяртае толькі чатыры поля, перайменаваючы title у name і зменшаючы спіс аўтаракурсаваў да адной мініатюры:

// bff.js — Node 18+, fetch is built in
import express from 'express';

const app = express();
const API = 'https://api.example.com';

app.get('/products/:id', async (req, res) => {
  const response = await fetch(`${API}/products/${req.params.id}`);
  const data = await response.json();

  res.json({
    id: data.id,
    name: data.title,
    price: data.price,
    thumbnail: data.images[0],
  });
});

app.listen(4000, () => console.log('BFF listening on :4000'));

Кліент запрашвае /products/123 і атрымляе самэй той формат, які ён хочаць, без зайвых полей і без дадзення дапамогі ў кожны раз. У прымэтнай версіі коду таксама трэба пераканаліцца, чы роўнаважна response.ok пры парсаванні, і захацьца ад продуктов, у якіх няма з’еўрабацоў, калі data.images[0] прыпускае наявнасць хаця б аднаго.

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

Стратэгіі адраджвання: дзе ствараецца HTML

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

Статычна генерація і поступовая регенерацыя

Статычная генерація сайта (SSG) адраджвае кожную сторонку пад час стварэння і выдае простыя файлы з CDN. Нет нічога шырэй чым гэта за скорасцю чыстаўкі, але контэнт застаецца незменным да наступной разгрузкі.

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

Адраджванне на боку сервера і стрімінг

Server-Side Rendering (SSR) стварае HTML для кожнага запиту. У сваёй класычной форме сервер адправляе цэлую сторанку, а пасля прыгарнік яе заповняе: ён завантажвае пакет JavaScript і прыўязывае обрабоўчыкі змян і стану да маркапа, який вэсьць на экране.

У React 18 быў адкрыты SSR з стрімаваннем через renderToPipeableStream; гэты метод адправляе часткі HTML як толькі кожная часть структуры готавая, замест таго каб чакаць на найпамедлівейшы компонент. Стрімаванне ёсць стандартны выбар для новых прыкладоў практычнага выкарыстоўвання, хоча багатыя прыкладнікі ў рэальных умовах яшчэ і далей працуюць за дапамогою класычнага SSR, які выкааноўваецца за адну хвіліну, без проблем.

Server Components, адзеленыя часткі і можлівасць паўторнага запуску

React Server Components (RSC) і архітектура островаў даходзяць яшчэ далей: толькі інтерактывныя часты наводкі перадаюць JavaScript. Статычны кантэнт застаецца звычным HTML без някакой неабяжнасці. Astro-ўскія островы прыменяюць гэю ідею паza межамі React. Qwik заходзіць яшчэ далей завдяк можлівасці паўторнага запуску, якая значна запобегае неабяжнасці, серыязуючы стан прыкладнення ў HTML, так што кліент можа продакцэюваць там, дзе зупыніўся сервер.

У прыкладе нижэй паказана стороніца Server Component у Next.js App Router. Пачынаючы з Next.js 15, params ўжо не являецца простаю значэнням, а ўсё больш Promise, які неабходна вычакаць; самэўтаму компонент распакоўвае id толькі пасля выкарыстоўвання await params. Запыт на отрыманне дадзэнняў выконваецца на серверы, таму назва тавара і цена прыходзяць у вачынку як готавы HTML:

// app/products/[id]/page.tsx (Next.js 15+)
import { fetchProduct } from '@/lib/api';

export default async function ProductPage({
  params,
}: {
  params: Promise<{ id: string }>;
}) {
  const { id } = await params;
  const product = await fetchProduct(id); // runs on the server

  return (
    <main>
      <h1>{product.name}</h1>
      <p>${product.price}</p>
      <AddToCartButton productId={product.id} />
    </main>
  );
}

Толькі AddToCartButton мае JavaScript на стороне кліента. Ён можа выкананы толькі якшо знаходзіцца у сваёй сабе файле, пазначанам дырэктываю 'use client', і яго неабходна імпортуваць у стороніцу; для скрацання кусак коду не показана гэтае імпортаванне. Рэзультатам являецца невялікі пакет, який є інтэрактывным там, дзе цяперашняе інтэрактыўнасць неабходная, а ў всіх іншых месцах — статычным.

Рэндарынг на серверы і прычыны, чаму абласць развіцця часткова зменіла падход

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

У перыяд з 2021 по 2023 год аргументы за такі падход былі пераканальныя: трэба было выконваць SSR на краю, на такіх платформах, як Cloudflare Workers чыста Vercel Edge Functions, у цэнтры обробкі дадзеных, які знаходзіцца паўстаноўка кожнага корыстувальніка. Меньшая вялічына расстояння — быстрэйшыя сторанкі. Vercel актыўна праспамівала гэты падход.

Vercel пазней адкрыта змяніў свою позыцыю; тадышній віце-прэзідент прадукту пахарактарызаваў гэта як "гэты прыем змусіў меня падумаць". Прычына ў цэм є значным паучаннем. Обробка данных должна знаходзіцца падалёку ад корыстніка, але таксама падалёку ад данных, а большасць баз дадзеных знаходзіцца ў аднай регіяў. Функцыя на краю сеті ў Токіё, якая выконвае калькі разоў перавозку дадзеных да базы дадзеных у Вірджиніі, часта працюе медленней, чым простая обробка дадзеных у Вірджиніі. Калі Vercel пераканаўся гэтым на своем продукце v0, з’явілася, што простая обробка дадзеных за дапамою Node.js працюе краща, чым обробка на краю сеті. Vercel пазней адмовіўся ад самастоятных функцый на краю сеті і тепер рэкамендуе варыянт Node.js, калі обробка дадзеных выканаўця знаходзіцца ў той жа регія, што і данные; для точнага ведама ўстатку кожнага выканаўця трэба адзірнуць дакументацыю платформы.

Што засталося — это болей шчырокая ідея: нега адразу выдаць статычную структуру сторанкі з краю, а потым працяваць з дынамічнымі часткамі, якія обробляюцца на серверах, распакаваных падалеў ад дадзэнняў. Гэта, у загальных рысах, тое, што робіць Partial Prerendering; тлумачэнне парадоксу частковага прадзеявлення і адночаснага дзеявлення раскрывае механізмы гэтага падходу.

Cloudflare Workers застаецца справжней платформай SSR на краю і добра функцыонуе, калі самыя дадзеныя распакаваны по всім свету. Важлівым урокам є тое, што локація дадзэнняў зазвычай мае перавагу над локаціяю корыстніка. Розумеў, чаму індастрыя зменіла сваю думку, цэннае больш, чым проста знаць популярны тэрмін.

Модульны фронтэнд-моналіт

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

Модульны моналіт раздзеляе базу кода на два шары, заставаючы адны з іх гатовым да развяртання:

  • Шар платформы, якім керуе команда платформы, і ў яком знаходзяцца система дизайну, спадзеленыя элементы, логаванне і падобная інфраструктура.
  • Шар домэны, які складаецца з папак з функцыямі, такіх як user/ або payments/, кожная з якіх належыць сваёй команде.

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

Мікро-фронтэнды: незалежнасць за плату

Архітектура мікро-фронтэнда расследзяе кожную домэну як окремую, можна розмістыць міні-застаўку, якая зазвычай завантажваецца пад час выконання фронтэнд-застаўкай за дапамогою такога механізма, як Webpack Module Federation.

Вы атрыбуеце сабэйную автанамію: команды выклікаюць свае продукты за савой графік і, як толькі це практычна неабходна, можаць нават викорыстоўваць разныя фрэймворкі. Zalando, IKEA і DAZN усе яны описалі пра рэалізацыю такога падходу у масштабе, завжды з великімі інжынерскімі арганізаціямі і значнымі інвестыціямі у спольную інструменталку. micro-frontends.org застаецца стандартным джерэлам для абшытага аналізу.

Форма неудачы, якая насправдзе заводзіць да проблем

Проблема, яка практычна ў звітах пра рэальныя інцыденты, — гэта не сумешчанне фреймворкаў. Це спяльная дрыфт завыскаў. Адна удалённая аплікацыя апдэйтавае спяльную бібліятэку, а іншая — няма, і раптам на одной жа сторунцы запускаюцца два экземпляры React, якія конкуруюць за той самы DOM. Module Federation можа адзначыць спяльныя сінглтоны і дыапазоны версый, каб запобiec гэтаму, але толькі якщо команды пагадаюцца пра гэтыя абмежэння і ўжываюць іх. Саме гэтая проблема коордынаціі разрушае команды, набагато больш, чым зазвычай адзначаемая „складнасць“.

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

Дазвольце размаху каманды кераваць рашэнням

Пытанне, якое рэдкая з’яўляецца на дыяграмах архітэктуры, — гэта колькі насправды ў вас інжынероў. Наведзеныя нижэй дыапазоны є гіюрістыкамі, выведзенымі з таго, як каманды пасля цього описваюць свае рашэння, а не строгімі правіламі:

  • Меней чым апошнія 15 інжынероў: модульны моноліт практычна завжды є выгодным варыянтом. Не хапае людзей, каб праграмаваць аднальныя процесы развёртвання.
  • Апошней 15 да 50 інжынераў з калькама чыстых меж домэнаў: BFF-ы ў поўнай меры дапамагаюць разам з адлеглая організаваным модульным моналітам. Мікро-фронтэнды, верагодна, яшчэ працягваюць застаўацца неранейшымі.
  • Больш чым апошней 50 інжынераў, калі каманды практычна перакрываюць адзін другаму выпуск продукту: мікро-фронтэнды пачынаюць даваць рэзультаты, не таму што програма вырасла, а таму што сама організацыя вырасла.
  • Пераконліва адпаведзь на пытанні пра выбор архітэктуры

    На высокія пасунакі чакаецца рашэнне, а не каталог вароў. Сильная адпаведзь зазвычай складаецца з чатырох частак:

    1. Што вы запускаеце. Напрыклад: стораніцы маркетынгу генеруюцца статычна, панелі керавання викорыстоўваюць SSR, а BFF знаходзіцца перед мобільным дапынкам.
  • Чаму. Статычна генераванне дае вельмі шырокую скорасць адразу пасля атрыбутавання кантэнту, які рэдкая змienяецца; SSR дазваляе прадстаўляць персаналізаваныя даны, такія як імя пользователя, без показу некоректнага кантэнту.
  • Косц, які вы выбралі заплаціць. BFF дагаўляе дапаможны ўзлёт, але дае команды фронтэнду контроль над ўгодамі даных, што практычна правергае яго неабходнасць.
  • Што вы адхілілі і чаму. Былі ацэнены мікро-фронтэнды, але накладныя витраты на коордынацію не практычна праверглі яе неабходнасць у ныяму розмерзе каманды.
  • Пяршы пункт мае найбольшую значнасць. Адказ на пытанне, што вы намеравана не выбралі, — гэта тое, што адразняе простае пераказванне інфармацыі ад практычнага рашэння. Перакрыцце процесу рэндарывання на краю є готовай ілюстрацыяй: нават платформа, якая падтрымвала такі падход, зменіла сваю палітку, калі паказаныя даны не саступіліся.

    Частыя запытанні

    Як разлічаюцца SSR і SSG?

    Пакалькі ў кожнай запытцы SSR адрасавае тэкст, ён можа мяць актуальныя або персональныя для кожнага корыстувальніка даны. SSG стварае HTML аднойчы пад час практыкавання і выдае статычныя файлы, што ўскорае і здешавляе процес, але толькі настолькі, насколькі ўсё ще актуальныя пасля последней деплікацыі. ISR знаходзіцца межу ўсімі трохма, перыядична генеруючы адзінаковыя сторанцы.

    Чы рэальна наявнасць BFF калі є толькі адны фронтэнд?

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

    Чы мертва тэхнологія edge rendering?

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

    Калі команде трэба перейсці на мікро-фронтенды?

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

    Ключовыя выводы

    • Кожны з паказаных падходаў — это адпаведнасць на аднай запытанні: які частака роботы належыць браузеру, серверу і кроку стварэння.
  • Правыя падчынныя завісяць ад размеру команды, месца зберагчы даных і ступеня складнасці запуску, значна больш, чым ад таго, який шаблон здаецца найболей вражаючым.
  • BFF-ы, мікро-фронтэнды і обробка на краю сутнаць у тым, што воні жертвуюць эксплуатацыйными виткамі за певную перадачу; чыткая адзначэння гэтай жертвы.
  • Храніце паводзкі прычын адхоўлення дзеяных варыянтов. Гэта ўбеджаючыя доказы таго, што выбор быў намеровым.