17. Реальная конфигурация
Финальный урок курса — полный production-ready webpack.config.js для React + TypeScript приложения со всеми необходимыми оптимизациями. Это конфиг, который используется в реальных enterprise-проектах.
Полный webpack.config.js
Заголовок раздела «Полный webpack.config.js»const path = require('path');const webpack = require('webpack');const HtmlWebpackPlugin = require('html-webpack-plugin');const MiniCssExtractPlugin = require('mini-css-extract-plugin');const TerserPlugin = require('terser-webpack-plugin');const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');const CopyPlugin = require('copy-webpack-plugin');const ForkTsCheckerPlugin = require('fork-ts-checker-webpack-plugin');const ReactRefreshPlugin = require('@pmmmwh/react-refresh-webpack-plugin');const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const isDev = process.env.NODE_ENV === 'development';const isProd = !isDev;const isAnalyze = process.env.ANALYZE === 'true';
module.exports = { // ─────────────────────────── Core ─────────────────────────── mode: isDev ? 'development' : 'production', target: 'browserslist', bail: isProd, // Остановить сборку при первой ошибке в production
// ─────────────────────────── Entry ────────────────────────── entry: { main: './src/index.tsx', },
// ─────────────────────────── Output ───────────────────────── output: { path: path.resolve(__dirname, 'dist'), filename: isProd ? '[name].[contenthash:8].js' : '[name].js', chunkFilename: isProd ? '[id].[contenthash:8].js' : '[id].js', assetModuleFilename: 'assets/[hash:8][ext]', publicPath: '/', clean: true, },
// ─────────────────────────── Resolve ──────────────────────── resolve: { extensions: ['.tsx', '.ts', '.js', '.jsx'], alias: { '@': path.resolve(__dirname, 'src'), '@api': path.resolve(__dirname, 'src/api'), '@components': path.resolve(__dirname, 'src/components'), '@hooks': path.resolve(__dirname, 'src/hooks'), '@utils': path.resolve(__dirname, 'src/utils'), }, modules: ['node_modules'], symlinks: false, },
// ─────────────────────────── Loaders ──────────────────────── module: { rules: [ // JS/TS + JSX/TSX { test: /\\.([jt]sx?)$/, use: { loader: 'babel-loader', options: { presets: [ ['@babel/preset-env', { targets: 'defaults', useBuiltIns: 'usage', corejs: 3 }], ['@babel/preset-react', { runtime: 'automatic' }], '@babel/preset-typescript', ], plugins: [isDev && 'react-refresh/babel'].filter(Boolean), cacheDirectory: true, // Кеш Babel }, }, exclude: /node_modules/, },
// Global CSS { test: /\\.css$/, exclude: /\\.module\\.css$/, use: [ isDev ? 'style-loader' : MiniCssExtractPlugin.loader, { loader: 'css-loader', options: { importLoaders: 1, sourceMap: isDev } }, { loader: 'postcss-loader', options: { postcssOptions: { plugins: ['autoprefixer'] } } }, ], },
// CSS Modules { test: /\\.module\\.css$/, use: [ isDev ? 'style-loader' : MiniCssExtractPlugin.loader, { loader: 'css-loader', options: { importLoaders: 1, modules: { localIdentName: isDev ? '[name]__[local]' : '[hash:base64:8]' }, }, }, ], },
// SCSS { test: /\\.s[ac]ss$/, use: [ isDev ? 'style-loader' : MiniCssExtractPlugin.loader, { loader: 'css-loader', options: { importLoaders: 3 } }, 'postcss-loader', 'sass-loader', ], },
// Images { test: /\\.(png|jpg|jpeg|gif|webp|avif)$/i, type: 'asset', parser: { dataUrlCondition: { maxSize: 8192 } }, generator: { filename: 'images/[hash:8][ext]' }, },
// SVG { test: /\\.svg$/, type: 'asset/resource', generator: { filename: 'icons/[hash:8][ext]' } },
// Fonts { test: /\\.(woff|woff2|eot|ttf|otf)$/i, type: 'asset/resource', generator: { filename: 'fonts/[name][ext]' }, }, ], },
// ─────────────────────────── Plugins ──────────────────────── plugins: [ new HtmlWebpackPlugin({ template: './public/index.html', minify: isProd }),
new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV), 'process.env.APP_VERSION': JSON.stringify(process.env.npm_package_version), }),
isProd && new MiniCssExtractPlugin({ filename: '[name].[contenthash:8].css' }), isDev && new ReactRefreshPlugin(),
new ForkTsCheckerPlugin({ async: isDev }),
isProd && new CopyPlugin({ patterns: [{ from: 'public', filter: (f) => !f.endsWith('.html') }] }),
isAnalyze && new BundleAnalyzerPlugin({ analyzerMode: 'static', openAnalyzer: false }), ].filter(Boolean),
// ─────────────────────────── Optimization ─────────────────── optimization: { minimize: isProd, minimizer: [ new TerserPlugin({ parallel: true, terserOptions: { compress: { drop_console: isProd }, format: { comments: false } }, extractComments: false, }), new CssMinimizerPlugin(), ], splitChunks: { chunks: 'all', cacheGroups: { react: { test: /[\\/]node_modules[\\/](react|react-dom|react-router)[\\/]/, name: 'react-vendor', priority: 30, chunks: 'all' }, vendors: { test: /[\\/]node_modules[\\/]/, name: 'vendors', priority: 20, chunks: 'all' }, common: { name: 'common', minChunks: 2, priority: 10, reuseExistingChunk: true }, }, }, runtimeChunk: 'single', moduleIds: 'deterministic', },
// ─────────────────────────── Dev Server ───────────────────── devServer: isDev ? { port: 3000, hot: true, historyApiFallback: true, compress: true, proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } }, } : undefined,
// ─────────────────────────── Cache ────────────────────────── cache: { type: 'filesystem', buildDependencies: { config: [__filename] }, },
// ─────────────────────────── Performance ──────────────────── performance: isProd ? { hints: 'warning', maxEntrypointSize: 300000, // 300 KB maxAssetSize: 300000, } : false,
// ─────────────────────────── DevTool ──────────────────────── devtool: isDev ? 'eval-cheap-module-source-map' : 'source-map',
// ─────────────────────────── Stats ────────────────────────── stats: isDev ? 'errors-warnings' : 'normal',};Структура dist/ после сборки
Заголовок раздела «Структура dist/ после сборки»dist/├── index.html├── runtime.abc12345.js (2 KB) ← Webpack runtime├── main.def67890.js (85 KB) ← Ваш код├── react-vendor.ghi23456.js (95 KB) ← React + React-DOM├── vendors.jkl78901.js (68 KB) ← node_modules├── common.mno23456.js (24 KB) ← Общий код├── main.pqr78901.css (18 KB) ← CSS├── assets/│ ├── logo.abc12345.png│ └── hero.def67890.webp├── fonts/│ └── Inter-Regular.woff2└── icons/ └── icon-check.ghi23456.svgНиже — интерактивный Webpack Stats Dashboard — финальный playground курса. Полная аналитика сборки: размеры чанков, граф зависимостей, метрики производительности.