Server Rendering Errors in React 18: part 1
В трёх из пяти крупных проектах, которые мне довелось трогать, был серверный рендеринг.
И в каждом из этих проектов было 3 проблемы:
1. как получать данные;
2. что делать с ошибками серверного рендера;
3. как ловить mismatch серверной и клиентской разметки после React.hydrate.
Про данные сегодня говорить не будем, т.к. Suspense пока что не поддерживает фетчинг этих самых данных и, в целом, это так или иначе решаемая проблема. А вот у второго и третьего пункта решения появились буквально пару дней назад.
Сперва про ошибки.
Самое неприятное, что может случиться при рендере страницы на сервере — 500 ошибка. Стоит где-то забыть обернуть обращение к window и вот пользователь видит 500 Internal Server Error. Красота. Обычно, такие ошибки мониторятся, но всё равно есть скорость реакции: ошибку нужно локализовать, откатить, починить, снова выкатить. А иногда ещё бывает стреляет не сразу, а, скажем, ночью. В общем, неприятно.
В Альфа-Банке мы обходили это достаточно странным способом. Если рендер падал с ошибкой, то пользователю просто отдавался пустой див
И это действительно работало. Правда потом кто-то (быть может даже я) сделал ошибку на достаточно популярной странице и за пару недель мы потеряли 20 позиций в гугле.
Естественно, было принято решение исправить это недоразумение, и в случае ошибки просто отдавать 500 код и специальную страничку «ой что-то сломалось». Этим самым был открыт ящик пандоры: мы увидели настоящее кол-во ошибок и, мягко говоря, офигели.
Меня всегда угнетала идея, что даже если самый маленький компонент где-то в глубине дерева будет написан с ошибкой, то приложение целиком отрендерить просто невозможно. Я много времени посвятил поиску решений: гуглил server error boundary, читал кучу ишью, изучал сомнительные имплементации кастомного серверного рендера и так далее.
К счастью, всё это в прошлом. Теперь в React 18 достаточно обернуть часть приложения в Suspense и указать fallback.
Если что-то внутри Comments пойдет не так, то не отрендерится лишь часть приложения. Точнее отрендерится то, что указано в качестве fallback. Ну, и внутри фолбек-компонента можно залогировать что произошла такая-то ошибка и пришлось рендерить этот самый фолбек.
В трёх из пяти крупных проектах, которые мне довелось трогать, был серверный рендеринг.
И в каждом из этих проектов было 3 проблемы:
1. как получать данные;
2. что делать с ошибками серверного рендера;
3. как ловить mismatch серверной и клиентской разметки после React.hydrate.
Про данные сегодня говорить не будем, т.к. Suspense пока что не поддерживает фетчинг этих самых данных и, в целом, это так или иначе решаемая проблема. А вот у второго и третьего пункта решения появились буквально пару дней назад.
Сперва про ошибки.
Самое неприятное, что может случиться при рендере страницы на сервере — 500 ошибка. Стоит где-то забыть обернуть обращение к window и вот пользователь видит 500 Internal Server Error. Красота. Обычно, такие ошибки мониторятся, но всё равно есть скорость реакции: ошибку нужно локализовать, откатить, починить, снова выкатить. А иногда ещё бывает стреляет не сразу, а, скажем, ночью. В общем, неприятно.
В Альфа-Банке мы обходили это достаточно странным способом. Если рендер падал с ошибкой, то пользователю просто отдавался пустой див
<div id="app"></div>
с 200 кодом ответа, как будто это просто SPA и, в общем-то, это работало. Даже если на сервере случалась ошибка, пользователь всё равно получал страничку и мог заказать кредитную карту.И это действительно работало. Правда потом кто-то (быть может даже я) сделал ошибку на достаточно популярной странице и за пару недель мы потеряли 20 позиций в гугле.
Естественно, было принято решение исправить это недоразумение, и в случае ошибки просто отдавать 500 код и специальную страничку «ой что-то сломалось». Этим самым был открыт ящик пандоры: мы увидели настоящее кол-во ошибок и, мягко говоря, офигели.
Меня всегда угнетала идея, что даже если самый маленький компонент где-то в глубине дерева будет написан с ошибкой, то приложение целиком отрендерить просто невозможно. Я много времени посвятил поиску решений: гуглил server error boundary, читал кучу ишью, изучал сомнительные имплементации кастомного серверного рендера и так далее.
К счастью, всё это в прошлом. Теперь в React 18 достаточно обернуть часть приложения в Suspense и указать fallback.
<Suspense fallback={<Spinner />}>
<Comments />
</Suspense>
Если что-то внутри Comments пойдет не так, то не отрендерится лишь часть приложения. Точнее отрендерится то, что указано в качестве fallback. Ну, и внутри фолбек-компонента можно залогировать что произошла такая-то ошибка и пришлось рендерить этот самый фолбек.