本篇承接 使用Webpack5搭建项目
开发模式:
配置webpack.dev.js
新建项目,生成package.json文件,创建config文件夹,创建webpack.dev.js文件
配置webpack.dev.js
const path = require("path")
const EslintWebpackPlugin = require("eslint-webpack-plugin")
//返回处理样式的loader函数
getStyleLoaders=function(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$/,
use: getStyleLoaders(),
},
{
test: /\.less$/,
use: getStyleLoaders('less-loader'),
},
{
test: /\.s[ac]ss$/,
use: getStyleLoaders('sass-loader'),
},
{
test: /\.styl$/,
use: getStyleLoaders('stylus-loader'),
},
//处理图片
{
test:/\.(jpe?g|png|gif|webp|svg)/,
type:"asset",
parser:{
dataCondition:{
maxSize:10*1024, //小于10kb以下可以转为base64,减少请求数量
}
}
},
// 处理其他资源
{
test:/\.(woff2?|ttf)/,
type:"asset/resource",
},
//处理js
]
},
plugins:[
new EslintWebpackPlugin({
context:path.resolve(__dirname,'../src'),
exclude:'node_modules',
cache:true,
cacheLocation:path.resolve(__dirname,'../node_modules/.cache/.eslintcache')
})
]
}
配置package.json,browserslist
{
"name": "webpack-react",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"browserslist":[
"last 2 version",
"> 1%",
"not dead"
]
}
创建并配置.eslintrc.js
module.exports={
extends:["react-app"], //继承官方react规则
parserOptions:{
babelOptions:{
presets:[
//解决页面报错的问题
["babel-preset-react-app",false],
"babel-preset-react-app/prod"
]
}
}
}
继续配置处理js文件
//处理js
{
test:/\.jsx?$/,
include:path.resolve(__dirname,'../src'),
loader:"babel-loader",
options:{
cacheDirectory:true,
cacheCompression:false
}
}
同时配置babel.config.js文件
module.exports={
presets:["react-app"] //内置了corejs,runtime插件,具体详情可以去github上查看。
}
添加HtmlWebpackPlugin,配置mode,以及devtool:
const path = require("path")
const EslintWebpackPlugin = require("eslint-webpack-plugin")
const HtmlWebpackPlugin = require("html-webpack-plugin")
//返回处理样式的loader函数
getStyleLoaders=function(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: {
...
plugins:[
...
new HtmlWebpackPlugin({
template:path.resolve(__dirname,"../public/index.html")
})
],
mode:"development",
devtool:"cheap-module-source-map"
}
配置代码分割:
optimization:{
splitChunks:{
chunks:"all" //代码分割
},
runtimeChunk:{
name:entrypoint=>`runtime~${entrypoint.name}.js` //单独储存引用的chunk的打包地址,main.js不会随着其他模块的变化导致地址变化而打包变化
}
}
配置devServer:
devServer:{
host:"localhost",
port:3000,
open:true,
hot:true
}
这就是目前的基本配置:
const path = require("path")
const EslintWebpackPlugin = require("eslint-webpack-plugin")
const HtmlWebpackPlugin = require("html-webpack-plugin")
//返回处理样式的loader函数
getStyleLoaders=function(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$/,
use: getStyleLoaders(),
},
{
test: /\.less$/,
use: getStyleLoaders('less-loader'),
},
{
test: /\.s[ac]ss$/,
use: getStyleLoaders('sass-loader'),
},
{
test: /\.styl$/,
use: getStyleLoaders('stylus-loader'),
},
//处理图片
{
test:/\.(jpe?g|png|gif|webp|svg)$/,
type:"asset",
parser:{
dataCondition:{
maxSize:10*1024, //小于10kb以下可以转为base64,减少请求数量
}
}
},
// 处理其他资源
{
test:/\.(woff2?|ttf)$/,
type:"asset/resource",
},
//处理js
{
test:/\.jsx?$/,
include:path.resolve(__dirname,'../src'),
loader:"babel-loader",
options:{
cacheDirectory:true,
cacheCompression:false
}
}
]
},
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")
})
],
mode:"development",
devtool:"cheap-module-source-map",
optimization:{
splitChunks:{
chunks:"all" //代码分割
},
runtimeChunk:{
name:entrypoint=>`runtime~${entrypoint.name}.js` //单独储存引用的chunk的打包地址,main.js不会随着其他模块的变化导致地址变化而打包变化
}
},
devServer:{
host:"localhost",
port:3000,
open:true,
hot:true
}
}
创建并配置main.js文件:
import React from 'react'
import ReactDom from "react-dom/client"
import App from "./App"
const root = ReactDom.createRoot(document.getElementById("app"))
root.render(<App/>)
创建并配置App.jsx
import React from "react";
function App(){
return <h1>App</h1>
}
export default App
创建并配置public/index.html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>React Cli</title>
</head>
<body>
<div id="app"></div>
</body>
</html>
开始下载依赖:
npm i eslint-webpack-plugin html-webpack-plugin style-loader css-loader postcss-loader postcss-preset-env less-loader sass-loader sass stylus-loader -D
npm i babel-loader @babel/core babel-preset-react-app eslint-config-react-app -D
npm i webpack-dev-server webpack webpack-cli -D
npm i react react-dom
下载完成后,配置package.jason
"scripts": {
"start":"npm run dev",
"dev":"webpack serve --config ./config/webpack.dev.js"
},
输入指令:npm start ,页面报错了:
这里需要babel-preset-app要求我们制定一个NODE_ENV或者BABEL_ENV的环境变量,我们下载cross-env的库设置环境变量:
npm install --save-dev cross-env
修改package.json:
"scripts": {
"start": "npm run dev",
"dev": "cross-env NODE_ENV=development webpack serve --config ./config/webpack.dev.js"
},
输入npm start ,继续报错:
在引入的时候我们没有这里是对js文件有自动补全的功能,但这里是jsx文件,所以继续配置webpack.dev.js
optimization:{
splitChunks:{
chunks:"all" //代码分割
},
runtimeChunk:{
name:entrypoint=>`runtime~${entrypoint.name}.js` //单独储存引用的chunk的打包地址,main.js不会随着其他模块的变化导致地址变化而打包变化
}
},
//webpack解析块加载选项
resolve:{
//自动补全文件拓展名
extensions:[".jsx",".js",".json"]
},
再次编译就没有问题了。
检测HMR热更新,样式文件是可以触发,但是js文件依旧不行,所以引用插件,react-refresh-webpack-plugin
npm install -D @pmmmwh/react-refresh-webpack-plugin react-refresh
配置webpack.dev.js
const path = require("path")
const EslintWebpackPlugin = require("eslint-webpack-plugin")
const HtmlWebpackPlugin = require("html-webpack-plugin")
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
...
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: [
...
//处理js
{
test:/\.jsx?$/,
include:path.resolve(__dirname,'../src'),
loader:"babel-loader",
options:{
cacheDirectory:true,
cacheCompression:false,
plugins:["react-refresh/babel"]//激活js文件HMR功能
}
}
]
},
plugins:[
...
new ReactRefreshWebpackPlugin()
],
...
}
接下来是路由设置:App.jsx
import React from "react";
import Home from "../src/pages/Home/Home"
import {Link, Routes,Route} from "react-router-dom"
import About from './pages/About/About'
function App() {
return (<div>
<h1>App</h1>
<ul>
<li><Link to="/home">Home</Link></li>
<li><Link to="/about">About</Link></li>
</ul>
<Routes>
<Route path="/home" element={<Home/>}/>
<Route path="/about" element={<About/>}/>
</Routes>
</div>)
}
export default App
import React from 'react'
export default function About() {
return (
<div>About</div>
)
}
import React from 'react'
import "./Home.less"
export default function Home() {
return (
<div className='home'>Home</div>
)
}
页面重新启动即可,但是刷新页面会有404的问题,解决方案:historyApiFallback,配置webapck.dev.js
devServer:{
host:"localhost",
port:3000,
open:true,
hot:true,
historyApiFallback:true//解决前端路由刷新404的问题
}
希望路由单独打包,需要配置路由懒加载:
import React, { Suspense, lazy } from "react";
// import Home from "../src/pages/Home/Home"
import { Link, Routes, Route } from "react-router-dom"
// import About from './pages/About/About'
const Home = lazy(() => import("./pages/Home/Home.jsx"))
const About = lazy(() => import("./pages/About/About.jsx"))
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 path="/about" element={<About />} />
</Routes>
</Suspense>
</div>)
}
export default App
同时可以给指定魔法命名,可以打包成你想要的名称:
const Home = lazy(() => import(/* webpackChunkName:'home' */"./pages/Home/Home.jsx"))
const About = lazy(() => import(/* webpackChunkName:'about' */"./pages/About/About.jsx"))
关于favicon.ico的配置,将文件放入public文件夹下面,然后配置index.html,link引入即可:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
<title>React Cli</title>
</head>
<body>
<div id="app"></div>
</body>
</html>
生产模式:
我们直接复制一份dev的,修改名称为webpack.prod.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
},
处理css,单独打包文件并压缩css
...
const MiniCssExtractPlugin= require("mini-css-extract-plugin")
const CssMinimizerWebpackPlugin= require("css-minimizer-webpack-plugin")
//返回处理样式的loader函数
let getStyleLoaders=function(pre){
return[
MiniCssExtractPlugin.loader, "css-loader", {
//处理兼容性问题,配合package.json中的browserslist来指定兼容性做到什么程度
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: ["postcss-preset-env"]
}
}
},
pre
].filter(Boolean)
}
module.exports = {
...
module: {
rules: [
...
//处理js
{
test:/\.jsx?$/,
include:path.resolve(__dirname,'../src'),
loader:"babel-loader",
options:{
cacheDirectory:true,
cacheCompression:false,
plugins:["react-refresh/babel"]//激活js文件HMR功能
}
}
]
},
plugins:[
...
new MiniCssExtractPlugin({
filename:'static/css/[name].[contenthash:10].css',
chunkFilename:'static/css/[name].[contenthash:10].chunk.css'
})
],
mode:"development",
devtool:"cheap-module-source-map",
optimization:{
...
minimizer:[
new CssMinimizerWebpackPlugin()
]
},
...
}
处理压缩js
const TerserWebpackPlugin= require("terser-webpack-plugin")
...
optimization:{
splitChunks:{
chunks:"all" //代码分割
},
runtimeChunk:{
name:entrypoint=>`runtime~${entrypoint.name}.js` //单独储存引用的chunk的打包地址,main.js不会随着其他模块的变化导致地址变化而打包变化
},
minimizer:[
new CssMinimizerWebpackPlugin(),
new TerserWebpackPlugin()
]
},
修改mode为production,devtool改为:source-map,删除devServer,删除HMR功能,
const path = require("path")
const EslintWebpackPlugin = require("eslint-webpack-plugin")
const HtmlWebpackPlugin = require("html-webpack-plugin")
const MiniCssExtractPlugin= require("mini-css-extract-plugin")
const CssMinimizerWebpackPlugin= require("css-minimizer-webpack-plugin")
const TerserWebpackPlugin= require("terser-webpack-plugin")
//返回处理样式的loader函数
let getStyleLoaders=function(pre){
return[
MiniCssExtractPlugin.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: 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$/,
use: getStyleLoaders(),
},
{
test: /\.less$/,
use: getStyleLoaders('less-loader'),
},
{
test: /\.s[ac]ss$/,
use: getStyleLoaders('sass-loader'),
},
{
test: /\.styl$/,
use: getStyleLoaders('stylus-loader'),
},
//处理图片
{
test:/\.(jpe?g|png|gif|webp|svg)$/,
type:"asset",
parser:{
dataCondition:{
maxSize:10*1024, //小于10kb以下可以转为base64,减少请求数量
}
}
},
// 处理其他资源
{
test:/\.(woff2?|ttf)$/,
type:"asset/resource",
},
//处理js
{
test:/\.jsx?$/,
include:path.resolve(__dirname,'../src'),
loader:"babel-loader",
options:{
cacheDirectory:true,
cacheCompression:false,
}
}
]
},
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"),
}),
new MiniCssExtractPlugin({
filename:'static/css/[name].[contenthash:10].css',
chunkFilename:'static/css/[name].[contenthash:10].chunk.css'
})
],
mode:"production",
devtool:"cheap-module-source-map",
optimization:{
splitChunks:{
chunks:"all" //代码分割
},
runtimeChunk:{
name:entrypoint=>`runtime~${entrypoint.name}.js` //单独储存引用的chunk的打包地址,main.js不会随着其他模块的变化导致地址变化而打包变化
},
minimizer:[
new CssMinimizerWebpackPlugin(),
new TerserWebpackPlugin()
]
},
//webpack解析块加载选项
resolve:{
//自动补全文件拓展名
extensions:[".jsx",".js",".json"]
},
}
压缩图片:
const ImageMinimizerWebpackPlugin = require("image-minimizer-webpack-plugin")
minimizer: [
new CssMinimizerWebpackPlugin(),
new TerserWebpackPlugin(),
new ImageMinimizerWebpackPlugin({
minimizer: {
implementation: ImageMinimizerWebpackPlugin.imageminGenerate,
options: {
plugins: [
["gifsicle", { interlaced: true }],
["jpegtran", { progressive: true }],
["optipng", { optimizationLevel: 5 }],
[
"svgo",
{
plugins: [
"preset-default",
"prefixIds",
{
name: "sortAttrs",
params: {
xmlnsOrder: "alphabetical",
},
},
],
},
],
],
},
},
}),
]
下载依赖:
npm i mini-css-extract-plugin css-minimizer-webpack-plugin -D
npm install image-minimizer-webpack-plugin imagemin --save-dev
npm install imagemin-gifsicle imagemin-jpegtran imagemin-optipng imagemin-svgo --save-dev
修改package.json打包启动指令:
"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 serve --config ./config/webpack.prod.js"
},
开始打包npm run build即可。但是发现favicon没有被打包到dist下,使用插件copy-webpack-plugin
npm i copy-webpack-plugin --save-dev
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"),
}),
new MiniCssExtractPlugin({
filename: 'static/css/[name].[contenthash:10].css',
chunkFilename: 'static/css/[name].[contenthash:10].chunk.css'
}),
new CopyWebpackPlugin({//复制到dist文件下
patterns: [
{
from: path.resolve(__dirname, "../public"), to: "../dist", globOptions: {
ignore: ["**/index.html", "**/ignored-directory/**"],//忽略Index.html文件
},
}
]
})
],
重新打包后即可。
配置好了生产和开发,由于有很多地方是重复代码那么我们现在做一下整合,目前文件代码如下:
webpack.dev.js
const path = require("path")
const EslintWebpackPlugin = require("eslint-webpack-plugin")
const HtmlWebpackPlugin = require("html-webpack-plugin")
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
//返回处理样式的loader函数
let getStyleLoaders=function(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$/,
use: getStyleLoaders(),
},
{
test: /\.less$/,
use: getStyleLoaders('less-loader'),
},
{
test: /\.s[ac]ss$/,
use: getStyleLoaders('sass-loader'),
},
{
test: /\.styl$/,
use: getStyleLoaders('stylus-loader'),
},
//处理图片
{
test:/\.(jpe?g|png|gif|webp|svg)$/,
type:"asset",
parser:{
dataCondition:{
maxSize:10*1024, //小于10kb以下可以转为base64,减少请求数量
}
}
},
// 处理其他资源
{
test:/\.(woff2?|ttf)$/,
type:"asset/resource",
},
//处理js
{
test:/\.jsx?$/,
include:path.resolve(__dirname,'../src'),
loader:"babel-loader",
options:{
cacheDirectory:true,
cacheCompression:false,
plugins:["react-refresh/babel"]//激活js文件HMR功能
}
}
]
},
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"),
}),
new ReactRefreshWebpackPlugin()
],
mode:"development",
devtool:"cheap-module-source-map",
optimization:{
splitChunks:{
chunks:"all" //代码分割
},
runtimeChunk:{
name:entrypoint=>`runtime~${entrypoint.name}.js` //单独储存引用的chunk的打包地址,main.js不会随着其他模块的变化导致地址变化而打包变化
}
},
//webpack解析块加载选项
resolve:{
//自动补全文件拓展名
extensions:[".jsx",".js",".json"]
},
devServer:{
host:"localhost",
port:3000,
open:true,
hot:true,
historyApiFallback:true//解决前端路由刷新404的问题
}
}
webpack.prod.js
const path = require("path")
const EslintWebpackPlugin = require("eslint-webpack-plugin")
const HtmlWebpackPlugin = require("html-webpack-plugin")
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const CssMinimizerWebpackPlugin = require("css-minimizer-webpack-plugin")
const TerserWebpackPlugin = require("terser-webpack-plugin")
const ImageMinimizerWebpackPlugin = require("image-minimizer-webpack-plugin")
const CopyWebpackPlugin = require("copy-webpack-plugin")
//返回处理样式的loader函数
let getStyleLoaders = function (pre) {
return [
MiniCssExtractPlugin.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: 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$/,
use: getStyleLoaders(),
},
{
test: /\.less$/,
use: getStyleLoaders('less-loader'),
},
{
test: /\.s[ac]ss$/,
use: getStyleLoaders('sass-loader'),
},
{
test: /\.styl$/,
use: getStyleLoaders('stylus-loader'),
},
//处理图片
{
test: /\.(jpe?g|png|gif|webp|svg)$/,
type: "asset",
parser: {
dataCondition: {
maxSize: 10 * 1024, //小于10kb以下可以转为base64,减少请求数量
}
}
},
// 处理其他资源
{
test: /\.(woff2?|ttf)$/,
type: "asset/resource",
},
//处理js
{
test: /\.jsx?$/,
include: path.resolve(__dirname, '../src'),
loader: "babel-loader",
options: {
cacheDirectory: true,
cacheCompression: false,
}
}
]
},
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"),
}),
new MiniCssExtractPlugin({
filename: 'static/css/[name].[contenthash:10].css',
chunkFilename: 'static/css/[name].[contenthash:10].chunk.css'
}),
new CopyWebpackPlugin({//复制到dist文件下
patterns: [
{
from: path.resolve(__dirname, "../public"), to: "../dist", globOptions: {
ignore: ["**/index.html", "**/ignored-directory/**"],//忽略Index.html文件
},
}
]
})
],
mode: "production",
devtool: "cheap-module-source-map",
optimization: {
splitChunks: {
chunks: "all" //代码分割
},
runtimeChunk: {
name: entrypoint => `runtime~${entrypoint.name}.js` //单独储存引用的chunk的打包地址,main.js不会随着其他模块的变化导致地址变化而打包变化
},
minimizer: [
new CssMinimizerWebpackPlugin(),
new TerserWebpackPlugin(),
new ImageMinimizerWebpackPlugin({
minimizer: {
implementation: ImageMinimizerWebpackPlugin.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"]
}
}
进行复用,合并为一个文件,新建文件webpack.config.js
const path = require("path")
const EslintWebpackPlugin = require("eslint-webpack-plugin")
const HtmlWebpackPlugin = require("html-webpack-plugin")
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const CssMinimizerWebpackPlugin = require("css-minimizer-webpack-plugin")
const TerserWebpackPlugin = require("terser-webpack-plugin")
const ImageMinimizerWebpackPlugin = require("image-minimizer-webpack-plugin")
const CopyWebpackPlugin = require("copy-webpack-plugin")
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
//获取cross-env定义的环境变量
const isProduction = process.env.NODE_ENV==="production"
//返回处理样式的loader函数
let getStyleLoaders = function (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$/,
use: getStyleLoaders(),
},
{
test: /\.less$/,
use: getStyleLoaders('less-loader'),
},
{
test: /\.s[ac]ss$/,
use: getStyleLoaders('sass-loader'),
},
{
test: /\.styl$/,
use: getStyleLoaders('stylus-loader'),
},
//处理图片
{
test: /\.(jpe?g|png|gif|webp|svg)$/,
type: "asset",
parser: {
dataCondition: {
maxSize: 10 * 1024, //小于10kb以下可以转为base64,减少请求数量
}
}
},
// 处理其他资源
{
test: /\.(woff2?|ttf)$/,
type: "asset/resource",
},
//处理js
{
test: /\.jsx?$/,
include: path.resolve(__dirname, '../src'),
loader: "babel-loader",
options: {
cacheDirectory: true,
cacheCompression: false,
plugins:[
!isProduction&&"react-refresh/babel"
].filter(Boolean)//激活js文件HMR功能
}
}
]
},
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"),
}),
isProduction && new MiniCssExtractPlugin({
filename: 'static/css/[name].[contenthash:10].css',
chunkFilename: 'static/css/[name].[contenthash:10].chunk.css'
}),
isProduction && new CopyWebpackPlugin({//复制到dist文件下
patterns: [
{
from: path.resolve(__dirname, "../public"), to: "../dist", globOptions: {
ignore: ["**/index.html", "**/ignored-directory/**"],//忽略Index.html文件
},
}
]
}),
!isProduction && new ReactRefreshWebpackPlugin()
].filter(Boolean),
mode: isProduction?"production":"development",
devtool: isProduction?'source-map':"cheap-module-source-map",
optimization: {
splitChunks: {
chunks: "all" //代码分割
},
runtimeChunk: {
name: entrypoint => `runtime~${entrypoint.name}.js` //单独储存引用的chunk的打包地址,main.js不会随着其他模块的变化导致地址变化而打包变化
},
//是否要进行压缩
minimizer:isProduction,
minimizer: [
new CssMinimizerWebpackPlugin(),
new TerserWebpackPlugin(),
new ImageMinimizerWebpackPlugin({
minimizer: {
implementation: ImageMinimizerWebpackPlugin.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:3000,
open:true,
hot:true,
historyApiFallback:true//解决前端路由刷新404的问题
}
}
在引入第三方库之后,打包文件会越来越大,加载速度会慢,页面加载性能不好,我们配置一下代码分割时单独打包:
optimization: {
splitChunks: {
chunks: "all", //代码分割
cacheGroups:{
react:{ //react react-dom react-router-dom 一起打包成一个js文件
test:/[\\/]node_modules[\\/]react(.*)?[\\/]/,
name:'chunk-react',
priority:40, //打包优先级权重
},
// antd:{ //antd单独打包
// test:/[\\/]node_modules[\\/]antd[\\/]/,
// name:'chunk-antd',
// priority:30,
// },
lib:{ //node_modules单独打包
test:/[\\/]node_modules[\\/]/,
name:'chunk-lib',
priority:20,
},
}
},
}
之后引入第三方库可以自行配置打包,根据实际情况来判断是否需要单独打包,考虑体积是否过大,请求数量是否过多。如果遇上警告说打包体积太大,我们也不想看,就添加performance属性为false,就不会在做性能分析并报警告,可以提升打包速度。
devServer:{
host:"localhost",
port:3000,
open:true,
hot:true,
historyApiFallback:true//解决前端路由刷新404的问题
},
performance:false //关闭性能分析,提高打包速度
开启webpack内部缓存,有助于下次的打包编译节省时间:
cache: { //可开启webpack5内置缓存
type: 'filesystem',
allowCollectingMemory: true
}
最终webpack.config.js的配置如下:
const path = require("path")
const EslintWebpackPlugin = require("eslint-webpack-plugin")
const HtmlWebpackPlugin = require("html-webpack-plugin")
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const CssMinimizerWebpackPlugin = require("css-minimizer-webpack-plugin")
const TerserWebpackPlugin = require("terser-webpack-plugin")
const ImageMinimizerWebpackPlugin = require("image-minimizer-webpack-plugin")
const CopyWebpackPlugin = require("copy-webpack-plugin")
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
//获取cross-env定义的环境变量
const isProduction = process.env.NODE_ENV
//返回处理样式的loader函数
let getStyleLoaders = function (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$/,
use: getStyleLoaders(),
},
{
test: /\.less$/,
use: getStyleLoaders('less-loader'),
},
{
test: /\.s[ac]ss$/,
use: getStyleLoaders('sass-loader'),
},
{
test: /\.styl$/,
use: getStyleLoaders('stylus-loader'),
},
//处理图片
{
test: /\.(jpe?g|png|gif|webp|svg)$/,
type: "asset",
parser: {
dataCondition: {
maxSize: 10 * 1024, //小于10kb以下可以转为base64,减少请求数量
}
}
},
// 处理其他资源
{
test: /\.(woff2?|ttf)$/,
type: "asset/resource",
},
//处理js
{
test: /\.jsx?$/,
include: path.resolve(__dirname, '../src'),
loader: "babel-loader",
options: {
cacheDirectory: true,
cacheCompression: false,
plugins:[
!isProduction&&"react-refresh/babel"
].filter(Boolean)//激活js文件HMR功能
}
}
]
},
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"),
}),
isProduction && new MiniCssExtractPlugin({
filename: 'static/css/[name].[contenthash:10].css',
chunkFilename: 'static/css/[name].[contenthash:10].chunk.css'
}),
isProduction && new CopyWebpackPlugin({//复制到dist文件下
patterns: [
{
from: path.resolve(__dirname, "../public"), to: "../dist", globOptions: {
ignore: ["**/index.html", "**/ignored-directory/**"],//忽略Index.html文件
},
}
]
}),
!isProduction && new ReactRefreshWebpackPlugin()
].filter(Boolean),
mode: isProduction?"production":"development",
devtool: isProduction?'source-map':"cheap-module-source-map",
optimization: {
splitChunks: {
chunks: "all", //代码分割
cacheGroups:{
react:{ //react react-dom react-router-dom 一起打包成一个js文件
test:/[\\/]node_modules[\\/]react(.*)?[\\/]/,
name:'chunk-react',
priority:40, //打包优先级权重
},
// antd:{ //antd单独打包
// test:/[\\/]node_modules[\\/]antd[\\/]/,
// name:'chunk-antd',
// priority:30,
// },
lib:{ //node_modules单独打包
test:/[\\/]node_modules[\\/]/,
name:'chunk-lib',
priority:20,
},
}
},
runtimeChunk: {
name: entrypoint => `runtime~${entrypoint.name}.js` //单独储存引用的chunk的打包地址,main.js不会随着其他模块的变化导致地址变化而打包变化
},
//是否要进行压缩
minimizer:isProduction,
minimizer: [
new CssMinimizerWebpackPlugin(),
new TerserWebpackPlugin(),
new ImageMinimizerWebpackPlugin({
minimizer: {
implementation: ImageMinimizerWebpackPlugin.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:3000,
open:true,
hot:true,
historyApiFallback:true//解决前端路由刷新404的问题
},
performance:false, //关闭性能分析,提高打包速度。
cache: { //可开启webpack5内置缓存
type: 'filesystem',
allowCollectingMemory: true
}
}
基本就是这样,其余的配置在开发过程中可自行配置。