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:
30
config/build/buildDevServer.ts
Normal file
30
config/build/buildDevServer.ts
Normal 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,
|
||||
}
|
||||
}
|
||||
37
config/build/buildLoaders.ts
Normal file
37
config/build/buildLoaders.ts
Normal 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]
|
||||
}
|
||||
72
config/build/buildPlugins.ts
Normal file
72
config/build/buildPlugins.ts
Normal 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
|
||||
}
|
||||
36
config/build/buildResolvers.ts
Normal file
36
config/build/buildResolvers.ts
Normal 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: {},
|
||||
}
|
||||
}
|
||||
60
config/build/buildWebpackConfig.ts
Normal file
60
config/build/buildWebpackConfig.ts
Normal 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,
|
||||
}
|
||||
}
|
||||
30
config/build/loaders/buildBabelLoader.ts
Normal file
30
config/build/loaders/buildBabelLoader.ts
Normal 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
|
||||
}
|
||||
43
config/build/loaders/buildCssLoader.ts
Normal file
43
config/build/loaders/buildCssLoader.ts
Normal 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
|
||||
}
|
||||
27
config/build/loaders/buildFileLoader.ts
Normal file
27
config/build/loaders/buildFileLoader.ts
Normal 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
|
||||
}
|
||||
24
config/build/loaders/buildSvgrLoader.ts
Normal file
24
config/build/loaders/buildSvgrLoader.ts
Normal 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
|
||||
}
|
||||
23
config/build/loaders/buildTypescriptLoader.ts
Normal file
23
config/build/loaders/buildTypescriptLoader.ts
Normal 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
|
||||
}
|
||||
54
config/build/types/config.ts
Normal file
54
config/build/types/config.ts
Normal 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
|
||||
}
|
||||
57
webpack.config.ts
Normal file
57
webpack.config.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Главный файл конфигурации webpack
|
||||
*
|
||||
* Точка входа для webpack, которая принимает переменные окружения
|
||||
* и создает финальную конфигурацию сборки.
|
||||
*
|
||||
* Переменные окружения (передаются через CLI):
|
||||
* - mode: режим сборки ('development' | 'production')
|
||||
* - port: порт для dev-сервера (по умолчанию 3000)
|
||||
* - apiUrl: URL API (по умолчанию 'http://localhost:8000')
|
||||
*
|
||||
* @example
|
||||
* // Запуск с параметрами по умолчанию:
|
||||
* pnpm dev
|
||||
*
|
||||
* // Запуск на другом порту:
|
||||
* webpack serve --env port=8080
|
||||
*
|
||||
* // Production сборка:
|
||||
* pnpm build
|
||||
*
|
||||
* @see {@link buildWebpackConfig} для деталей конфигурации
|
||||
*/
|
||||
|
||||
import * as path from 'path'
|
||||
import webpack from 'webpack'
|
||||
|
||||
import { buildWebpackConfig } from './config/build/buildWebpackConfig'
|
||||
import { BuildEnv } from './config/build/types/config'
|
||||
|
||||
export default (env: BuildEnv) => {
|
||||
const paths = {
|
||||
entry: path.resolve(__dirname, 'src', 'index.tsx'),
|
||||
html: path.resolve(__dirname, 'public', 'index.html'),
|
||||
build: path.resolve(__dirname, 'dist'),
|
||||
src: path.resolve(__dirname, 'src'),
|
||||
}
|
||||
|
||||
const mode = env.mode || 'development'
|
||||
const isDev = mode === 'development'
|
||||
const PORT = env.port || 3000
|
||||
const apiUrl = env.apiUrl || 'http://localhost:8000'
|
||||
const open = true
|
||||
const project = 'frontend'
|
||||
|
||||
const config: webpack.Configuration = buildWebpackConfig({
|
||||
mode,
|
||||
paths,
|
||||
isDev,
|
||||
port: PORT,
|
||||
open,
|
||||
apiUrl,
|
||||
project,
|
||||
})
|
||||
|
||||
return config
|
||||
}
|
||||
Reference in New Issue
Block a user