Перейти к содержимому

14. React-проект на Webpack

Настройка React приложения с TypeScript и Webpack с нуля — важный навык. В этом уроке мы построим полный production-ready конфиг шаг за шагом, включая Hot Reloading, оптимизации и все необходимые инструменты.

react-webpack-app/
├── public/
│ └── index.html
├── src/
│ ├── index.tsx ← Entry point
│ ├── App.tsx
│ ├── components/
│ ├── hooks/
│ ├── styles/
│ │ └── global.css
│ └── types/
│ └── declarations.d.ts
├── webpack/
│ ├── webpack.common.js ← Общая конфигурация
│ ├── webpack.dev.js ← Development
│ └── webpack.prod.js ← Production
├── .babelrc
├── tsconfig.json
└── package.json
Окно терминала
# Runtime зависимости
npm install react react-dom
# TypeScript
npm install --save-dev typescript @types/react @types/react-dom
# Webpack
npm install --save-dev webpack webpack-cli webpack-dev-server webpack-merge
# Babel (рекомендуем для React)
npm install --save-dev babel-loader @babel/core @babel/preset-env \
@babel/preset-react @babel/preset-typescript
# Hot Reloading
npm install --save-dev @pmmmwh/react-refresh-webpack-plugin react-refresh
# HTML
npm install --save-dev html-webpack-plugin
# CSS
npm install --save-dev css-loader style-loader mini-css-extract-plugin \
css-minimizer-webpack-plugin
# TypeScript проверка
npm install --save-dev fork-ts-checker-webpack-plugin
# Минификация
npm install --save-dev terser-webpack-plugin
# Копирование ресурсов
npm install --save-dev copy-webpack-plugin
{
"presets": [
["@babel/preset-env", {
"targets": { "browsers": ["> 1%", "last 2 versions"] },
"useBuiltIns": "usage",
"corejs": 3
}],
["@babel/preset-react", {
"runtime": "automatic"
}],
"@babel/preset-typescript"
],
"plugins": []
}
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"jsx": "react-jsx",
"baseUrl": ".",
"paths": { "@/*": ["src/*"] },
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"skipLibCheck": true,
"noEmit": true
},
"include": ["src"]
}
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ForkTsCheckerPlugin = require('fork-ts-checker-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
module.exports = {
entry: './src/index.tsx',
resolve: {
extensions: ['.tsx', '.ts', '.js'],
alias: { '@': path.resolve(__dirname, '../src') },
},
module: {
rules: [{
test: /\\.tsx?$/,
use: { loader: 'babel-loader' },
exclude: /node_modules/,
}],
},
plugins: [
new HtmlWebpackPlugin({ template: './public/index.html' }),
new ForkTsCheckerPlugin({ async: true }),
new CopyPlugin({ patterns: [{ from: 'public/robots.txt' }] }),
],
output: {
path: path.resolve(__dirname, '../dist'),
assetModuleFilename: 'assets/[hash:8][ext]',
clean: true,
},
};
const { merge } = require('webpack-merge');
const ReactRefreshPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const common = require('./webpack.common');
module.exports = merge(common, {
mode: 'development',
devtool: 'eval-cheap-module-source-map',
devServer: {
port: 3000,
hot: true,
historyApiFallback: true,
proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } },
},
module: {
rules: [{
test: /\\.css$/,
use: ['style-loader', 'css-loader'],
}],
},
plugins: [new ReactRefreshPlugin()],
});
const { merge } = require('webpack-merge');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const common = require('./webpack.common');
module.exports = merge(common, {
mode: 'production',
devtool: 'source-map',
output: {
filename: '[name].[contenthash:8].js',
chunkFilename: '[id].[contenthash:8].js',
publicPath: '/',
},
module: {
rules: [{
test: /\\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
}],
},
plugins: [
new MiniCssExtractPlugin({ filename: '[name].[contenthash:8].css' }),
],
optimization: {
minimize: true,
minimizer: [new TerserPlugin({ terserOptions: { compress: { drop_console: true } } }), new CssMinimizerPlugin()],
splitChunks: { chunks: 'all' },
runtimeChunk: 'single',
},
});

Ниже — интерактивный scaffold генератор React проекта. Выберите опции и получите готовую структуру файлов.