feat: модульная конфигурация webpack с React 19 и TypeScript 5

- Создана модульная архитектура webpack конфигурации в config/build/
- Настроены loader'ы: Babel, TypeScript, CSS/SCSS, File, SVGR
- Добавлены плагины: HtmlWebpackPlugin, MiniCssExtractPlugin, ReactRefresh, BundleAnalyzer
- Настроен dev-сервер с HMR и поддержкой SPA роутинга
- Добавлена полная JSDoc документация на русском языке
This commit is contained in:
Ilia Mashkov
2025-11-19 09:59:39 +03:00
commit 1376a20c90
12 changed files with 493 additions and 0 deletions

View File

@@ -0,0 +1,30 @@
import { Configuration as DevServerConfiguration } from 'webpack-dev-server'
import { BuildOptions } from './types/config'
/**
* Конфигурация webpack-dev-server для режима разработки
*
* Настраивает локальный сервер разработки с поддержкой:
* - Hot Module Replacement (HMR) - горячая перезагрузка модулей
* - History API Fallback - поддержка клиентского роутинга (SPA)
* - Автоматическое открытие браузера
*
* @param {BuildOptions} options - Опции сборки
* @param {number} options.port - Порт для запуска сервера (по умолчанию 3000)
* @param {boolean} options.open - Автоматически открывать браузер при запуске
* @returns {DevServerConfiguration} Конфигурация webpack-dev-server
*
* @example
* // Запуск: pnpm dev
* // Сервер будет доступен на http://localhost:3000
*/
export function buildDevServer(options: BuildOptions): DevServerConfiguration {
const { port, open } = options
return {
port,
open,
historyApiFallback: true,
hot: true,
}
}

View File

@@ -0,0 +1,37 @@
import webpack from 'webpack'
import { buildBabelLoader } from './loaders/buildBabelLoader'
import { buildCssLoader } from './loaders/buildCssLoader'
import { buildFileLoader } from './loaders/buildFileLoader'
import { buildSvgrLoader } from './loaders/buildSvgrLoader'
import { buildTypescriptLoader } from './loaders/buildTypescriptLoader'
import { BuildOptions } from './types/config'
/**
* Собирает все webpack loaders в единый массив
*
* Порядок loaders важен! Webpack применяет их справа налево (снизу вверх).
* Текущий порядок:
* 1. fileLoader - обрабатывает изображения и шрифты
* 2. svgrLoader - преобразует SVG в React компоненты
* 3. babelLoader - транспилирует JS/JSX/TSX с React Refresh
* 4. typescriptLoader - компилирует TypeScript
* 5. cssLoader - обрабатывает CSS/SCSS с модулями
*
* @param {BuildOptions} options - Опции сборки
* @param {boolean} options.isDev - Флаг режима разработки
* @returns {webpack.RuleSetRule[]} Массив правил для webpack
*/
export function buildLoaders({ isDev }: BuildOptions): webpack.RuleSetRule[] {
const babelLoader = buildBabelLoader(isDev)
const fileLoader = buildFileLoader()
const svgrLoader = buildSvgrLoader()
const typescriptLoader = buildTypescriptLoader()
const cssLoader = buildCssLoader(isDev)
return [fileLoader, svgrLoader, babelLoader, typescriptLoader, cssLoader]
}

View File

@@ -0,0 +1,72 @@
import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin'
import HtmlWebpackPlugin from 'html-webpack-plugin'
import MiniCssExtractPlugin from 'mini-css-extract-plugin'
import webpack from 'webpack'
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'
import { BuildOptions } from './types/config'
/**
* Конфигурация webpack плагинов
*
* Собирает все необходимые плагины для сборки приложения.
*
* Плагины для всех режимов:
* - HtmlWebpackPlugin: генерирует HTML файл и автоматически подключает скрипты
* - MiniCssExtractPlugin: извлекает CSS в отдельные файлы с хешами для кеширования
* - ProgressPlugin: показывает прогресс сборки в консоли
* - DefinePlugin: определяет глобальные константы для использования в коде
*
* Плагины только для разработки:
* - BundleAnalyzerPlugin: анализирует размер бандла (не открывается автоматически)
* - ReactRefreshWebpackPlugin: обеспечивает быструю перезагрузку React компонентов
* - HotModuleReplacementPlugin: включает горячую замену модулей (HMR)
*
* @param {BuildOptions} options - Опции сборки
* @param {BuildPaths} options.paths - Пути проекта
* @param {boolean} options.isDev - Флаг режима разработки
* @param {string} options.apiUrl - URL API для глобальной переменной __API__
* @param {string} options.project - Тип проекта для глобальной переменной __PROJECT__
* @returns {webpack.WebpackPluginInstance[]} Массив плагинов webpack
*
* @example
* // Глобальные константы доступны в коде:
* if (__IS_DEV__) {
* console.log('Development mode')
* }
*
* fetch(__API__ + '/users')
*/
export function buildPlugins({
paths,
isDev,
apiUrl,
project,
}: BuildOptions): webpack.WebpackPluginInstance[] {
const plugins = [
new HtmlWebpackPlugin({
template: paths.html,
}),
new MiniCssExtractPlugin({
filename: 'css/[name].[contenthash:8].css',
chunkFilename: 'css/[name].[contenthash:8].css',
}),
new webpack.ProgressPlugin(),
new webpack.DefinePlugin({
__IS_DEV__: JSON.stringify(isDev),
__API__: JSON.stringify(apiUrl),
__PROJECT__: JSON.stringify(project),
}),
]
if (isDev) {
plugins.push(
new BundleAnalyzerPlugin({
openAnalyzer: false,
})
)
plugins.push(new ReactRefreshWebpackPlugin({ overlay: false }))
plugins.push(new webpack.HotModuleReplacementPlugin())
}
return plugins
}

View File

@@ -0,0 +1,36 @@
import webpack from 'webpack'
import { BuildOptions } from './types/config'
/**
* Конфигурация разрешения модулей для webpack
*
* Определяет, как webpack будет искать и разрешать импорты модулей.
*
* Настройки:
* - extensions: автоматически разрешает указанные расширения файлов
* - preferAbsolute: предпочитает абсолютные пути относительным
* - modules: директории для поиска модулей
* - mainFiles: имена файлов по умолчанию при импорте директории
* - alias: алиасы для упрощения импортов (можно расширить)
*
* @param {BuildOptions} options - Опции сборки
* @param {BuildPaths} options.paths - Пути проекта
* @returns {webpack.ResolveOptions} Конфигурация resolve для webpack
*
* @example
* // Благодаря extensions можно писать:
* import Component from './Component' // вместо './Component.tsx'
*
* // Благодаря mainFiles можно писать:
* import utils from './utils' // вместо './utils/index.ts'
*/
export function buildResolvers(options: BuildOptions): webpack.ResolveOptions {
return {
extensions: ['.tsx', '.ts', '.js'],
preferAbsolute: true,
modules: [options.paths.src, 'node_modules'],
mainFiles: ['index'],
alias: {},
}
}

View File

@@ -0,0 +1,60 @@
import webpack from 'webpack'
import { buildDevServer } from './buildDevServer'
import { buildLoaders } from './buildLoaders'
import { buildPlugins } from './buildPlugins'
import { buildResolvers } from './buildResolvers'
import { BuildOptions } from './types/config'
/**
* Главная функция сборки конфигурации webpack
*
* Объединяет все модули конфигурации (loaders, plugins, resolvers, devServer)
* в единую конфигурацию webpack.
*
* Основные настройки:
* - mode: режим сборки (development/production)
* - entry: точка входа приложения (src/index.tsx)
* - output: настройки выходных файлов с хешами для кеширования
* - module.rules: правила обработки различных типов файлов
* - resolve: настройки разрешения модулей
* - plugins: плагины для расширения функциональности webpack
* - devtool: source maps для отладки (только в dev режиме)
* - devServer: настройки dev-сервера (только в dev режиме)
*
* @param {BuildOptions} options - Полные опции сборки
* @returns {webpack.Configuration} Готовая конфигурация webpack
*
* @example
* const config = buildWebpackConfig({
* mode: 'development',
* paths: { entry: 'src/index.tsx', ... },
* isDev: true,
* port: 3000,
* open: true,
* apiUrl: 'http://localhost:8000',
* project: 'frontend'
* })
*/
export function buildWebpackConfig(
options: BuildOptions
): webpack.Configuration {
const { mode, paths, isDev } = options
return {
mode,
entry: paths.entry,
output: {
path: paths.build,
filename: '[name].[contenthash].js',
clean: true,
publicPath: '/',
},
module: {
rules: buildLoaders(options),
},
resolve: buildResolvers(options),
plugins: buildPlugins(options),
devtool: isDev ? 'inline-source-map' : undefined,
devServer: isDev ? buildDevServer(options) : undefined,
}
}

View File

@@ -0,0 +1,30 @@
/**
* Конфигурация Babel loader для webpack
*
* Обрабатывает файлы JavaScript, JSX и TSX с помощью Babel.
* В режиме разработки включает React Refresh для горячей перезагрузки компонентов.
*
* @param {boolean} isDev - Флаг режима разработки
* @returns {Object} Конфигурация babel-loader
*
* @example
* const babelLoader = buildBabelLoader(true)
* // Возвращает loader с React Refresh для разработки
*/
export function buildBabelLoader(isDev: boolean) {
const babelLoader = {
test: /\.(js|jsx|tsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: [isDev && require.resolve('react-refresh/babel')].filter(
Boolean
),
},
},
}
return babelLoader
}

View File

@@ -0,0 +1,43 @@
import MiniCssExtractPlugin from 'mini-css-extract-plugin'
/**
* Конфигурация CSS/SCSS loader для webpack
*
* Обрабатывает файлы .css, .scss и .sass с поддержкой CSS модулей.
* В режиме разработки использует style-loader для инъекции стилей в DOM.
* В режиме production использует MiniCssExtractPlugin для извлечения CSS в отдельные файлы.
*
* CSS модули автоматически включаются для файлов с паттерном *.module.*
*
* @param {boolean} isDev - Флаг режима разработки
* @returns {Object} Конфигурация css-loader с поддержкой SCSS и CSS модулей
*
* @example
* // Для файла Button.module.scss будут применены CSS модули
* // Для файла global.scss CSS модули не применяются
*/
export const buildCssLoader = (isDev: boolean) => {
const cssLoader = {
test: /\.s[ac]ss$/i,
use: [
// Создает <style> теги из JS строк (dev) или извлекает в файлы (prod)
isDev ? 'style-loader' : MiniCssExtractPlugin.loader,
// Преобразует CSS в CommonJS модули
{
loader: 'css-loader',
options: {
modules: {
auto: /\.module\..*$/,
localIdentName: isDev
? '[path][name]__[local]--[hash:base64:5]'
: '[hash:base64:8]',
},
},
},
// Компилирует Sass в CSS
'sass-loader',
],
}
return cssLoader
}

View File

@@ -0,0 +1,27 @@
/**
* Конфигурация file-loader для webpack
*
* Обрабатывает статические файлы: изображения и шрифты.
* Копирует файлы в директорию сборки и возвращает публичный URL.
*
* Поддерживаемые форматы:
* - Изображения: .png, .jpg, .jpeg, .gif
* - Шрифты: .woff, .woff2
*
* @returns {Object} Конфигурация file-loader
*
* @example
* import logo from './logo.png'
* // logo будет содержать путь к файлу в сборке
*/
export function buildFileLoader() {
const fileLoader = {
test: /\.(png|jpe?g|gif|woff|woff2)$/i,
use: [
{
loader: 'file-loader',
},
],
}
return fileLoader
}

View File

@@ -0,0 +1,24 @@
/**
* Конфигурация SVGR loader для webpack
*
* Преобразует SVG файлы в React компоненты.
* Позволяет импортировать SVG как обычные React компоненты с возможностью
* управления их свойствами (цвет, размер и т.д.) через props.
*
* @returns {Object} Конфигурация @svgr/webpack loader
*
* @example
* import Logo from './logo.svg'
*
* function App() {
* return <Logo width={100} height={100} fill="red" />
* }
*/
export function buildSvgrLoader() {
const svgrLoader = {
test: /\.svg$/,
use: ['@svgr/webpack'],
}
return svgrLoader
}

View File

@@ -0,0 +1,23 @@
/**
* Конфигурация TypeScript loader для webpack
*
* Компилирует TypeScript файлы (.ts, .tsx) в JavaScript.
* Выполняет проверку типов во время сборки.
*
* @returns {Object} Конфигурация ts-loader
*
* @example
* // Обрабатывает файлы:
* // - Component.tsx
* // - utils.ts
* // - types.d.ts
*/
export function buildTypescriptLoader() {
const typescriptLoader = {
test: /\.tsx?$/,
use: 'ts-loader',
exclude: '/node-modules/',
}
return typescriptLoader
}

View File

@@ -0,0 +1,54 @@
/**
* Режим сборки приложения
* @typedef {'development' | 'production'} BuildMode
*/
export type BuildMode = 'development' | 'production'
/**
* Пути для конфигурации webpack
* @interface BuildPaths
* @property {string} entry - Точка входа приложения (src/index.tsx)
* @property {string} build - Директория для выходных файлов сборки (dist)
* @property {string} html - Путь к HTML шаблону (public/index.html)
* @property {string} src - Корневая директория исходного кода (src)
*/
export interface BuildPaths {
entry: string
build: string
html: string
src: string
}
/**
* Опции конфигурации сборки webpack
* @interface BuildOptions
* @property {BuildMode} mode - Режим сборки (development/production)
* @property {BuildPaths} paths - Пути для конфигурации
* @property {boolean} isDev - Флаг режима разработки
* @property {number} port - Порт для dev-сервера
* @property {boolean} open - Автоматически открывать браузер при запуске
* @property {string} apiUrl - URL API для глобальной переменной __API__
* @property {'frontend' | 'storybook' | 'jest'} project - Тип проекта для глобальной переменной __PROJECT__
*/
export interface BuildOptions {
mode: BuildMode
paths: BuildPaths
isDev: boolean
port: number
open: boolean
apiUrl: string
project: 'frontend' | 'storybook' | 'jest'
}
/**
* Переменные окружения, передаваемые в webpack
* @interface BuildEnv
* @property {BuildMode} mode - Режим сборки
* @property {number} port - Порт для dev-сервера
* @property {string} apiUrl - URL API
*/
export interface BuildEnv {
mode: BuildMode
port: number
apiUrl: string
}