создание react приложения без create react app
Создаем приложение React с нуля в 2021 году
Apr 24 · 10 min read
Замысел проекта
До этого подобную тему освещал Jedai Saboteur в своей статье Creating a React App… From Scratch (англ.), на которую ввиду ее грамотности даже сделали ссылку в официальной документации React.
Как бы то ни было, но время идет, и я р ешил создать современное приложение React с нуля в 2021 году. В итоге было решено добавить в цепочку инструментов ряд “важных элементов” и задействовать последние версии основных библиотек. В некотором смысле у меня получилась последняя версия вышеприведенного руководства.
Задача
Тем не менее помимо настройки простого рабочего приложения я также определил пару дополнительных, “важных” по меркам современного стека, требований:
Инструменты
Озадачившись списком необходимых инструментов, я решил обратиться к документации React.
После прочтения раздела Creating Toolchain from Scratch я прикинул следующий список:
Этот краткий отрывок достаточно подробно раскрывает суть необходимых компонентов. В итоге на их роли я выбрал:
Это вполне типичные варианты. Даже если вам не приходилось заниматься самостоятельной настройкой этих инструментов, то вы наверняка с ними либо работали, либо просто о них слышали.
Однако, согласно моим требованиям, все еще недостает одного элемента: библиотеки управления состоянием.
Redux могла стать очевидным выбором, но я предпочел Kea. Дело в том, что разработана Kea на базе Redux, но при этом существенно упрощает управление состоянием.
По правде говоря, здесь я определенно предвзят, так как выбрал Kea больше из-за того, что использую эту библиотеку на работе, а разработал ее мой коллега.
Начало
В src будет храниться весь исходный код проекта, а в public мы разместим статические ресурсы.
Настройка
Наше руководство будет не универсальным, а обучающим, и работа с возникающими сложностями станет его неотъемлемой частью.
В качестве примера я решил взять для этого руководства webpack v5, который вызвал ряд проблем совместимости с конфигурациями, используемыми мной ранее в проектах с webpack v4. Как обычно разобраться с этой проблемой и попутно запастись дополнительными знаниями мне помогла документация, различные статьи и посты на Stack Overflow.
Babel
Для работы Babel требуется еще несколько пакетов, которые устанавливаются так:
babel-core — это компилятор, то есть сам основной компонент.
babel-cli позволит использовать компилятор из командной строки.
Последние три пакета — это “шаблоны” (настройки) Babel для работы с различными сценариями использования. present-env избавляет нас лишних проблем, позволяя писать современный JS-код и обеспечивая его работоспособность на различных клиентах. preset-typescript и preset-react говорят сами за себя: так как используем мы и TypeScript, и React, то нам понадобятся они оба.
TypeScript
В этом проекте мы будем использовать TypeScript, поэтому у него будут свои дополнительные настройки.
Сначала установим пакет typescript :
Забегая чуть вперед, я предлагаю вам также установить следующие пакеты, если вы собираетесь следовать руководству до конца:
В них содержатся объявления типов для модулей, которые мы задействуем в проекте.
Можете смело менять приведенную конфигурацию под свои нужды. Тем не менее важно сохранить эти опции:
Webpack
Для работоспособности этому инструменту также требуется ряд настроек. По сути, для каждого типа файла, который мы будем собирать, понадобится отдельный загрузчик.
webpack и webpack-cli следуют тому же принципу, что и Babel. Первый является основным пакетом, а второй позволяет обращаться к нему через командную строку.
webpack-dev-server требуется нам для локальной разработки. Вы заметите, что package.json никогда не ссылается на него из скрипта, но он необходим для запуска webpack serve :
Последними идут загрузчики, нужные для разных файлов, которые мы будем обрабатывать. ts-loader также присутствует, но поскольку мы используем для компиляции JS-файлов Babel, фактичекски, он нам не понадобится.
В завершении, как и для Babel, нужно настроить файл конфигурации webpack.config.js :
React
Учитывая, что создаем мы приложение React, нам также нужны и соответствующие пакеты.
Этого будет достаточно:
В завершении настроим библиотеку управления состоянием.
Согласно документации нам нужно следующее:
Здесь мы подумаем наперед и добавим отдельный пакет, который используется при написании логики Kea в TypeScript:
package.json
После всей этой настройки нужно добавить в package.json пару скриптов:
start будет запускать сервер, а typegen генерировать типы для файлов логики Kea.
Наконец, сам код React
Нехило так настроечек? Думаю, что шаблоны определенно заслуживают благодарности, особенно, когда они берут на себя все управление зависимостями и версионирование (react-scripts).
Как бы то ни было, но с настройкой мы закончили, и пора заняться кодом.
Но сначала немного чистого HTML
Здесь происходит несколько действий:
Точка входа
Вот содержимое моего:
Здесь происходит три основных действия:
2. Мы импортируем и отрисовываем компонент App (который еще не собран).
3. Мы сообщаем React отрисовать приложение, используя div root из index.html в качестве «точки привязки».
Приложение!
Далее также внутри src/ создайте файл App.tsx со следующим содержимым:
Эти два дополнительных компонента я включил, чтобы убедиться в следующем:
Так что при желании вы можете на этом остановиться. Если же вы тоже хотите увидеть, как работают перечисленные возможности, то продолжим.
Написание JS и TS
Проблем не возникает, так как в webpack.config.js установлено это правило:
Чтобы убедиться в работоспособности этой схемы, я просто создал мелкий JS-компонент и импортировал его в приложение.
Counter
Последним я добавил в этот мини-проект традиционный React-компонент Counter.
Задачей было убедиться в работоспособности настроек Kea и в том, что при этом также работает импорт CSS-файлов.
1. index.tsx — содержит сам компонент:
3. style.css — здесь я использовал минимальную стилизацию просто, чтобы убедиться в правильной работоспособности CSS:
Вот и все!
Если вы добрались до этой части, то, надеюсь, на выходе вы получили свежеиспеченное приложение React, современный шаблон, а также некоторый багаж дополнительных знаний. Честно говоря, здесь я просто задокументировал часть своего процесса обучения, но и вы наверняка из этого что-нибудь да почерпнули!
Отказ от create-react-app и создание собственного шаблона для React-приложений
Что такое CRA?
Create React App — это набор инструментов, созданный и поддерживаемый разработчиками из Facebook. CRA предназначен для быстрого создания шаблонных проектов React-приложений. При использовании CRA база React-проекта создаётся с помощью одной команды.
Сильные стороны CRA
Недостатки CRA
Альтернатива CRA
Вот репозиторий, в котором имеется весь код, который мы будем обсуждать в этом материале.
Начнём работу с инициализации проекта средствами npm и с инициализации его git-репозитория:
Это позволит нам не включать в состав репозитория папки, имена которых присутствуют в файле.
Теперь поразмыслим о том, какие основные зависимости нам нужны для того чтобы собрать и запустить React-приложение.
Библиотеки react и react-dom
Это — единственные зависимости времени выполнения, которые нам нужны:
Транспилятор (Babel)
Транспилятор Babel преобразует код, соответствующий стандартам ECMAScript 2015+, в код, который будет работать и в новых, и в устаревших браузерах. Babel, благодаря применению пресетов, используется и для обработки JSX-кода:
Babel поддерживает множество пресетов и плагинов. Их можно добавлять в проект по мере возникновения необходимости в них.
Бандлер (Webpack)
Бандлер Webpack отвечает за сборку проекта, формируя на основе кода проекта и кода его зависимостей единственный файл (бандл) приложения. При использовании таких техник оптимизации проектов, как разделение кода, в бандл приложения могут входить и несколько файлов.
Простая конфигурация Webpack, предназначенная для сборки пакетов React-приложений, выглядит так, как показано ниже:
Сюда, в соответствии с нуждами конкретного приложения, можно добавить различные загрузчики. Если вам эта тема интересна — взгляните на мой материал, где я рассказываю о конфигурациях Webpack, которыми можно воспользоваться для подготовки React-приложений к использованию в продакшне.
Это — все необходимые нам зависимости. Теперь давайте добавим в проект шаблонный HTML-файл и заготовку React-компонента.
Создадим в директории проекта папку src и добавим в неё файл index.html :
В той же папке создадим React-компонент HelloWorld :
В ту же папку добавим файл index.js :
И наконец — добавим в package.json описания скриптов для запуска ( start ) и сборки ( build ) проекта:
Теперь давайте оснастим нашу систему возможностью подготовки шаблона проекта с помощью единственной команды. То есть — воссоздадим одну из сильных сторон CRA. Мы собираемся использовать исполняемый JS-файл, который будет вызываться при вводе соответствующей команды в командной строке. Например, подобная команда может выглядеть так:
Сначала установим пакет fs-extra:
Теперь давайте свяжем этот исполняемый JS-файл с командой из package.json :
Создадим локальную связь для пакета:
Замечательно. Теперь всё это работает на вашем компьютере и позволяет вам, пользуясь единственной командой, создавать базовые React-проекты, обладающие собственной конфигурацией сборки.
Вы можете пойти дальше и опубликовать свой шаблон в реестре npm. Для того чтобы это сделать, сначала надо отправить проект в GitHub-репозиторий. А дальше — следуйте этим инструкциям.
Конечно, наше решение минималистично. Проекты, создаваемые на его основе, нельзя признать готовыми к использованию в продакшне. Для того чтобы подготовить их к реальной работе, нужно оснастить наш шаблон некоторыми настройками Webpack, ответственными за оптимизацию сборок проектов.
Я подготовил шаблон reactjs-boilerplate, позволяющий создавать проекты, готовые к работе в продакшне. Тут используется соответствующая конфигурация сборки, линтинг и хуки, ответственные за проверку проекта перед созданием коммитов. Испытайте этот шаблон. Если у вас появятся какие-то идеи по его совершенствованию, или если вы решите сделать вклад в его разработку — присоединяйтесь к работе над ним.
Итоги
Вот о чём мы говорили в этом материале:
Пользуетесь ли вы create-react-app при создании новых React-проектов?
Что взять за основу React приложения
Каждый раз начиная писать React приложение, вы так или иначе выберите какой-то вариант:
Каждый из способов имеет свои сильные и слабые стороны, как на длинной, так и на короткой дистанции.
Некоторые решения скрывают сложность в начале, позволяя сделать быстрый старт. Это что-то вроде решения под ключ, но в результате такие решения могут оказаться недостаточно гибкими и сложными в подстройке. С другой стороны, в начале все может казаться слегка монструозным и неповоротливым, и чтоб начать нужно немного повозиться, но зато потом преимущества станут очевидными. Всегда есть возможность сделать все с нуля, ровно так, как хочется, но в таком случае Вы будете отвечать за бесчисленные аспекты и Вам потребуются очень глубокие знания во всех участвующих технологиях.
Очевидно, что иметь некий стандарт внутри компании крайне полезно, когда речь идет о разработке нескольких проектов, таким образом любая команда может быть переключена на любой проект. Или в случае дизайн-студии, которая постоянно создает новые и новые проекты. В этом случае создание основы должно занимать как можно меньше времени. Общий стандартный подход позволяет командам и разработчикам делиться знаниями, можно вести некую базу стандартных решений, лучших практик и т.д.
Анализ рынка показывает, что существует несколько довольно стабильных проектов, предоставляющих некую инфраструктуру для создания сайтов на React. Я выбрал несколько из них, стараясь чтоб все кандидаты, для наглядности, имели как можно более разную природу.
Кандидаты
Что нужно помнить разрабатывая современное приложение
Кешируемые части
Если собрать все приложение в один гигантский JS файл, то он будет грузиться вечность, пока юзеры будут наблюдать анимацию загрузки. Исследования показывают, что юзеры предпочитают покидать сайты, которые не успевают загрузиться за 3 секунды.
Управление статикой
С одной стороны приложение должно доставить как можно больше сразу, чтоб не ходить лишний раз по сети за ресурсами (картинки, стили, скрипты), например, т.н. vendor-chunk со всеми библиотеками, важные CSS скрипты. Но в то же время мы хотим доставлять как можно меньше, только то, что необходимо на данной странице.
Server Side Rendering
Приложение может загрузить все необходимые данные и сгенерировать готовый HTML, который вместе с данными будет отдан клиенту, таким образом практически устраняется задержка между первоначальной загрузкой и моментом, когда хоть что-то появляется на сайте, хотя бы для просмотра. Про возможность всем этим пользоваться не говорим, это отдельная тема.
Google ранжирует сайты с помощью времени отклика в том числе. Не смотря на то, что поисковики умеют рендерить AJAX сайты, это плохо влияет на позицию, поэтому сайт обязан предоставлять некую версию, которую смогут переварить поисковики. С этим есть проблема, если мы захотим загрузить все данные, а не только основную контентную область, как дать понять серверному рендеру, что все загрузки закончены? Для этого пока нет сложившегося подхода. В кастомном варианте мы можем распарсить дерево компонентов и выдернуть из каждого, например, статический метод getInitialProps (по аналогии с Next.js), и когда все эти методы вернут свои значения, тогда и можно рендерить.
Для того, чтобы компоненты сами могли сказать, что им нужно из данных, был придуман Relay + GraphQL, но минусы перевешивают его плюсы. Для него надо отдельный сервер. Он дико словоблуден (сама схема + мутации чудовищно громоздки). Сложность кода, который нужно написать для простейших действий практически убивает все бонусы. Объяснить это кому-то из команды с нуля тоже проблематично. К тому же потребуется специальный Babel трансформ, а также утилита для скачивания и компилиции схемы. А в результате все равно получится несовместимое с SEO нечто. Стоит признать, что если вы только потребляете существующий GraphQL API, то ситуация чуть получше. Это довольно многообещающая технология, хочется верить, что у ребят получится сделать ее более дружелюбной. Стоит еще отметить такую штуку как Apollo Framework.
Во время исследования я создал пару библиотек, которые могут помочь с Server Side Rendering:
Производительность Server Side Rendering
В какой-то момент производительности сервера перестанет хватать для рендеринга компонентов. В таком случае некоторые компоненты можно начать кешировать.
CSS preprocessors
Многие пользуются LESS/SASS/Stylus/PostCSS для того, чтобы использовать переменные и микс-ины в своих стилях, так код получается чище и лаконичнее.
В любом из кандидатов всегда можно создать отдельный процесс сборки/watch’а за стилями SASS/LESS, как например в Create React App, но полученный CSS нужно руками как-то подключать к приложению (в Create React App его можно импортировать напрямую). В этом случае Critical CSS и Hot Module Reloading, а также Server-Side Rendering стилей становится вашей заботой, что нивелирует преимущества не-кастомных решений.
Интеграция со сторонними UI библиотеками
Очевидно, что используя лучшие библиотеки для интерфейсов мы улучшаем вид продукта, ускоряем его создание, особенно если мы говорим о таких вещах как Twitter Bootstrap или Material Design. Эти библиотеки обычно идут в комплекте с CSS, который нужно каким-то образом включить в приложение.
Critical CSS / Above The Fold CSS
Грубо говоря, определенные стили можно загрузить вместе с HTML, таким образом пользователи никогда не увидят т.н. вспышку нестилизованного контента (FOUC). Полезно, но совершенно не критично, т.к. современные сети достаточно производительны и стилевая таблица весом до 100КБ это вообще ни о чем.
Поддержка скинов
Это редкий кейс нужный далеко не всем, но многие приложения поддерживают разные скины для разных брендов или просто для удобства пользователей (ну например темная или светлая цветовая схема).
Экосистема и сообщество
Жить внутри экосистемы, хорошо спроектированной и документированной, всегда приятнее, чем разбираться в куче мелких библиотек: меньше мороки с зависимостями, возможность следовать направлению, заданному авторами, кучи примеров. Вспоминается фраза, что если вы не используете фреймворк, то в итоге вы его напишете сами.
Тесты
Думаю уже никто не будет спорить, что в современном мире без тестов вообще никуда.
Boilerplate, конфигурация, начальная стоимость
Поскольку мы планируем делать много проектов основанных на одном стандарте, мы хотим иметь как можно меньше мороки с первоначальной настройкой и запуском наших решений. Для этого желательно чтоб инициализация плодила как можно меньше файлов и конфигов.
Кривая обучения в начале и в сложных случаях, сложность кастомизации, поддержка в будущем
Предположим, вы будете работать с приложением в составе команды, в таком случае вам придется каким-то образом обучать своих коллег. Документация и зафиксированные паттерны — это хорошая основа для легкого обмена знаниями внутри команды и между командами.
Возможность кастомизировать что угодно тоже должна присутствовать, т.к. мы живем в реальной жизни и в ней что угодно может поменяться когда угодно, требования же не вечны. И очень не хотелось бы упереться в какое-то жесткое ограничение фреймворка.
Интернационализация
Для удобства строки с локализацией должны быть в стандартном формате, с подстановками и склонениями. Желательно в таком, который может быть легко воспринят фирмами, занимающимися переводами, потому что именно они будут больше всего с ними возиться.
Ни один из представленных фреймворков не дает никаких средств для перевода. Однако, их несложно добавить. После поисков я выяснил, что централизованный асинхронный загрузчик работает лучше всего, в таком случае каждый язык становится отдельным chunk’ом. Добиться этого можно создав функцию, которая принимает язык как параметр и отдает асинхронно загруженные строки для языка. Что-то типа const loadStrings(lang) => import(‘./strings/’+lang) (данная конструкция вряд ли сразу заработает, но суть должна быть понятна, перед ней можно еще насоздавать Webpack Context’ов, чтоб гарантировать связку 1 язык = 1 чанк.
Библиотеки: FormatJS и Format Message (и та и та работает с так называемым ICU Format).
Сравнение
Дисциплина \ Название | React App | Electrode | Next.js | Custom |
---|---|---|---|---|
Dynamic Routes | да | да | DIY | да |
Server rendering | нет | да | да | DIY |
SSR optimization | нет SSR | да | нет | DIY |
CSS | да | да | ночной кошмар | DIY легко |
Preprocessors | ночной кошмар | ночной кошмар | ночной кошмар | DIY легко |
Critical CSS | DIY | плагин | нет | DIY |
Сообщество | большое | есть | есть | ты сам по себе |
Тесты | jest | phantom | DIY | DIY |
Код основы | ноль | много | ноль | очень много |
Конфигурация | ноль | много | ноль | очень много |
Документация | хорошая | так себе | в наличии | разрозненная |
Обучение простому | сел и поехал | приемлемо | легко | ночной кошмар |
Дальнейшее обучение | проще умереть | тяжело | тяжело | ночной кошмар |
Движок сервера | nginx | node | node | node |
Кастомизация | eject и смерть | приемлемо | ночной кошмар | все что угодно |
Первоначальная установка | легко | словоблудно | легко | ночной кошмар |
Предсказуемость | хорошая | так себе | плохая | ночной кошмар |
Апгрейды | шикарно | неплохо | так себе | ночной кошмар |
Вердикт
Если вы не собираетесь заниматься серверным рендерингом (вы ничего не продаете, приложение не индексируется гуглом, и вообще приватное), то можете смело смотреть в сторону Create React App, он самый популярный и простой. Его даже можно немножечко кастомизировать. Только eject не делайте, оно того не стоит.
Если серверный рендеринг нужен, и вы готовы смириться с кое-какими ограничениями, то выбирайте Electrode (в качестве условия вас так же не должны пугать большое количество файлов, словоблудность и конфигурации). Это так же хороший выбор, если вас беспокоит производительность.
Если вы готовы мириться с еще большими ограничениями и любите минимализм, то присмотритесь к Next.js.
Ну и наконец, всегда есть кастом. К счастью, библиотеки типа Webpack Blocks, Create React Server, React Router, Redux и прочие делают жизнь сильно проще. Единственная проблема это обмен знаниями и выработка процессов для быстрого создания приложений без повторения одного и того же кода каждый раз.
Отказ от create-react-app и создание собственного шаблона для React-приложений
Что такое CRA?
Create React App — это набор инструментов, созданный и поддерживаемый разработчиками из Facebook. CRA предназначен для быстрого создания шаблонных проектов React-приложений. При использовании CRA база React-проекта создаётся с помощью одной команды.
Сильные стороны CRA
Недостатки CRA
Альтернатива CRA
Вот репозиторий, в котором имеется весь код, который мы будем обсуждать в этом материале.
Начнём работу с инициализации проекта средствами npm и с инициализации его git-репозитория:
Это позволит нам не включать в состав репозитория папки, имена которых присутствуют в файле.
Теперь поразмыслим о том, какие основные зависимости нам нужны для того чтобы собрать и запустить React-приложение.
Библиотеки react и react-dom
Это — единственные зависимости времени выполнения, которые нам нужны:
Транспилятор (Babel)
Транспилятор Babel преобразует код, соответствующий стандартам ECMAScript 2015+, в код, который будет работать и в новых, и в устаревших браузерах. Babel, благодаря применению пресетов, используется и для обработки JSX-кода:
Babel поддерживает множество пресетов и плагинов. Их можно добавлять в проект по мере возникновения необходимости в них.
Бандлер (Webpack)
Бандлер Webpack отвечает за сборку проекта, формируя на основе кода проекта и кода его зависимостей единственный файл (бандл) приложения. При использовании таких техник оптимизации проектов, как разделение кода, в бандл приложения могут входить и несколько файлов.
Простая конфигурация Webpack, предназначенная для сборки пакетов React-приложений, выглядит так, как показано ниже:
Сюда, в соответствии с нуждами конкретного приложения, можно добавить различные загрузчики. Если вам эта тема интересна — взгляните на мой материал, где я рассказываю о конфигурациях Webpack, которыми можно воспользоваться для подготовки React-приложений к использованию в продакшне.
Это — все необходимые нам зависимости. Теперь давайте добавим в проект шаблонный HTML-файл и заготовку React-компонента.
Создадим в директории проекта папку src и добавим в неё файл index.html :
В той же папке создадим React-компонент HelloWorld :
В ту же папку добавим файл index.js :
И наконец — добавим в package.json описания скриптов для запуска ( start ) и сборки ( build ) проекта:
Теперь давайте оснастим нашу систему возможностью подготовки шаблона проекта с помощью единственной команды. То есть — воссоздадим одну из сильных сторон CRA. Мы собираемся использовать исполняемый JS-файл, который будет вызываться при вводе соответствующей команды в командной строке. Например, подобная команда может выглядеть так:
Сначала установим пакет fs-extra:
Теперь давайте свяжем этот исполняемый JS-файл с командой из package.json :
Создадим локальную связь для пакета:
Замечательно. Теперь всё это работает на вашем компьютере и позволяет вам, пользуясь единственной командой, создавать базовые React-проекты, обладающие собственной конфигурацией сборки.
Вы можете пойти дальше и опубликовать свой шаблон в реестре npm. Для того чтобы это сделать, сначала надо отправить проект в GitHub-репозиторий. А дальше — следуйте этим инструкциям.
Конечно, наше решение минималистично. Проекты, создаваемые на его основе, нельзя признать готовыми к использованию в продакшне. Для того чтобы подготовить их к реальной работе, нужно оснастить наш шаблон некоторыми настройками Webpack, ответственными за оптимизацию сборок проектов.
Я подготовил шаблон reactjs-boilerplate, позволяющий создавать проекты, готовые к работе в продакшне. Тут используется соответствующая конфигурация сборки, линтинг и хуки, ответственные за проверку проекта перед созданием коммитов. Испытайте этот шаблон. Если у вас появятся какие-то идеи по его совершенствованию, или если вы решите сделать вклад в его разработку — присоединяйтесь к работе над ним.
Итоги
Вот о чём мы говорили в этом материале:
Пользуетесь ли вы create-react-app при создании новых React-проектов?