# Фронтенд

## Що це таке

Фронтенд — це частина програмної системи, яку люди бачать і якою керують: сторінки, екрани, форми й
елементи керування разом із кодом, що їх малює й реагує на введення. Англійською його також пишуть
front end або front-end, а у вебі ту саму територію часто називають клієнтською стороною, client
side.

У вебі фронтенд складається з трьох мов, які розуміє браузер. HTML задає сторінці структуру й зміст,
CSS визначає її вигляд, а JavaScript додає поведінку. Браузер — це те, що документ W3C Architecture
of the World Wide Web називає user agent: програма, яка діє від імені людини, отримує дані із
серверів і показує їх. Усе, що фронтенд надсилає браузеру, опиняється на пристрої, який належить
комусь іншому.

Його партнер — бекенд, який зберігає дані, застосовує бізнес-правила й відповідає на запити. Вони
спілкуються через HTTP, зазвичай за допомогою API. Межу між ними хочеться провести там, де проходить
мережа, але сучасні фреймворки її розмивають. У Next.js сторінки й layouts за замовчуванням є
[Server Components](https://react.dev/reference/rsc/server-components): вони створюють те, що бачить
користувач, і виконуються на сервері. Директива `"use client"` на початку файлу позначає межу, і цей
файл, його імпорти та компоненти, які він рендерить, потрапляють у бандл, що вирушає до браузера.
Фронтендом код робить його завдання, представлення й взаємодія, а місце виконання — окреме рішення.

## Чому це важливо

Перше рішення стосується того, де відбувається робота. Архітектурний документ W3C описує спектр, на
одному кінці якого все робить клієнт, а на іншому все робить сервер, і зазначає, що більшість рішень
поєднує обидва підходи. Місце застосунку на цьому спектрі залежить, за словами документа, від
потужності клієнта, потужності й навантаження сервера та пропускної здатності між ними. Документ
називає компроміс з обох боків: підлаштування вмісту на сервері знижує ефективність кешування, а
коли кількість можливих клієнтів необмежена, краще масштабується перенесення обчислень на них.
Звичні варіанти такі: сторінки, зібрані один раз, сторінки, які сервер рендерить на кожен запит,
сторінки, складені в браузері, і їхні поєднання. Сторінку, однакову для всіх, найдешевше зібрати
один раз і кешувати. Сторінку з даними конкретного користувача десь рендерять на кожен запит, і якщо
це браузер, кожен читач завантажує код, що виконує цю роботу.

Друге рішення стосується довіри, і робоча відповідь така: сервер вважає все, що надходить від
фронтенду, неперевіреним. Усе, що доставляє фронтенд, людина за браузером може прочитати, змінити й
надіслати повторно. Прихована кнопка чи форма, яка відмовляється відправлятися, — це ввічливість
щодо чесного користувача й невеликий обхід для будь-кого іншого, тому кожен дозвіл і кожна
перевірка, які мають значення, повторюються на сервері. Секрети підкоряються тому самому правилу:
API-ключ, що потрапив у бандл, є публічним, хоч би як називалася змінна. Content Security Policy
обмежує, що може зробити впроваджений скрипт, а її специфікація подає її як глибокий захист, який
доповнює ретельну валідацію введення й кодування виводу, а не замінює їх.

Фронтенд — це також місце, де доступність виграють або програють. WCAG 2.2, рекомендація W3C від
грудня 2024 року, встановлює критерії успіху, які можна перевірити, і багато з них залежать від
рішень у фронтенді: чи можна дістатися до елемента керування й скористатися ним із клавіатури та чи
повідомляє він допоміжним технологіям своє ім'я й роль. Нативні елементи HTML виконують кілька з цих
критеріїв одразу, а власний віджет мусить відтворити кожен вручну.

Нарешті, фронтенд, який знає, як база даних зберігає дані, доводиться змінювати щоразу, коли
змінюється база, а фронтенд, що обмежується представленням, дає кожній стороні рухатися у власному
темпі.

## Як це виглядає на практиці

Фронтенд на Next.js 16
[обирає режим рендерингу для кожної частини застосунку](/uk/portfolio/built-the-next-js-16-frontend-with-deliberate-73/).
Маркетингові й публічні сторінки генеруються статично, а інтерактивні частини рендеряться в
браузері. На автентифікованому дашборді й великих сторінках-каталогах, де патерн N+1 перетворював
одну сторінку на каскад мережевих звернень, фабрика `createPrefetchedServerPage` отримує дані
сторінки на сервері й передає їх клієнту вже заповненими, а стратегію інвалідації кешу
задокументовано для кожного запиту. Сторінка, перенесена на фабрику, завантажується за одне
звернення, і наступна перенесена сторінка успадковує цю поведінку. Там же сказано, що перехід
триває: решта автентифікованого застосунку досі рендериться на клієнті й стоїть у черзі.

Багаторівнева морська платформа
[дає своєму фронтенду одне завдання й нічого більше](/uk/portfolio/architected-a-layered-maritime-platform-separating-a-next-57/).
Фронтенд на Next.js відповідає за представлення й інтерактивність. Навмисно тонкий API на Go,
побудований на Huma поверх Fiber, маршрутизує й валідує запити, застосовує фільтрацію безпеки та
оркеструє, а бізнес-логіка живе у функціях PostgreSQL. Коли правило змінюється, воно змінюється в
одному рівні, у SQL, а фронтенд не переймається, коли схема змінюється під ним. Межі зафіксували
письмово й закріпили через код-рев'ю, і саме цьому розділенню сторінка приписує те, що продукт міг і
далі нарощувати функціональність без гниття архітектури.

Робота з посилення захисту застосунку
[виходить із припущення, що клієнт ворожий](/uk/portfolio/hardened-the-application-with-nonce-based-csp-hsts-77/).
Усе, що браузерові дозволено виконати й надіслати, задає один файл, `proxy.ts`: мідлвар Next.js
додає до кожної відповіді Content Security Policy зі свіжим nonce і `strict-dynamic`, заголовок HSTS
та cookie з атрибутом SameSite. Сама межа проходить на сервері. Права доступу, тобто тариф, роль,
організацію й прив'язку до судна, сервер повторно перевіряє на кожен запит, а фронтендні обмеження
розглядаються лише як UX: вони визначають, що бачить людина, а сервер визначає, що їй дозволено
робити.

## Де виникають проблеми

Збої фронтенду зазвичай мають спільну причину: щось вирішили в браузері, хоча це належало серверу,
або навпаки.

**API-ключ з'являється в JavaScript, який може завантажити будь-який відвідувач.** У Next.js змінна
середовища потрапляє в бандл браузера, лише коли її назва починається з `NEXT_PUBLIC_`, а будь-яку
іншу змінну, прочитану з клієнтського коду, замінює порожній рядок. Запит повертається
неавторизованим, хтось швидко перейменовує змінну, щоб усе запрацювало, і секрет опиняється в
публічному файлі. Код, якому потрібен секрет, варто тримати на сервері, а його модуль позначати
пакетом `server-only`, щоб імпорт із Client Component зупиняв збирання. Кожен ключ, який уже
потрапив у реліз, треба замінити.

```ts
import "server-only";
export async function getInvoices(customerId: string) {
    const url = `${process.env.BILLING_URL}/customers/${customerId}/invoices`;
    const headers = { Authorization: `Bearer ${process.env.BILLING_KEY}` };
    const res = await fetch(url, { headers });
    return res.json();
}
```

**Користувач дістається записів, які інтерфейс від нього приховав.** Перевірка дозволів жила у
фронтенді як route guard, прихований пункт меню або вимкнена кнопка. Будь-хто, хто читає мережевий
трафік, може викликати API напряму з іншими параметрами. Кожне право варто перевіряти на сервері на
кожен запит, щодо користувача, який увійшов, і конкретного запису, а перевірки у фронтенді вважати
зручністю для чесних користувачів.

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

**Користувачі клавіатури й екранних читачів застрягають на саморобному елементі керування.**
Клікабельний `div` отримує поведінку кнопки для миші й більше нічого: клавіша Tab його оминає, Enter
і пробіл нічого не роблять, а допоміжні технології не дізнаються, чим він є. WCAG 2.2 на рівні A
вимагає, щоб уся функціональність працювала з клавіатури (критерій успіху 2.1.1) і щоб кожен
компонент повідомляв своє ім'я та роль (4.1.2). Варто використовувати `button`, `a`, `input` і
`label` за їхнім призначенням і пробувати кожен новий екран лише з клавіатурою, перш ніж він вийде в
реліз.

## Що почитати далі

- [Architecture of the World Wide Web, Volume One](https://www.w3.org/TR/webarch/) — рекомендація
  W3C про user agents і про розподіл роботи між клієнтом і сервером.
- [HTML Standard](https://html.spec.whatwg.org/multipage/) — живий стандарт WHATWG для елементів і
  браузерних API, з яких будують вебфронтенд.
- [Web Content Accessibility Guidelines (WCAG) 2.2](https://www.w3.org/TR/WCAG22/) — рекомендація
  W3C із критеріями успіху, на яких тримається доступний інтерфейс.
- [Content Security Policy Level 3](https://www.w3.org/TR/CSP3/) — робоча чернетка W3C, яка визначає
  nonces і `strict-dynamic`.
- [Next.js: Server and Client Components](https://nextjs.org/docs/app/getting-started/server-and-client-components)
  — як один фреймворк розподіляє код фронтенду між сервером і браузером.

<https://engineer.company/uk/glossary/frontend/>
