1 Webpack. Введение в арх-ру. Code splitting. Css Modules
Dec 24, 202420 min read
1 Начало разработки Основы Webpack. Добавляем TypeScript Метка
Первым делом нужно инициализировать проект
Далее нужно будет установить вебпак и первый плагин к нему
Далее идёт настройка конфига вебпака
В output свойство filename отвечает за название того файла, который будет генерироваться. Конкретно тут используются шаблоны, конфигурирующие стандартное имя для файла и хеш:
[name] - выберет дефолтное имя по пути
[contenthash] - будет добавлять хеш в название, чтобы браузер не сохранял закешированный файл
webpack.config.js
Тут сразу стоит сказать, что входных точек в проект может быть несколько
Далее нам нужно будет добавить typescript и его лоадер, чтобы вебпак смог его обработать
Добавим типы и обработчик ноды
Далее меняем расширение конфига и меняем входной файл на .ts. Добавляем resolve и module, в который поместим лоадер для обработки ts файлов
webpack.config.ts
Для работы нодовских пакетов, нормальных импортов и модулей в целом, нужно добавить такой конфиг в проект:
tsconfig.json
И примерно так выглядит итоговый проект
2 Декомпозиция конфига. Опции конфигурации
Далее перед нами встанет задача разбить конфигурацию вебпака на несколько разных файлов, чтобы было проще поддерживать разрастающийся конфиг
Первым делом нужно будет описать типы тех данных, что будет принимать в себя конфиг:
типы режима (разработка | продакшн)
пути
config > build > types > config.ts
Далее нам нужно будет вынести плагины в отдельную функцию, которая будет принимать в себя объект конфига и брать из него пути, чтобы сослаться на html
config > build > buildPlugins.ts
Далее нужно будет вынести лоадеры в отдельный файл, так как их будет много.
Некоторые лоадеры нужно будет вынести в константы, чтобы было проще отслеживать последовательность их выполнения (потому что это может играть роль в работе приложения)
config > build > buildLoaders.ts
Далее выносим резолверы в отдельную функцию
config > build > buildResolvers.ts
Выносим остальную часть конфига в отдельную функцию, которая будет принимать в себя опции конфига. Тут же и вызываем все функции для сборки остальных частей конфига вебпака
config > build > buildWebpackConfig.ts
В основном файле конфига добавляем переменные путей и разработки, чтобы можно было их контролировать из одного места и вызываем buildWebpackConfig(), чтобы собрать вебпак конфиг
webpack.config.ts
И примерно так выглядит проект в конце:
3 Webpack-dev-server. Переменные окружения (env)
Установим модуль девсервера для вебпака
Далее нужно будет создать отдельную функцию конфига под сервер
config > build > buildDevServer.ts
Добавляем в основной конфиг два свойства:
devtool - будет формировать мэпы внутри файлов
devServer - хранит конфиг для девсервера. Если мы находимся в продакшене, то нам не нужен конфиг
config > build > buildWebpackConfig.ts
Добавим в конфиг BuildEnv, который будет отвечать за попадаемые переменные окружения и добавим порт в BuildOptions, на котором будет запускаться приложение
config > build > types > config.ts
Чтобы переменные окружения попадали в конфиг, его нужно обернуть в функцию, которая будет принимать в себя env. После уже можно будет воспользоваться данными переменными и задать порт для приложения
webpack.config.ts
Теперь можно добавить три команды, которые будут выполнять разную сборку проекта
package.json
4 Подключаем React и настраиваем css в webpack метка
Устанавливаем зависимости реакта
Устанавливаем зависимости лоадеров
Далее нужно добавить правила для лоадеров в конфиг buildLoaders()
config > build > buildLoaders.ts
Корневой компонент, которому мы поменяли расширение на TSX
src > index.tsx
Так же нужно не забывать менять путь к entry-файлу в приложении
Сам компонент с подключенными стилями
src > components > app > App.tsx
Стили
src > components > app > App.scss
5 Настраиваем css modules
Цель: реализовать подключение модульных и глобальных стилей
Первым делом нужно установить экстрактор, который будет отделять чанки
Далее в конфигурацию плагинов нужно добавить MiniCssExtractPlugin, внутри которого нужно будет определить наименования собранных css-файлов
config > build > buildPlugins.ts
В лоадерах нужно настроить style-loader и экстрактор, чтобы они работали в разное время (прод/дев) и нужно настроить css-loader, чтобы он поддерживал модули в названиях файлов и транспилировал их в объекты, которые поддерживаются JS
config > build > buildLoaders.ts
Так же нужно добавить глобальные типы, которые определят то, что находится внутри импортируемых модулей стилей - без этого TS не поймёт, что импортируется из модульных стилей
src > global.d.ts
И теперь работают все стили приложения
6 Роутинг Code splitting Lazy Suspence метка
Первым делом нужно установить роутер и его
Code Splitting, Lazy Loading, Async Chunks - это всё механизмы подгрузки данных на страницу по необходимости.
Конкретно мы имеем SPA и несколько страниц в рамках него и их всех стоило бы подгружать ровно тогда, когда он на них перейдёт.
В обычном случае у нас генерируется один бандл со всеми страницами, а нужно, чтобы генерировалось несколько
Оборачиваем всё приложение в BrowserRouter, чтобы работали роуты
src > index.tsx
Далее нужно добавить опцию historyApiFallback, чтобы проксировать все запросы через index. Это нужно, чтобы страница не выдавала ошибку при перезагрузке, если это не стартовая страница
`config > build > buildDevServer.ts
Далее нужно реализовать две страницы в приложении
src > pages > AboutPage.tsx
src > pages > MainPage.tsx
И тут же мы создадим их lazy-варианты, чтобы они подгружались только тогда, когда мы на них заходим
Такой подход будет говорить webpack, что мы хотим выделить эти страницы в отдельные бандлы, чтобы они подгружались только при необходимости
src > pages > AboutPage.async.tsx
src > pages > MainPage.async.tsx
И в корневом компоненте App нужно реализовать сам роутинг.
Вместо обычных страниц, нужно использовать их асинхронные версии, чтобы они уходили в отдельный бандл.
Реакт обязует нас использовать компонент Suspense вместе с асинхронными компонентами, чтобы пользователь знал, что идёт подзагрузка страницы.
src > components > app > App.tsx
И теперь у нас подгружается только те страницы, на которые мы зашли
7 Организация стилей. Добавляем темы
Цель: нам нужно организовать стили между разными файлами, организовать быструю смену тем
В приложении будут использоватся css-переменные вместо переменных SASS.
Стили будут распределены подобным образом (reset.scss находится тут):
src > styles > index.scss
src > styles > variables > global.scss
src > styles > themes > light.scss
src > styles > themes > dark.scss
И первым делом, что нужно сделать для глобального сохранения состояния темы - это создать контекст, который будет в себе хранить функцию смены темы и само значение темы
src > theme > ThemeContext.ts
Далее нужно будет реализовать провайдер контекста, в который мы обернём всё приложение
src > theme > ThemeProvider.ts
И уже потом оборачиваем всё приложение в провайдер
src > index.tsx
Тут реализован хук получения функции изменения темы и самой темы
`src > theme > useTheme.tsx
И далее просто получаем функцию смены темы и саму тему в корневом компоненте приложения
src > components > app > App.tsx
В итоге мы имеем смену темы по кнопке и сохранение её в локальном хранилище
8 classNames создаем git репозиторий
Цель: реализовать свой хелпер для добавления нескольких классов
Ниже представлена реализация замены библиотеке classnames (или clsx), которая будет принимать в себя классы по условию и массив различных классов
src > helpers > classNames > classNames.ts
Тут представлено использование функции
`src > components > app > App.tsx
9 Архитектура. введение. Теория
В данном проекте будет использоваться архитектура FSD, которая предоставляет оптимальную организацию проекта фронтенд приложения
FSD предоставляет архитектуру, которая делит приложение на 7 компонентов, каждое из которых делится на слайсы:
shared — переиспользуемый код, не имеющий отношения к специфике приложения/бизнеса.(например, UIKit, libs, API)
features (фичи) — взаимодействия с пользователем, действия, которые несут бизнес-ценность для пользователя.(например, SendComment, AddToCart, UsersSearch)
widgets (виджеты) — композиционный слой для соединения сущностей и фич в самостоятельные блоки(например, IssuesList, UserProfile).
pages (страницы) — композиционный слой для сборки полноценных страниц из сущностей, фич и виджетов.
app — настройки, стили и провайдеры для всего приложения.
10 Архитектура. Начинаем внедрять. Основы метка
Первым делом, нужно настроить абсолютные пути в самом конфиге TS
tsconfig.json
Далее нужно добавить в интерфейс свойство базового пути конфига
`config > build > types > config.ts
И далее добавим путь до папки src
`webpack.config.ts
Этот путь нужен был для настройки конфига buildResolvers, в котором нужно указать настройки абсолютных путей (preferAbsolute, modules, mainFields, alias)
config > build > buildResolvers.ts
Далее нужно перекомпоновать проект следующим образом:
Все компоненты страниц, которые связаны с отображением, идут в папку ui. Из неё экспортируем асинхронный компонент, который будем использовать в App