NextJS та нові серверні компоненти — навіщо потрібні та як готувати
Всім привіт, мене звати Віталій Рубан, я працюю в компаніїї Itera і сьогодні я розкажу про нову, цікаву, але досить неоднозначну можливість, яка з’явилася в останньому, великому оновленні [email protected] — серверні компоненти.
Навіщо з’явилися серверні компоненти?
Давайте почнемо з найважливішого — відповіді на запитання «Навіщо з’явилися серверні компоненти»?
Як ви, напевно вже знаєте, спрощено, Next.JS працює наступним чином:
- Клієнт звертається за адресою, яку обслуговую Next.JS сервер
- Next.JS, в рантаймі (можуть бути опитмізації з кешуванням), отримує необхідні для створінки дані
- І створює HTML сторінку, яку, разом з JS кодом, відправляє клієнтові
- Оскільки сторінка є звичайним HTML-ем — користувач бачить її по мірі завантаження і, на відміну від SPA, не чекає допоки React створить її з нуля на клієнті
- Після отримання клієнтського бандлу відбувається процес гідрації — перетворення статичного HTML-у на звичний нам React застосунок, з яким користувач може взаємодіяти. Якщо гідрацію не робити, користувач просто не зможе взаємодіяти з HTML сторінкою, тому що всі event listner додаються саме на цьому етапі

Весь цей, не тривіальний процес робиться для того, щоб ваш користувач як найшвидше побачив потрібний йому контент і не пішов передачсно з вашого веб сайту. Це також спрощує життя SEO роботам і збільшує шанси сторінки опинитися вище в пошуку. При цьому, розробник може працювати в звичному і зручному React-і з усіма його перевагами — компонентним підходом, HMR, та багатим інструментарієм.
Але цей процес має недоліки, найбільший з яких полягає в тому, що на гідрацію потрібен час, протягом якого застосунок є не інтерактивним. І чим більший ваш бандл, тим більше часу потрібно на гідрацію. Можлива навіть така ситуація, коли користувач вже завантажив сторінку, намагається з нею взаємодіяти, але вона не відповідає, оскільки головний потік зайнятий. Це справляє враження що сторінка взагалі не робоча, люди можуть просто з неї піти і ще й друзям розкажуть, що ваш магазин не працює.
Другий недолік полягає в тому, що як і в гідрації, так і в життєвому циклі React застосунку участь приймають всі компоненти, навіть ті, контент яких ніколи не змінюється. Це, відповідно, зменшує час відгуку вашої сторінки на дії користувача, що погано для користувацького досвіду.
І ось тут на допомогу і приходять серверні компоненти які намагаються вирішити обидві проблеми одночасно за рахунок наступного:
- Залежності, які ви використовуєте в серверних компонентах не включаються в бандл, взагалі. Це зменшує його розмір і пришвидшує момент коли ваша сторінка стає інтерактивною.
- Серверні компоненти не приймають участь ні в гідрації, ні життєвому циклі застосунків, що пришвидшує час реакції застосунку (власне дає більше часу для інших операцій) та зберігає батарею вашого телефону
Звичайно, така магія безкоштовною небуває, тому серверні компоненти мають суттєві обмеження (деякі з яких майже повністю нівелюють їх користь).
Правила та обмеження серверних компонентів
Перше правило серверних компонентів — нікому не казати що ти використовуєш серверні компоненти серверні компоненти не можуть мати додану поведінку. useState, useEffect, onClick та інший інтерактив заборонений для використання в серверних компонентах. І це логічно, якщо ви згадаєте що серверні компоненти не можуть змінюватися. Якщо вам все ж таки потрібна поведінка — вам потрібні клієнтські компоненти. Звичайні функції, в тому числі fetch — дозволені. Але, майте на увазі, що серверні компоненти виконуються на сервері, тож вони не можуть звертатися до API браузера, об’єктів window та document. Ще один цікавий момент полягає в тому, що нативна інтерактивність елементів нікуди не ділася, тому форми, чекбокси, радіки, лінки, summary та всі інші компоненти, що мають вбудовану поведінку — будуть чудово працювати.
Також серверні компоненти не можуть використовувати контекст, що призовдить до того, що багато звичних нам інструментів, які побудовані на контексті — таких як Redux Toolkit, Emotion, навіть популярна бібліотека компонентів MUI — не працюють з серверними компонентами. І це, на мою думку, найбільший та найсуттєвіший недолік серверних компонентів, який нівелює майже всю їх користь. Щоправда, наразі існує експерементальний, серверний контекст, але, він, по-перше, поки що не використовується стороннімі бібліотеками, а, по-друге, не коректно працює під час навігації.
Друге правило серверних компонентів — всі компоненти вважаються серверними, поки не сказано протилежне. Якщо вам потрібний клієнтський компонент, ви повинні додати директиву ’use client’ на самому початку файла з компонентами, до усіх імпортів. Наприклад ось так:
"use client";
import { useState } from "react";
export function Counter() {
...
}З перших двох пунктів випливає, що, за замовчуванням, Next.JS застосунок не дуже орієнтований на інтерактив. Майте це на увазі, коли обираєте фреймворк для вашого наступного застосунку.
Третє правило серверних компонентів полягає в тому, що імпорт серверного компоненту клієнтським автоматично перетворює останній на клієнтський, тим самим позбавляючи його усіх тих переваг про які я писав вище. Цей момент дуже важливий, тому наголошу на ньому ще раз: Будь-які серверні компоненти, імпортовані до клієнтського компоненту, автоматично перетворюються на клієнтські. Причому цей ефект транзитивний — підкомпоненти також стають клієнтськими автоматично і так до останнього компоненту в ієрархії. Як казав дід Панас — отака біда* малята.
Практичним наслідком цього стає, те що, якщо ви, на свій рутовий компонент (наприклад сторінку) додасте директиву use-client, то всі її імпорти та імпорти їх імпортів автоматично перетворяться на клієнтські компоненти. З цього випливає те, що директиву use client треба використовувати якумога нижче за ієрархією імпорту. Ще одним варіантом трохи вирішити цю ситуацію — використовувати children в клієнтських компонентах. Оскільки прямого імпорту не відбувається, це працює. Звісно, за умови що компонент-композитор є серверним компонентом.
Ну і нарешті четверте правило серверних компонентів, яке дещо підсоложує мою трохи гіркувату історію — вони можуть бути асинохронними і можуть отримувати дані прямо в тілі компоненту, без жодних useEffect. Далі ці дані можна обробити і передати в уже клієнтські компоненти, які зможуть і контекст створити і якусь взаємодію додати. А для обробки помилок, які виникають під час асинхронних операцій, достатньо додати файл error.jsx/tsx. Це досить зручо і трохи покращує враження від усіх попередніх обмежень. Але, буду відвертим — не сильно.
Підсумки
Технологія потенційно корисна і може зробити ваші застосунки швидшими за рахунок зменшення вихідного бандлу. Але не можливість використання контексту, та бібліотек, що на ньому побудовані, майже повністю нівелює їхню користь в реальному світі. Навіть якщо ваша сторінка повністю статична, але наприклад, використовує популярну білібіотек CSS in JS — emotion для стилізації, ви не зможете використовувати серверні компоненти в повному обсязі — максимум як контейнер для зручного отримання даних, але очевидно, що це не то на що розраховували розробники коли додавали серверні компоненти.
А що ви думаєте з цього приводу?
* Дід Панас не так казав.
Відео-варіант цієї статті (та інші навчальні відео) можна знайти на моєму каналі React для початківців. А ще в нас є телеграм про React
Оновлення № 1
Питання: Якщо ми використовуємо емоушен(наприклад) і вішаємо на рутовий компонент ’use client’ у нас некст стає реактом без серверного рендеру?🤔
Відповідь: У нас є, умовно, три рівні рендеру:
Рівень — 1 — «Голий» реакт, рендериться на клієнті
Рівень — 2 — SSR, рендеремо на сервері, в бандл кладемо всі залежності
Рівень — 3 — серверні компоненти, рендеремо на сервері, в бандл кладемо лише залежності клієнтських компонентів
Коли ви використовуєте use client, ви відкочуєтесь до другого рівня. Серверний рендерінг залишається, але клієнт буде отримувати всі залежності
Оновлення № 2
MUI (material UI) версії v5.14.0 заявив про підтримку нового app router в Next.JS і оновив гайди:
20 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарівСкажите, а есть тут те, кто использует HoudiniCSS?developer.mozilla.org/...US/docs/Web/Guide/Houdini Если да, то поделитесь впечатлениями. Получается, что препроцессоры с постпроцессорами приказали долго жить?
ось є класний ресурс де розказують про ментальну модель та концепцію RSC на прикладах — demystifying-rsc.vercel.app
Коментар порушує правила спільноти і видалений модераторами.
Если коротко, по тому что сказал Дэн Абрамов этом видео www.youtube.com/watch?v=h7tur48JSaw. Разделение между серверным и клиентским компонентами позволит нам снова в полной мере использовать преимущества сервера. Перенеся несколько основных задач, таких как выборка данных, на сервер, мы можем уменьшить размер пакета и повысить производительность наших приложений.
Про Qwik что скажите пододвинет, он React.js?React.js лишен реактивности,сигналов и прогрессивности хоть по названию этого и не скажешь.
Маєте на увазі цей quick.js.org ?
Да.
У мене немає досвіду з цією бібліотекою. Але React намагались скинути вже двічі і поки без особливих успіхів. А тут — останній коміт в бібліотеці був 06.2022, документації не багато.. На вбивцю React не схоже
имелся ввиду этот фрейм qwik.builder.io
я понимаю что ваши сообщения полугодичной давности, ответ скорее для других читателей:
фрейм, как по мне, толковый. очень нравятся основные концепции. очень похож на некст.
из плюсов: вместо гидратации resumability. из коробки есть роутер. реактивность. контекст можно юзать в качестве начального стейтменеджера, тк ререндерит тоьлко подписаные на него комопненты. код несколько лаконичней в итоге нежели на реакте. сразу не вспомню всех плюшек.
из минусов: на сегодня маленькая экосистема, много чего самому писать прийдется. если вы ленивый и либы ваше все, то самое время прокачаться -) в то же время в дискорде много ответов на люые вопросы и мемберы охотно помогают друг другу.
ЗЫ на убийцу реакта вряд ли потянет, но имхо займет свое время под солнцем..
по поводу контекста обмолвился — прелесть как раз таки в том, что из всех подписанных ререндерится только выполнивший «запрос» компонент.
так же из + то что фрейм в-дом «дергает» только по мере необходимости, а не после каждого чиха.
Мені серверні компоненти дуже зайшли, просто треба розібратись з філософією, яку вкладали розробкики. До речі, це не лише команда Next.js працювала над цим, а спільно з розробниками React, оскільки серверні компоненти це саме їхня ідея. А бібліотеки підтягнуться, оскільки за оптимізацією майбутнє.
А підкажіть, під які задачі вони вам зайшли?
Я про загальне враження. Мені концепція подобається, яка має очевидні переваги по оптимізації і не тільки.
Спорный вопрос. С моей точки зрения больше стал на пыху смахивать!
Сама ідея — чудова. Просто на практиці вона лягає лише на мінімально інтерактивні застосунки. А це трохи суперечить ідеї самого React)
Скоріше це провал для Next, а 3rd party як жили так і будуть жити. Це ж не вони витратили час на адаптацію та підтримку серверних компонентів
Прикручивают какое-то кривое и бесполезное говно к хорошему фреймворку, делая из него черт знает что. Хотят что-то испоганить — пусть бы сделали новый фреймворк и извращились над ним как душе угодно.
Серверні компоненти, по-факту опціональні, тому тут великої проблеми немає.
А новий роутер мені як раз сподобався, нарешті не треба дублювати структуру проекту, і є зручні вкладені роути
Если вам так роутер нравится, тогда вам нужно было писать про Remix.js там все вокруг роутинга и крутится.
Не роутером єдиним. NextJS більш популярний та стабільний на разі.