开发环境
package.json
{
"name": "react-cli",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "npm run dev",
"dev": "cross-env NODE_ENV=development webpack serve --config ./config/webpack.dev.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"browserslist": [
"last 2 version",
"> 1%",
"not dead"
],
"devDependencies": {
"@babel/core": "^7.20.2",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.10",
"babel-loader": "^9.1.0",
"babel-preset-react-app": "^10.0.1",
"cross-env": "^7.0.3",
"css-loader": "^6.7.2",
"eslint-config-react-app": "^7.0.1",
"eslint-webpack-plugin": "^3.2.0",
"html-webpack-plugin": "^5.5.0",
"less-loader": "^11.1.0",
"postcss-loader": "^7.0.1",
"postcss-preset-env": "^7.8.3",
"react-app": "^1.1.2",
"react-refresh": "^0.14.0",
"sass": "^1.56.1",
"sass-loader": "^13.2.0",
"style-loader": "^3.3.1",
"stylus-loader": "^7.1.0",
"webpack": "^5.75.0",
"webpack-cli": "^5.0.0",
"webpack-dev-server": "^4.11.1"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.4.3"
}
}
.eslintrc.js
module.exports = {
extends: ["react-app"], // 继承react官方规则
// 解析选项
parserOptions: {
babelOptions: {
presets: [
// 解决页面报错问题
["babel-preset-react-app", false],
"babel-preset-react-app/prod"
]
}
},
// 具体检查规则
rules: {},
// 其它规则详见: http://eslint.bootcss.com/docs/user-guide/configuring
}
babel.config.js
module.exports = {
// 预设
presets: [
// https://github.com/facebook/create-react-app
// babel-preset-react-app
["react-app"]
]
}
config/webpack.dev.js
const path = require('path');
const ESLintPlugin = require('eslint-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin'); // react提供的js HMR插件
// 返回处理样式loader的函数
const getStyleLoaders = (pre) => {
return [
"style-loader",
"css-loader",
{
// 处理浏览器兼容性问题
// 需要配合package.json中的browserslist来指定兼容性处理到什么程度
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins:['postcss-preset-env']
}
}
},
pre
].filter(Boolean);
}
module.exports = {
entry: './src/main.js',
output: {
path: undefined,
filename: 'static/js/[name].js',
chunkFilename: 'static/js/[name].chunk.js',
assetModuleFilename: 'static/media/[hash:10][ext][query]',
},
module: {
rules: [
// 处理css
{
test: /\.css$/i,
use: getStyleLoaders()
},
{
test: /\.less$/i,
use: getStyleLoaders('less-loader')
},
{
test: /\.s[ac]ss$/i,
use: getStyleLoaders('sass-loader')
},
{
test: /\.styl$/i,
use: getStyleLoaders('stylus-loader')
},
// 处理图片
{
test: /.(png|jpe?g|gif|webp|svg)$/,
type: "asset",
parser: {
dataUrlCondition: {
// 小于10kb的图片会转base64
maxSize: 10 * 1024 // 10kb
}
},
},
// 处理其他资源
{
test: /.(ttf|woff2?|mp3|mp4|avi)$/,
type: "asset/resource"
},
// 处理js
// 配置babel
{
test: /\.jsx?$/,
include: path.resolve(__dirname, '../src'), // 只处理src
loader: 'babel-loader',
options: {
cacheDirectory: true, // 开启babel缓存
cacheCompression: false, // 关闭缓存文件压缩
plugins: ['react-refresh/babel'], // 激活js的HMR
}
}
]
},
plugins: [
new ESLintPlugin({
context: path.resolve(__dirname, '../src'),
exclude: ['node_modules'],
cache: true, // 开启eslint缓存
cacheLocation: path.resolve(__dirname, '../node_modules/.cache/eslintcache'), // eslint缓存目录
}),
// 处理html
new HtmlWebpackPlugin({
template: path.resolve(__dirname, '../public/index.html')
}),
new ReactRefreshWebpackPlugin(), // 激活js的HMR
],
// 模式
mode: 'development',
// SourceMap
devtool: 'cheap-module-source-map',
optimization: {
// 代码分割配置
splitChunks: {
chunks: "all",
// 其它的都用默认值即可
},
// runtime文件来保存文件的hash值
runtimeChunk: {
name: entrypoint => `runtime-${entrypoint.name}.js`
}
},
// webpack解析模块加载选项
resolve: {
extensions: ['.jsx', '.js', '.json']
},
devServer: {
host: 'localhost', // 启动服务器的域名
port: 4000, // 启动服务器端口号
open: true,
hot: true, // 默认开启
historyApiFallback: true, // 解决前端路由刷新404问题
},
}
src/main.ts
import React from 'react'
import ReactDOM from 'react-dom/client'
import { BrowserRouter } from 'react-router-dom'
import App from './App'
const root = ReactDOM.createRoot(document.getElementById("app"));
root.render(
<BrowserRouter>
<App />
</BrowserRouter>
);
src/App.jsx
import React, { Suspense, lazy } from 'react'
import { Link, Routes, Route } from 'react-router-dom'
// import Home from './pages/Home'
// import About from './pages/About'
// 路由懒加载
const Home = lazy(() => import(/* webpackChunkName: 'home' */ './pages/Home'));
const About = lazy(() => import(/* webpackChunkName: 'about' */ './pages/About'));
function App() {
return (
<div>
<h1>app</h1>
<ul>
<li><Link to="/home">home</Link></li>
<li><Link to="/about">about</Link></li>
</ul>
<Suspense fallback={<div>loading...</div>}>
<Routes>
<Route path="/home" element={<Home/>}></Route>
<Route path="/about" element={<About/>}></Route>
</Routes>
</Suspense>
</div>
)
}
export default App;
生产环境配置
package.json
{
"name": "react-cli",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "npm run dev",
"dev": "cross-env NODE_ENV=development webpack serve --config ./config/webpack.dev.js",
"build": "cross-env NODE_ENV=production webpack --config ./config/webpack.prod.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"browserslist": [
"last 2 version",
"> 1%",
"not dead"
],
"devDependencies": {
"@babel/core": "^7.20.2",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.10",
"babel-loader": "^9.1.0",
"babel-preset-react-app": "^10.0.1",
"copy-webpack-plugin": "^11.0.0",
"cross-env": "^7.0.3",
"css-loader": "^6.7.2",
"css-minimizer-webpack-plugin": "^4.2.2",
"eslint-config-react-app": "^7.0.1",
"eslint-webpack-plugin": "^3.2.0",
"html-webpack-plugin": "^5.5.0",
"image-minimizer-webpack-plugin": "^3.8.1",
"imagemin-gifsicle": "^7.0.0",
"imagemin-jpegtran": "^7.0.0",
"imagemin-optipng": "^8.0.0",
"imagemin-svgo": "^10.0.1",
"less-loader": "^11.1.0",
"mini-css-extract-plugin": "^2.7.0",
"postcss-loader": "^7.0.1",
"postcss-preset-env": "^7.8.3",
"react-app": "^1.1.2",
"react-refresh": "^0.14.0",
"sass": "^1.56.1",
"sass-loader": "^13.2.0",
"style-loader": "^3.3.1",
"stylus-loader": "^7.1.0",
"webpack": "^5.75.0",
"webpack-cli": "^5.0.0",
"webpack-dev-server": "^4.11.1"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.4.3"
}
}
config/webpack.prod.js
const path = require('path');
const ESLintPlugin = require('eslint-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
// const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin'); // react提供的js HMR插件
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); // 提取css为单独文件
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); // css压缩
const TerserWebpackPlugin = require('terser-webpack-plugin'); // 内置(压缩js)
const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin"); // 图片压缩
const CopyPlugin = require("copy-webpack-plugin"); // 复制插件
// 返回处理样式loader的函数
const getStyleLoaders = (pre) => {
return [
MiniCssExtractPlugin.loader, // 提取css为单独文件
"css-loader",
{
// 处理浏览器兼容性问题
// 需要配合package.json中的browserslist来指定兼容性处理到什么程度
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins:['postcss-preset-env']
}
}
},
pre
].filter(Boolean);
}
module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, '../dist'),
filename: 'static/js/[name].[contenthash:10].js',
chunkFilename: 'static/js/[name].[contenthash:10].chunk.js',
assetModuleFilename: 'static/media/[hash:10][ext][query]',
clean: true,
},
module: {
rules: [
// 处理css
{
test: /\.css$/i,
use: getStyleLoaders()
},
{
test: /\.less$/i,
use: getStyleLoaders('less-loader')
},
{
test: /\.s[ac]ss$/i,
use: getStyleLoaders('sass-loader')
},
{
test: /\.styl$/i,
use: getStyleLoaders('stylus-loader')
},
// 处理图片
{
test: /.(png|jpe?g|gif|webp|svg)$/,
type: "asset",
parser: {
dataUrlCondition: {
// 小于10kb的图片会转base64
maxSize: 10 * 1024 // 10kb
}
},
},
// 处理其他资源
{
test: /.(ttf|woff2?|mp3|mp4|avi)$/,
type: "asset/resource"
},
// 处理js
// 配置babel
{
test: /\.jsx?$/,
include: path.resolve(__dirname, '../src'), // 只处理src
loader: 'babel-loader',
options: {
cacheDirectory: true, // 开启babel缓存
cacheCompression: false, // 关闭缓存文件压缩
// plugins: ['react-refresh/babel'], // 激活js的HMR 生产模式没HMR功能
}
}
]
},
plugins: [
new ESLintPlugin({
context: path.resolve(__dirname, '../src'),
exclude: ['node_modules'],
cache: true, // 开启eslint缓存
cacheLocation: path.resolve(__dirname, '../node_modules/.cache/eslintcache'), // eslint缓存目录
}),
// 处理html
new HtmlWebpackPlugin({
template: path.resolve(__dirname, '../public/index.html')
}),
// new ReactRefreshWebpackPlugin(), // 激活js的HMR 生产环境无HMR功能
new MiniCssExtractPlugin({ // 提取css为单独文件
filename: 'static/css/[name].[contenthash:10].css',
chunkFilename: 'static/css/[name].[contenthash:10].chunk.css',
}),
new CopyPlugin({
patterns: [
{ // 把public下的文件复制到dist目录
from: path.resolve(__dirname, '../public'),
to: path.resolve(__dirname, '../dist'),
globOptions: {
ignore: ["**/index.html"], // 忽略public中的index.html
},
},
],
}),
],
// 模式
mode: 'production',
// SourceMap
devtool: 'source-map',
optimization: {
// 代码分割配置
splitChunks: {
chunks: "all",
// 其它的都用默认值即可
},
// runtime文件来保存文件的hash值
runtimeChunk: {
name: entrypoint => `runtime-${entrypoint.name}.js`
},
minimizer: [
new CssMinimizerPlugin(), // css压缩
new TerserWebpackPlugin(), // 压缩js
// 压缩图片(也可以放到plugin配置中)
new ImageMinimizerPlugin({
minimizer: {
implementation: ImageMinimizerPlugin.imageminGenerate,
options: {
plugins: [
["gifsicle", { interlaced: true }],
["jpegtran", { progressive: true }],
["optipng", { optimizationLevel: 5 }],
[
"svgo",
{
plugins: [
"preset-default",
"prefixIds",
{
name: "sortAttrs",
params: {
xmlnsOrder: "alphabetical"
}
}
]
}
]
]
}
}
}),
]
},
// webpack解析模块加载选项
resolve: {
extensions: ['.jsx', '.js', '.json']
},
}
合并开发配置和生产配置
package.json
{
"name": "react-cli",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "npm run dev",
"dev": "cross-env NODE_ENV=development webpack serve --config ./config/webpack.config.js",
"build": "cross-env NODE_ENV=production webpack --config ./config/webpack.config.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"browserslist": [
"last 2 version",
"> 1%",
"not dead"
],
"devDependencies": {
"@babel/core": "^7.20.2",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.10",
"babel-loader": "^9.1.0",
"babel-preset-react-app": "^10.0.1",
"copy-webpack-plugin": "^11.0.0",
"cross-env": "^7.0.3",
"css-loader": "^6.7.2",
"css-minimizer-webpack-plugin": "^4.2.2",
"eslint-config-react-app": "^7.0.1",
"eslint-webpack-plugin": "^3.2.0",
"html-webpack-plugin": "^5.5.0",
"image-minimizer-webpack-plugin": "^3.8.1",
"imagemin-gifsicle": "^7.0.0",
"imagemin-jpegtran": "^7.0.0",
"imagemin-optipng": "^8.0.0",
"imagemin-svgo": "^10.0.1",
"less-loader": "^11.1.0",
"mini-css-extract-plugin": "^2.7.0",
"postcss-loader": "^7.0.1",
"postcss-preset-env": "^7.8.3",
"react-app": "^1.1.2",
"react-refresh": "^0.14.0",
"sass": "^1.56.1",
"sass-loader": "^13.2.0",
"style-loader": "^3.3.1",
"stylus-loader": "^7.1.0",
"webpack": "^5.75.0",
"webpack-cli": "^5.0.0",
"webpack-dev-server": "^4.11.1"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.4.3"
}
}
config/webpack.config.js
const path = require('path');
const ESLintPlugin = require('eslint-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin'); // react提供的js HMR插件
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); // 提取css为单独文件
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); // css压缩
const TerserWebpackPlugin = require('terser-webpack-plugin'); // 内置(压缩js)
const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin"); // 图片压缩
const CopyPlugin = require("copy-webpack-plugin"); // 复制插件
// 获取cross-env定义的环境变量
const isProduction = process.env.NODE_ENV === 'production';
// 返回处理样式loader的函数
const getStyleLoaders = (pre) => {
return [
isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
"css-loader",
{
// 处理浏览器兼容性问题
// 需要配合package.json中的browserslist来指定兼容性处理到什么程度
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins:['postcss-preset-env']
}
}
},
pre
].filter(Boolean);
}
module.exports = {
entry: './src/main.js',
output: {
path: isProduction ? path.resolve(__dirname, '../dist') : undefined,
filename: isProduction ? 'static/js/[name].[contenthash:10].js' : 'static/js/[name].js',
chunkFilename: isProduction ? 'static/js/[name].[contenthash:10].chunk.js' : 'static/js/[name].chunk.js',
assetModuleFilename: 'static/media/[hash:10][ext][query]',
clean: true,
},
module: {
rules: [
// 处理css
{
test: /\.css$/i,
use: getStyleLoaders()
},
{
test: /\.less$/i,
use: getStyleLoaders('less-loader')
},
{
test: /\.s[ac]ss$/i,
use: getStyleLoaders('sass-loader')
},
{
test: /\.styl$/i,
use: getStyleLoaders('stylus-loader')
},
// 处理图片
{
test: /.(png|jpe?g|gif|webp|svg)$/,
type: "asset",
parser: {
dataUrlCondition: {
// 小于10kb的图片会转base64
maxSize: 10 * 1024 // 10kb
}
},
},
// 处理其他资源
{
test: /.(ttf|woff2?|mp3|mp4|avi)$/,
type: "asset/resource"
},
// 处理js
// 配置babel
{
test: /\.jsx?$/,
include: path.resolve(__dirname, '../src'), // 只处理src
loader: 'babel-loader',
options: {
cacheDirectory: true, // 开启babel缓存
cacheCompression: false, // 关闭缓存文件压缩
plugins: [ !isProduction && 'react-refresh/babel'].filter(Boolean), // 激活js的HMR 生产模式没HMR功能
}
}
]
},
plugins: [
new ESLintPlugin({
context: path.resolve(__dirname, '../src'),
exclude: ['node_modules'],
cache: true, // 开启eslint缓存
cacheLocation: path.resolve(__dirname, '../node_modules/.cache/eslintcache'), // eslint缓存目录
}),
// 处理html
new HtmlWebpackPlugin({
template: path.resolve(__dirname, '../public/index.html')
}),
!isProduction && new ReactRefreshWebpackPlugin(), // 激活js的HMR 生产环境无HMR功能
isProduction && new MiniCssExtractPlugin({ // 提取css为单独文件
filename: 'static/css/[name].[contenthash:10].css',
chunkFilename: 'static/css/[name].[contenthash:10].chunk.css',
}),
isProduction && new CopyPlugin({
patterns: [
{ // 把public下的文件复制到dist目录
from: path.resolve(__dirname, '../public'),
to: path.resolve(__dirname, '../dist'),
globOptions: {
ignore: ["**/index.html"], // 忽略public中的index.html
},
},
],
}),
].filter(Boolean),
// 模式
mode: isProduction ? 'production' : 'development',
// SourceMap
devtool: isProduction ? 'source-map' : 'cheap-module-source-map',
optimization: {
// 代码分割配置
splitChunks: {
chunks: "all",
// 其它的都用默认值即可
},
// runtime文件来保存文件的hash值
runtimeChunk: {
name: entrypoint => `runtime-${entrypoint.name}.js`
},
minimize: isProduction, // 是否需要压缩(生产环境下开启)
minimizer: [
new CssMinimizerPlugin(), // css压缩
new TerserWebpackPlugin(), // 压缩js
// 压缩图片(也可以放到plugin配置中)
new ImageMinimizerPlugin({
minimizer: {
implementation: ImageMinimizerPlugin.imageminGenerate,
options: {
plugins: [
["gifsicle", { interlaced: true }],
["jpegtran", { progressive: true }],
["optipng", { optimizationLevel: 5 }],
[
"svgo",
{
plugins: [
"preset-default",
"prefixIds",
{
name: "sortAttrs",
params: {
xmlnsOrder: "alphabetical"
}
}
]
}
]
]
}
}
}),
]
},
// webpack解析模块加载选项
resolve: {
extensions: ['.jsx', '.js', '.json']
},
devServer: {
host: 'localhost', // 启动服务器的域名
port: 4000, // 启动服务器端口号
open: true,
hot: true, // 默认开启
historyApiFallback: true, // 解决前端路由刷新404问题
},
}
优化配置
1、引入antd配置antd的自定义主题色
antd的样式是用less写的,要改antd中的某一个颜色变量
自定义antd样式:4x.ant.design/docs/react/…
main.js引入andt样式
import 'antd/dist/antd.less'
2、将react、andt、node_modules单独打包
package.json
{
"name": "react-cli",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "npm run dev",
"dev": "cross-env NODE_ENV=development webpack serve --config ./config/webpack.config.js",
"build": "cross-env NODE_ENV=production webpack --config ./config/webpack.config.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"browserslist": [
"last 2 version",
"> 1%",
"not dead"
],
"devDependencies": {
"@babel/core": "^7.20.2",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.10",
"babel-loader": "^9.1.0",
"babel-preset-react-app": "^10.0.1",
"copy-webpack-plugin": "^11.0.0",
"cross-env": "^7.0.3",
"css-loader": "^6.7.2",
"css-minimizer-webpack-plugin": "^4.2.2",
"eslint-config-react-app": "^7.0.1",
"eslint-webpack-plugin": "^3.2.0",
"html-webpack-plugin": "^5.5.0",
"image-minimizer-webpack-plugin": "^3.8.1",
"imagemin-gifsicle": "^7.0.0",
"imagemin-jpegtran": "^7.0.0",
"imagemin-optipng": "^8.0.0",
"imagemin-svgo": "^10.0.1",
"less-loader": "^11.1.0",
"mini-css-extract-plugin": "^2.7.0",
"postcss-loader": "^7.0.1",
"postcss-preset-env": "^7.8.3",
"react-app": "^1.1.2",
"react-refresh": "^0.14.0",
"sass": "^1.56.1",
"sass-loader": "^13.2.0",
"style-loader": "^3.3.1",
"stylus-loader": "^7.1.0",
"webpack": "^5.75.0",
"webpack-cli": "^5.0.0",
"webpack-dev-server": "^4.11.1"
},
"dependencies": {
"antd": "^4.24.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.4.3"
}
}
webpack.config.js
const path = require('path');
const ESLintPlugin = require('eslint-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin'); // react提供的js HMR插件
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); // 提取css为单独文件
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); // css压缩
const TerserWebpackPlugin = require('terser-webpack-plugin'); // 内置(压缩js)
const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin"); // 图片压缩
const CopyPlugin = require("copy-webpack-plugin"); // 复制插件
// 获取cross-env定义的环境变量
const isProduction = process.env.NODE_ENV === 'production';
// 返回处理样式loader的函数
const getStyleLoaders = (pre) => {
return [
isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
"css-loader",
{
// 处理浏览器兼容性问题
// 需要配合package.json中的browserslist来指定兼容性处理到什么程度
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins:['postcss-preset-env']
}
}
},
pre && {
loader: pre,
options: pre === 'less-loader' ? {
// antd自定义主体配置
lessOptions: {
modifyVars: { '@primary-color': '#1DA57A' },
javascriptEnabled: true,
},
} : {}
}
].filter(Boolean);
}
module.exports = {
entry: './src/main.js',
output: {
path: isProduction ? path.resolve(__dirname, '../dist') : undefined,
filename: isProduction ? 'static/js/[name].[contenthash:10].js' : 'static/js/[name].js',
chunkFilename: isProduction ? 'static/js/[name].[contenthash:10].chunk.js' : 'static/js/[name].chunk.js',
assetModuleFilename: 'static/media/[hash:10][ext][query]',
clean: true,
},
module: {
rules: [
// 处理css
{
test: /\.css$/i,
use: getStyleLoaders()
},
{
test: /\.less$/i,
use: getStyleLoaders('less-loader')
},
{
test: /\.s[ac]ss$/i,
use: getStyleLoaders('sass-loader')
},
{
test: /\.styl$/i,
use: getStyleLoaders('stylus-loader')
},
// 处理图片
{
test: /.(png|jpe?g|gif|webp|svg)$/,
type: "asset",
parser: {
dataUrlCondition: {
// 小于10kb的图片会转base64
maxSize: 10 * 1024 // 10kb
}
},
},
// 处理其他资源
{
test: /.(ttf|woff2?|mp3|mp4|avi)$/,
type: "asset/resource"
},
// 处理js
// 配置babel
{
test: /\.jsx?$/,
include: path.resolve(__dirname, '../src'), // 只处理src
loader: 'babel-loader',
options: {
cacheDirectory: true, // 开启babel缓存
cacheCompression: false, // 关闭缓存文件压缩
plugins: [ !isProduction && 'react-refresh/babel'].filter(Boolean), // 激活js的HMR 生产模式没HMR功能
}
}
]
},
plugins: [
new ESLintPlugin({
context: path.resolve(__dirname, '../src'),
exclude: ['node_modules'],
cache: true, // 开启eslint缓存
cacheLocation: path.resolve(__dirname, '../node_modules/.cache/eslintcache'), // eslint缓存目录
}),
// 处理html
new HtmlWebpackPlugin({
template: path.resolve(__dirname, '../public/index.html')
}),
!isProduction && new ReactRefreshWebpackPlugin(), // 激活js的HMR 生产环境无HMR功能
isProduction && new MiniCssExtractPlugin({ // 提取css为单独文件
filename: 'static/css/[name].[contenthash:10].css',
chunkFilename: 'static/css/[name].[contenthash:10].chunk.css',
}),
isProduction && new CopyPlugin({
patterns: [
{ // 把public下的文件复制到dist目录
from: path.resolve(__dirname, '../public'),
to: path.resolve(__dirname, '../dist'),
globOptions: {
ignore: ["**/index.html"], // 忽略public中的index.html
},
},
],
}),
].filter(Boolean),
// 模式
mode: isProduction ? 'production' : 'development',
// SourceMap
devtool: isProduction ? 'source-map' : 'cheap-module-source-map',
optimization: {
// 代码分割配置
splitChunks: {
chunks: "all",
// 其它的都用默认值即可
cacheGroups: {
// react react-dom react-router-dom 一起打包成一个js文件
react: {
test: /[\\/]node_modules[\\/]react(.*)?/,
name: 'chunk-react', // 包名
priority: 40, // 权重要比node_modules权重高,否则就打包到node_modules中了
},
// antd单独打包
antd: {
test: /[\\/]node_modules[\\/]antd[\\/]/,
name: 'chunk-antd', // 包名
priority: 30,
},
// 剩下node_modules单独打包
libs: {
test: /[\\/]node_modules[\\/]/,
name: 'chunk-libs', // 包名
priority: 20,
},
}
},
// runtime文件来保存文件的hash值
runtimeChunk: {
name: entrypoint => `runtime-${entrypoint.name}.js`
},
minimize: isProduction, // 是否需要压缩(生产环境下开启)
minimizer: [
new CssMinimizerPlugin(), // css压缩
new TerserWebpackPlugin(), // 压缩js
// 压缩图片(也可以放到plugin配置中)
// new ImageMinimizerPlugin({
// minimizer: {
// implementation: ImageMinimizerPlugin.imageminGenerate,
// options: {
// plugins: [
// ["gifsicle", { interlaced: true }],
// ["jpegtran", { progressive: true }],
// ["optipng", { optimizationLevel: 5 }],
// [
// "svgo",
// {
// plugins: [
// "preset-default",
// "prefixIds",
// {
// name: "sortAttrs",
// params: {
// xmlnsOrder: "alphabetical"
// }
// }
// ]
// }
// ]
// ]
// }
// }
// }),
]
},
// webpack解析模块加载选项
resolve: {
extensions: ['.jsx', '.js', '.json']
},
devServer: {
host: 'localhost', // 启动服务器的域名
port: 4000, // 启动服务器端口号
open: true,
hot: true, // 默认开启
historyApiFallback: true, // 解决前端路由刷新404问题
},
performance: false, // 关闭性能分析,提升打包速度
}