Побудова React-фреймворку

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

Note

Зважте використання наявного фреймворку

Побудова фреймворку є комплексною і вимагає неабиякого досвіду в різних сферах. Ця складність не тільки в React — це поширена проблема, з якою стикаються всі UI-бібліотеки. Використання наявного фреймворку може значно заощадити час і зусилля, даючи змогу зосередитися саме на побудові застосунку. Наявні фреймворки мають перевірені й надійні функції та підтримку спільноти.

Щоб отримати список рекомендованих фреймворків, перегляньте розділ “Створення React-застосунку”.

Побудова фреймворку — це чимале зобов’язання, яке часто потребує досвіду в багатьох різних сферах. Розуміння ваших цілей і вимог перед початком створення власного фреймворку може допомогти вам скерувати процес розробки та заощадити велику кількість часу.

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

Якщо ви створюєте власний фреймворк для навчання, то використання популярних інструментів, як-от Vite і React Router, стане гарним початком і дасть вам змогу зосередитися на тому, як комбінувати різні інструменти для побудови фреймворку.

Крок 1: Установіть інструмент збирання

Першим кроком є ​​встановлення інструменту збирання, наприклад, vite, parcel або rsbuild. Вони надають функції для пакування та виконання вихідного коду, сервер для локальної розробки та команду збирання, щоб розгорнути застосунок на робочому сервері.

Vite

Vite — це інструмент збирання, який має на меті забезпечити швидшу та ефективнішу розробку сучасних вебпроєктів.

Terminal
npm create vite@latest my-app — —template react

Vite є досить розсудливим і постачається відразу з виваженими початковими налаштуваннями. Він має багату екосистему плагінів для підтримування швидкого оновлення, JSX, Babel/SWC та інших поширених функцій. Найперше перегляньте плагін React або плагін React SWC і приклад проєкту з React SSR.

Vite вже використовується як інструмент збирання в одному з наших рекомендованих фреймворківReact Router.

Parcel

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

Terminal
npm install —save-dev parcel

Parcel відразу підтримує швидке оновлення, JSX, TypeScript, Flow і стилізацію. Найперше перегляньте рецепт React від Parcel.

Rsbuild

Rsbuild — це інструмент збирання на основі Rspack, який забезпечує безшовну розробку React-застосунків. Він постачається з ретельно налаштованими початковими параметрами й оптимізаціями продуктивності, готовими до використання.

Terminal
npx create-rsbuild —template react

Rsbuild відразу підтримує такі функції React, як швидке оновлення, JSX, TypeScript і стилізація. Найперше перегляньте посібник React від Rsbuild.

Note

Metro для React Native

Якщо ви хочете, щоб ваш фреймворк підтримував React Native, вам потрібно буде використовувати Metro — бандлер JavaScript для React Native. Metro створює бандли для iOS та Android, але йому бракує багатьох функцій, як порівняти з Vite або Parcel. Ми рекомендуємо почати з Vite або Parcel, якщо ваш проєкт не вимагає підтримування React Native.

Крок 2: Збудуйте власний фреймворк

Інструмент збирання, який ви вибрали, починається з клієнтського односторінкового застосунку (SPA). Хоч SPA можуть бути гарними для початку, багато з них зіткнуться з проблемами, коли розростуться. Фреймворки можуть надати риштування для вирішення цих проблем. Більшість із них реалізують маршрутизацію (routing), розділення коду (code-splitting), різні стратегії рендерингу та отримання даних (data-fetching). Ці функції взаємопов’язані. Наприклад, якщо ви використовуєте маршрутизатор, який працює лише на клієнті, це може перешкоджати реалізації рендерингу з боку сервера. Найкращі фреймворки забезпечують узгоджену, послідовну роботу з цими функціями для розробників і користувачів.

Маршрутизація

Маршрутизація визначає, що відображати, коли користувач відвідує певну URL-адресу. Вам треба налаштувати маршрутизатор, щоб зіставляти URL-адреси з різними частинами застосунку. Вам також потрібно буде обробляти вкладені маршрути, параметри маршруту та параметри запиту (query parameters). Більшість сучасних маршрутизаторів використовує маршрутизацію на основі файлів. Маршрутизація може бути інтегрована з іншими функціями, як-от:

Якщо ви не впевнені, як працювати з маршрутизацією, рекомендуємо використати React Router або Tanstack Router.

Отримання даних

Отримання даних — це процес отримання даних із сервера або іншого джерела даних. Вам треба налаштувати або створити відповідну бібліотеку, щоб обробляти отримання даних із вашого сервера та управляти станом цих даних. Вам також потрібно опрацьовувати стани завантаження, стани помилок і кешування даних. Отримання даних може бути інтегроване з іншими функціями, як-от:

  • Маршрутизація, щоб увімкнути отримання даних перед завантаженням сторінки. Це може покращити швидкість завантаження сторінки та її видимість для користувачів (малювання найбільшого вмісту, LCP) і зменшити час, потрібний вашому застосунку, щоб стати інтерактивним (час до інтерактивності, TTI).
  • Стратегії рендерингу, щоб попередньо рендерити запитувані дані перед тим, як надіслати їх клієнту. Це може зменшити час до рендерингу найбільшого видимого вмісту застосунку (малювання найбільшого вмісту, LCP).

Інтеграція маршрутизації та отримання даних насамперед важлива для запобігання мережевого “водоспаду”. Якщо ви запитуєте дані під час початкового рендеру компонента, то перше отримання даних у SPA відкладається, доки не буде завантажено весь код і компоненти не завершать рендеринг. Це зазвичай називають водоспадом: замість того, щоб отримувати дані під час завантаження коду, вам потрібно спочатку зачекати, поки він завантажиться. І щоб усунути ці каскади, ваш застосунок повинен отримувати дані для кожного маршруту паралельно з надсиланням коду в браузер.

Популярні бібліотеки отримання даних, які ви можете використовувати як частину свого фреймворку: React Query, SWR, Apollo і Relay.

Стратегії рендерингу

Оскільки вибраний вами інструмент збирання підтримує лише односторінкові застосунки (SPA), вам треба самостійно реалізувати інші патерни рендерингу, як-от рендеринг із боку сервера (SSR), генерація статичного сайту (SSG) та/або серверні компоненти React (RSC). Хоч спочатку вони рідко потрібні, згодом SSR, SSG або RSC можуть оптимізувати деякі маршрути вашого застосунку.

  • Односторінкові застосунки (SPA) завантажують одну HTML-сторінку та динамічно оновлюють її, коли користувач взаємодіє із застосунком. SPA є швидкими та чуйними, але часто повільніші під час початкового завантаження. SPA є стандартною архітектурою для більшості інструментів збирання.

  • Потоковий рендеринг з боку сервера (SSR) рендерить сторінку на сервері та надсилає повністю відрендерену сторінку клієнту. SSR може покращити продуктивність, але його налаштування та обслуговування радше складніші, ніж для односторінкового застосунку. З додаванням потоковості SSR це може бути ще складнішим. Перегляньте посібник Vite із SSR.

  • Генерація статичного сайту (SSG) генерує статичні HTML-файли для вашого застосунку під час збирання. SSG може покращити продуктивність, але його налаштування та обслуговування можуть бути складнішими, ніж для рендерингу з боку сервера.

  • Серверні компоненти React (RSC) дають змогу змішувати компільовані, суто серверні та інтерактивні компоненти в одному React-дереві. RSC може покращити продуктивність, але наразі необхідні глибокі знання для його налаштування та обслуговування. Перегляньте приклади RSC від Parcel.

Ваші стратегії рендерингу мають бути інтегровані з вашим маршрутизатором, щоб застосунки, створені за допомогою вашого фреймворку, могли вибирати стратегію рендерингу для кожного маршруту. Це дає змогу використовувати різні стратегії рендерингу без переписування всього застосунку. Наприклад, головна сторінка вашого застосунку може мати користь від статичної генерації (SSG), а сторінка з інформаційною стрічкою — від рендерингу з боку сервера. Використання слушної стратегії рендерингу для відповідних маршрутів може зменшити час до завантаження першого байта вмісту (час до першого байта), рендерингу першого фрагмента вмісту (малювання першого вмісту, FCP) і рендерингу найбільшого видимого вмісту застосунку (малювання найбільшого вмісту, LCP).

Розділення коду

Розділення коду — це процес розбиття вашого застосунку на менші бандли, які можна завантажувати на вимогу. Розмір коду застосунку збільшується з кожною новою функцією чи доданою залежністю. Застосунки можуть повільно завантажуватися, оскільки перед використанням потрібно надіслати весь код для всього застосунку. Кешування, зменшення функцій/залежностей і перенесення деякого коду для виконання на сервері радше пришвидшать завантаження, але є неповними рішеннями, які можуть пожертвувати функціональністю у разі надмірного використання.

Також якщо ви покладаєтеся на те, щоб застосунки на базі вашого фреймворку розділяли код, ви можете зіткнутися із ситуаціями, коли завантаження стає повільнішим, ніж якби розділення коду не відбувалося взагалі. Наприклад, ліниво завантажена діаграма затримує надсилання коду, необхідного для її рендерингу, відділяючи свій код від решти застосунку. Parcel підтримує розділення коду за допомогою React.lazy. Однак, якщо діаграма завантажує свої дані після свого початкового рендерингу, ви тепер чекаєте двічі. Це водоспад: замість одночасного отримання даних для діаграми та надсилання коду для її рендерингу, ви повинні чекати, поки кожен крок завершиться один за одним.

Розділення коду за маршрутом, інтегроване з бандлером й отриманням даних, може зменшити час початкового завантаження вашого застосунку та рендерингу найбільшого видимого вмісту застосунку (малювання найбільшого вмісту, LCP).

І більше…

Це були лише кілька прикладів функцій, які необхідно враховувати фреймворку.

Є багато інших проблем, які користувачі повинні вирішити, наприклад:

  • Доступність
  • Завантаження ресурсів
  • Автентифікація
  • Обробка помилок
  • Мутація даних
  • Навігації
  • Вкладені маршрути
  • Оптимістичні оновлення
  • Кешування
  • Поступове покращення (Progressive Enhancement)
  • Генерація статичного сайту (SSG)
  • Рендеринг з боку сервера (SSR)

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