Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Выучить React недостаточно для профессиональной разработки больших приложений. Для этого есть две основные причины. Первая, у React есть огромная экосистема модулей, в которой необходимо разбираться. Вторая, эта экосистема меняется каждый год. Поэтому может быть не просто разобраться во всех тонкостях применения React, и эта статья может стать путеводителем в увлекательный мир современного React.
К этой статье прилагается GitHub репозиторий и Демо приложение, которые демонстрируют работу упомянутых в этой стать модулей (и некоторых других). GitHub репозиторий можно использовать в качестве boilerplate для вашего следующего профессионального приложения.
P.S. Я пишу также статьи на английском языке. Английский вариант этой моей статьи доступен тут.
Основные модули
Next.js — React SSR фреймворк
Redux — Central state management
next-redux-wrapper — Next and Redux коннектор
Redux-Saga — Async middleware для Redux
next-translate — Переводы и i18n
React Hook Form — Работа с формами
Chakra UI — Design system
Демо — https://enterprise-react-2022.vercel.app
Репо — https://github.com/slava-lu/enterprise-react-2022
Основное изменение по сравнению со стеком популярным пару лет назад является обязательное использование технологии Server-Side Rendering (SSR). Это уже не просто способ улучшить индексируемость поисковыми системами или немного улучшить производительность приложения. Без SSR практически невозможно добиться хороших результатов в новой методике оценки сайтов от Google - Core Web Vitals. Core Web Vitals стали настолько важны, что учебный раздел основного SSR фреймворка посветил этой теме целый раздел. Я рекомендую достаточно хорошо изучить Core Web Vitals. При постоянно увеличивающимся объеме информации может быть не просто определить какой сайт лучше исключительно на основе его контента, поэтому основным определяющим фактором для поисковых систем может стать количество усилий, которые вложили разработчики в создание продукта.
Основным фреймворком для создания SSR приложений на React является Next.js. В настоящий момент каких-то реальных альтернатив не существует. Next.js достаточно прост и имеют хорошую документацию и обучающий раздел. На нем можно легко создать простое приложение, но создание крупных веб решений может вызвать сложности. Проблемным местом является Redux, который все еще требуется при создании больших приложений. Многочисленные попытки избавиться от Redux или заменить его на что-то другое пока не привели к его исчезновению. Учитывая, как сильно он облегчает работу разработчика, я думаю что Redux будет с нами еще несколько лет.
Сложность при работе с Redux состоит в том, что он предназначен для работы на стороне клиента (в браузере). Каждый раз, когда вы генерите страницу на сервере, вы создаёте новый Redux store, который надо синхронизовать с данными на клиенте. Этот процесс называется Hydration. Hydration может быть не простым и быть подвержен ошибкам. Оптимальным подходом было бы начальная генерация страницы на сервере вместе с созданием нового чистого Redux store, и затем последующая генерация страниц на клиенте. Таким и был изначальный подход Next.js, когда они предложили метод getInitialProps для получения данных. По каким-то причинам позже они решили не продвигать этот метод и предложили два новых метода getServerSideProps и getStaticProps в качестве потенциальной замены изначального getInitialProps
. Основной посыл компании Vercel, которая стоит за Next.js заключался в том, что два новых метода могу улучшить производительность приложений. Они не отказались полностью от getInitialProps
, но старались не упоминать его ни в документации, ни в своих коммуникациях.
Целью метода getStaticProps
является генерация страницы во время сборки приложения и затем отдача статического контента браузеру. Я сомневаюсь, что крупные приложения имеют много статического контента. Возможно, основной целью getStaticProps
была попытка конкурировать с фреймворком Gatsby. Смысл метода getServerSideProps
менее прозрачен даже после ознакомления с объяснениями от Vercel. Разработчики продолжают спорить о целесообразности использования этого метода вместо getInitialProps
. Очевидно, однако, что getInitialProps
работает гораздо лучше с Redux, и полный отказ от этого метода может привести к значительному уменьшению популярности Next.js. Поскольку в мире React других реальных альтернатив нет, то это могло бы мотивировать разработчиков посмотреть в сторону Vue.js и Nuxt.js и возможно там и остаться.
На текущий момент пока не очевидно, какой путь выберет Next.js. В Демо приложении я использовал все три метода, чтобы показать, как с ними можно работать. Как можно увидеть из кода, работать с getInitialProps
гораздо удобней, чем с другими двумя методами.
В качестве Redux middleware для работы с REST API (а также WebSocket) я рекомендую использовать старый добрый модуль Redux-Saga. Он дает возможность хорошо отделять UI от бизнес-логики, а также позволяет легко реализовывать сложную логику получения данных. Стоит отметить, что процесс начального изучения Redux-Saga может быть трудоемким, но затем вы сможете легко и быстро создать любые асинхронные middleware.
Если вы следите за трендами в мире React, то могли заметить, что иногда высказываются предложения переместить функции получения данных на уровень React компонентов. Однако мне кажется, что это может быть всего лишь очередной попыткой наконец-то избавиться от Redux. Я не вижу особых преимуществ от такого объединения. Наоборот, разделения UI от получения данных позволяет улучшить надежность приложения и облегчает его разработку. Простота и скорость разработки, которая получила свой термин как “Developer Experience” становится все более важной в современном мире. Технологии становятся более сложными, а их изучение более трудоемким. Человеку трудно постичь их всех, не говоря уже о том, чтобы овладеть ими. Поэтому простота разработки может стать определяющим фактором в выборе технологии.
Одним из дополнительных преимуществ при использовании Redux-Saga совместно с Next.js является простота выбора стратегии навигации и получения данных. Существует два основных подхода к этому вопросу:
Сначала переход на страницу, потом загрузка данных
Сначала предзагрузка данных, потом переход на страницу.
Первый способ, на мой взгляд является более популярным, однако его не так легко реализовать на Next.js, поскольку Next.js блокирует навигацию до завершения работы любого из трех методов получения данных, описанных выше. Redux-Saga, однако, позволяет указать, хотите ли вы дожидаться завершения запросов (перевода Promise в статус resolved) до навигации или нет, таким образом реализуя любую из этих двух стратегий. Вы можете посмотреть, как это делается в Демо приложении. Ищите свойство navigateAfterSaga
.
Shop.getInitialProps = async ({ store }) => {
store.dispatch(triggerProductList(10))
return {
navigateAfterSaga: false,
title: 'title#shop_page',
}
}
Что касается низкоуровневой функции запроса данных, то я предлагаю использовать axios вместо классического fetch. В большей степени из-за отличного функционала, который предлагает axios при работе с таймаутами как на стороне клиента, так и на стороне сервера. Честно говоря, я даже не знаю, как можно реализовать таймауты на стороне сервера при работе с Next.js и fetch.
Одной из новых и приятных функциональностей Next.js является интернациональная маршрутизация (Internationalized Routing). Она предоставляется прямо из коробки и позволяет добавлять префиксы к URL для мультиязычных сайтов. К сожалению, это только маленькая часть того, что нужно разработчикам для создания мультиязычных сайтов. Как минимум необходим еще модуль переводов. Выбирать его следует осторожно, так как не все модули переводов поддерживают все три методы получения данных, предлагаемые Next.js. Я предлагаю использовать next-translate, так как он поддерживает getInitialProps
.
Еще одной полезной функцией, которая требуется мультиязычным сайтам, является функция изменения URL в зависимости от языка. Не только префикса, а всего URL. Так например en/page
должно стать de/seite
. Есть примеры реализации этого функционала с помощью настройки rewrites. Но это явно не то место, где это должно делаться. Хочется надеяться, что разработчики Next.js обратят внимание на этот вопрос в будущем.
Одной из важных задач при выборе стека является выбор UI модуля или Дизайн Системы (Design System). Можно сделать свою собственную, но это достаточно трудоемко. Существуют готовые решения и очевидным лидером среди них на сегодняшней день является Chakra UI. Ранее популярной опцией был также Material UI, но он уже несколько приелся, да и развивается не очень активно. Chakra UI предлагает хороший выбор базовых бесплатных элементов, а также платные сложные темплейты. С помощью этих темплейтов можно создать дизайн E-Commerce сайта за считанные дни, не прибегая к помощи таких инструментов как Figma или аналогичных. Это очень здорово.
Проблема при использовании этой библиотеки, как в прочем и почти любой другой состоит в том, что она навязывает свой API. Если вы успели выучить наизусть все свойства CSS, то при использовании Chakra UI придется учить их заново. В прочем, вы можете распечатать основные из них и повесить где-нибудь перед собой. Для уникальных или сложных UI компонентов я предлагаю использовать styled-components. Эта библиотека очень гибкая и позволяет использовать стандартный CSS без сокращений или конвертации в Camelcase.
Что касается работы с формами, то в экосистеме React появился новый лидер. Некоторое время назад на смену всем известной библиотеки Redux Form пришел Formik. Проблема с Formik заключалась в том, что эта библиотека использует шаблон render props. В свое время этот шаблон был популярен, но не прижился в React сообществе. Мне кажется этот шаблон несколько запутанным, и при разработке больших приложений бывает трудно понять, что происходит в коде.
На фоне сложностей с Formik и другими библиотеками для обработки форм появилась новая - React Hook Form, которая очень активно набирает популярность. Она очень проста в использовании, но имеет одну особенность. Она основана на шаблоне неуправляемых компонентов (Uncontrolled Components). Из-за этого становиться непросто отсылать форму не из компонента самой формы, но это возможно. Простота и очень хорошая документация является неоспоримыми преимуществами этой библиотеки.
Этот был обзор основных модулей для того, чтобы вы могли начать создавать большие корпоративные приложения на React.
Хочется еще сказать несколько слов про развертывание приложений. Если вы создали приложение на Next.js, то я рекомендую рассмотреть возможность его развёртывания на хостинге Vercel. Вы можете подключить свой репозиторий GitHub к облаку Vercel и развернуть приложение за пару кликов мышкой. Что еще более приятно, так это то, что вы получаете готовый CI/CD из коробки. Как только вы создаете Pull Request (PR), то создается так называемая preview версия приложения на основе этого PR. После принятия этого PR, основное приложение также автоматически обновляется. Если вы когда-либо пытались настроить такой функционал в Jenkins или GitHub Actions, то вам непременно эта функциональность должна понравиться.
Есть еще пара важных тем, которые напрямую не относятся к React, но относятся к области frontend разработки. Я скажу пару слов о них ниже.
Тестирование. Тема тестирования является гораздо более запутанной, чем кажется на первый взгляд. С одной стороны, никто не сомневается, что тестирование является важным. Но немногие могу раскрыть, какое тестирование является важным и почему. Большой шум вокруг юнит тестирования пришел к нам из мира backend, где у разработчиков нет возможности мгновенно видеть результат своей работы. Единственным простым и быстрым способом убедиться в качестве написанного кода для backend разработчика является тестирование его юнит тестами. Но это не так в мире frontend. С надежной и производительной технологией Fast Refresh, которую предлагает Next.js и другие фреймворки, frontend разработчик может мгновенно видеть результат каждой строчки кода, которую он печатает. Если это еще и соединить с компонентным подходом, который разделяет элементы кода (особенно при использовании Redux-Saga), то ценность юнит тестирования становиться совсем неочевидной. Я даже готов сделать смелое утверждение, что юнит тестирование приносит совсем мало пользы при современной разработки React приложений, если только у вас нет файлов с действительно сложной логикой. Но если они есть, то имеет смысл подумать про перенос этой логики на backend.
Но что может быть действительно полезным, так это функциональное тестирование интерфейса. Разработчику часто бывает сложно заметить, что радиус контейнера картинки составляет 2px вместо 4px, или что расстояние между элементами интерфейса увеличилось на 4px. Этот тип тестирования может быть хорошо автоматизирован. Также может быть полезным хаотичное нажатие на ссылки и кнопки. Разработчики обычно проверяют только разумный сценарий, который должны выбрать сознательные пользователи. Случайное нажатие на кнопки может уронить сайт или привести к отображению неправильных данных. Таких проблем лучше избегать.
Typescript. Typescript активно пытается стать основным языком разработки frontend приложений, но пока не смог получить этот статус. Утверждается, что Typescript позволяет совершать меньше ошибок при разработке приложений. Возможно, это так, но не стоит забывать про побочные эффекты, такие как менее читаемый код и дополнительный траблшутинг специфичных для Typescript проблем, который отнимает время, но не улучшает при этом само приложение. Можно сравнить Typescript c автопилотом от Tesla. Автопилот Tesla действительно хорош и помогает водителю управлять автомобилем. Проблема, однако, состоит в том, что он стоит 10К+ долларов и водитель все равно не может расслабиться и посмотреть фильм на заднем сидении. Он вынужден держать руки на руле. Возникает вопрос, а в чем тогда ценность этого Автопилота?
Похожие рассуждения можно применить и к Typescript. Вы все равно должны быть хорошим разработчиком, чтобы создавать профессиональные приложения. Но если вы являетесь профессиональным разработчиком, то возможно вам не нужен и Typescript, чтобы помогать вам писать качественный работающий код, и вы можете создавать приложения быстрей без него.
Возможно, часть хайпа вокруг Typescript идет от backend разработчиков, которые приходят в мир frontend и пытаются ООПезировать JavaScript, чтобы чувствовать себя более комфортно.
Typescript может быть полезен при разработке модулей для других разработчиков, так как это позволяет получить подсказки в стиле IntelliSense от IDE. Ценность Typescript при разработке конечных продуктов для меня менее очевидна.
Последняя тема, которую я хотел бы тут затронуть, это сторонние сервисы. Сегодня никто не хочет возиться с настройкой почтовых серверов и других инфраструктурных сервисов. Чтобы сэкономить вам немного времени на поиск информации, я составил свой список предпочтений. Я не буду приводить какие-либо аргументы, чтобы не увеличивать объем статьи, но мы можем обсудить мой выбор в комментариях, если будет желание.
Cloudinary — хранение мультимедиа и обычных файлов
Sendgrid — отправка технических emails
Mailchimp — отправка маркетинговых emails
Sendbird — чаты и другая коммуникация с пользователями
Многие могут сказать, что они создали хорошие приложения, используя другой набор модулей. Это скорей всего будет правда. Но что я могу обещать, так это то, что вы не пожалеете, если остановите свой выбор на стеке, представленным здесь.
Надеюсь, что этот обзор был вам полезен и интересен и поможет вам лучше понять экосистему React, даже если вы не согласны со всеми тезисами в этой статье.