webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const EslintWebpackPlugin = require('eslint-webpack-plugin');
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerWebpackPlugin = require('css-minimizer-webpack-plugin');
const TerserWebpackPlugin = require('terser-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const isProduction = process.env.NODE_ENV === 'production';
const pubExcludeFiles = [
path.resolve(__dirname, '../node_modules/antd/dist'),
path.resolve(__dirname, '../src/style'),
];
const pubIncludeFiles = [
path.resolve(__dirname, '../node_modules/antd/dist'),
path.resolve(__dirname, '../src/style'),
];
const getStyleLoaders = (pre) =>
[
isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
{
loader: 'css-loader',
options: {
modules: {
localIdentName: '[path][name]-[local]',
},
},
},
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: ['postcss-preset-env'],
},
},
},
pre && {
loader: pre,
options:
pre !== 'less-loader'
? {
additionalData: '@import "./src/scss/cssVars.scss"; ',
sassOptions: {
includePaths: [path.resolve(__dirname, 'src/scss')],
},
}
: {},
},
].filter(Boolean);
module.exports = {
entry: {
main: [path.resolve(__dirname, '../src/main.js')],
},
target: 'web',
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: [
{
test: /\.css$/,
exclude: pubExcludeFiles,
use: getStyleLoaders(),
},
{
test: /\.less$/,
exclude: pubExcludeFiles,
use: getStyleLoaders('less-loader'),
},
{
test: /\.s[ac]ss$/,
exclude: pubExcludeFiles,
use: getStyleLoaders('sass-loader'),
},
{
test: /\.(css|less)$/,
include: pubIncludeFiles,
use: [
'style-loader',
'css-loader',
{
loader: 'less-loader',
options: {
lessOptions: {
javascriptEnabled: true,
},
},
},
],
},
{
test: /\.s[ac]ss$/,
include: pubIncludeFiles,
use: ['style-loader', 'css-loader', 'sass-loader'],
},
{
test: /\.(jpe?g|png|gif|webp|svg)$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 20 * 1024,
},
},
},
{
test: /\.(woff2?|ttf)$/,
type: 'asset/resource',
},
{
test: /\.jsx?$/,
include: path.resolve(__dirname, '../src'),
loader: 'babel-loader',
options: {
cacheDirectory: true,
cacheCompression: false,
plugins: [
!isProduction && 'react-refresh/babel',
].filter(Boolean),
},
},
],
},
plugins: [
new EslintWebpackPlugin({
context: path.resolve(__dirname, '../src'),
exclude: 'node_modules',
cache: true,
cacheLocation: path.resolve(__dirname, '../node_modules/.cache/.eslintcache'),
}),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, '../public/index.html'),
publicPath: isProduction ? '/YZQ/test/' : '/',
}),
isProduction &&
new MiniCssExtractPlugin({
filename: 'static/css/[name].[contenthash:10].css',
chunkFilename: 'static/css/[name].[contenthash:10].chunk.css',
}),
!isProduction && new ReactRefreshWebpackPlugin(),
new CopyPlugin({
patterns: [
{
from: path.resolve(__dirname, '../public'),
to: path.resolve(__dirname, '../dist/public'),
globOptions: {
ignore: ['**/index.html'],
},
},
],
}),
new NodePolyfillPlugin(),
].filter(Boolean),
mode: isProduction ? 'production' : 'development',
devtool: isProduction ? false : 'cheap-module-source-map',
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
react: {
test: /[\\/]node_modules[\\/]react(.*)?[\\/]/,
name: 'chunk-react',
priority: 100,
},
antd: {
test: /[\\/]node_modules[\\/]antd[\\/]/,
name: 'chunk-antd',
priority: 90,
},
echarts: {
test: /[\\/]node_modules[\\/]echarts(-*)?[\\/]/,
name: 'chunk-echarts',
priority: 80,
},
libs: {
test: /[\\/]node_modules[\\/]/,
name: 'chunk-libs',
priority: 10,
},
},
},
runtimeChunk: {
name: (entrypoint) => `runtime~${entrypoint.name}.js`,
},
minimize: isProduction,
minimizer: [new CssMinimizerWebpackPlugin(), new TerserWebpackPlugin()],
},
resolve: {
extensions: ['.jsx', '.js', '.json'],
alias: {
'@': path.resolve(__dirname, '../src'),
},
},
devServer: {
host: 'localhost',
port: 8001,
open: true,
hot: true,
historyApiFallback: true,
},
performance: false,
};
package.json
{
"name": "react-cli",
"version": "1.0.0",
"description": "个人项目框架",
"keywords": [],
"license": "ISC",
"author": "",
"main": "main.js",
"scripts": {
"bui": "cross-env NODE_ENV=production webpack --config ./config/webpack.config.js",
"buildapp:dev": "npm run bui",
"startapp:dev": "npm run dev",
"dev": "cross-env NODE_ENV=development webpack serve --config ./config/webpack.config.js",
"lint:eslint": "eslint --ext .js,.jsx,.ts,.tsx ",
"lint:fix": "eslint --fix --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src && npm run lint:style",
"lint:js": "eslint --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src",
"lint:prettier": "check-prettier lint",
"lint:style": "stylelint --fix \"src/**/*.less\" --syntax less",
"prettier": "prettier -c --write \"**/*\"",
"removeUnUseVars": "remove-unexpected-variable.rmjsvar"
},
"browserslist": [
"last 2 version",
"> 1%",
"not dead"
],
"dependencies": {
"@ant-design/icons": "^4.7.0",
"@antv/g6": "^4.3.11",
"@reduxjs/toolkit": "^1.8.5",
"amfe-flexible": "^2.2.1",
"animate.css": "^4.1.1",
"antd": "^4.20.3",
"axios": "^0.22.0",
"echarts": "^5.2.1",
"echarts-for-react": "^3.0.1",
"i18next": "^22.4.15",
"js-export-excel": "^1.1.4",
"moment": "^2.29.3",
"prop-types": "^15.8.1",
"qg-react-components": "^0.1.3",
"qs": "^6.10.1",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"react-i18next": "^12.2.2",
"react-redux": "^8.0.2",
"react-router-dom": "^6.3.0",
"react-router-redux": "^4.0.8",
"redux": "^4.2.0",
"redux-persist": "^6.0.0",
"terser-webpack-plugin": "^5.3.6",
"uuid": "^8.3.2"
},
"devDependencies": {
"@babel/core": "^7.19.1",
"@babel/eslint-parser": "^7.19.1",
"@babel/plugin-syntax-flow": "^7.14.5",
"@babel/plugin-transform-react-jsx": "^7.14.9",
"@babel/preset-env": "^7.19.1",
"@babel/preset-react": "^7.18.6",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.5",
"@trivago/prettier-plugin-sort-imports": "^3.3.0",
"@umijs/fabric": "^3.0.0",
"babel-eslint": "^10.1.0",
"babel-loader": "^8.2.5",
"babel-plugin-syntax-dynamic-import": "^6.18.0",
"babel-preset-react-app": "^10.0.1",
"browserslist": "^4.21.4",
"copy-webpack-plugin": "^11.0.0",
"cross-env": "^7.0.3",
"css-loader": "^6.7.1",
"css-minimizer-webpack-plugin": "^3.4.1",
"eslint": "^8.23.1",
"eslint-config-prettier": "^8.5.0",
"eslint-config-react-app": "^7.0.1",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.31.10",
"eslint-webpack-plugin": "^3.1.1",
"html-webpack-plugin": "^5.5.0",
"less": "^3.0.0",
"less-loader": "^8.0.0",
"mini-css-extract-plugin": "^2.6.0",
"node-polyfill-webpack-plugin": "^2.0.1",
"postcss": "^8.4",
"postcss-loader": "^6.2.1",
"postcss-modules-values": "^4.0.0",
"postcss-preset-env": "^7.5.0",
"postcss-scss": "^4.0.5",
"prettier": "^2.4.1",
"react-refresh": "^0.13.0",
"sass": "^1.51.0",
"sass-loader": "^12.6.0",
"style-loader": "^3.3.1",
"stylelint": "^14.3.0",
"stylelint-config-prettier": "^9.0.3",
"stylelint-config-standard": "^24.0.0",
"stylelint-order": "^5.0.0",
"stylus": "^0.59.0",
"stylus-loader": "^6.2.0",
"webpack": "^5.72.0",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.9.0"
}
}