Webpack 是一个静态模块打包器,它将所有资源(JS、CSS、图片等)视为模块,通过依赖关系构建依赖图,最终打包成浏览器可识别的静态资源。
# 创建项目目录
mkdir webpack5-demo
cd webpack5-demo
# 初始化package.json
npm init -y
# 安装Webpack
npm install webpack webpack-cli --save-dev
webpack5-demo/
├── src/
│ ├── index.js # 入口文件
│ ├── styles/
│ │ └── main.css
│ └── assets/
│ └── images/
├── public/
│ └── index.html
├── dist/ # 打包输出目录
├── webpack.config.js # Webpack配置文件
└── package.json
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// 1. 入口配置
entry: {
main: './src/index.js',
vendor: './src/vendor.js' // 多入口示例
},
// 2. 输出配置
output: {
// 输出目录(绝对路径)
path: path.resolve(__dirname, 'dist'),
// 输出文件名,[name]对应入口的key,[contenthash]根据内容生成hash
filename: '[name].[contenthash].bundle.js',
// 清理dist目录
clean: true,
// 静态资源输出路径
assetModuleFilename: 'assets/[hash][ext][query]'
},
// 3. 模式配置
mode: 'development', // 'production' | 'development' | 'none'
// 4. 开发服务器配置
devServer: {
static: {
directory: path.join(__dirname, 'dist'),
},
// 热更新
hot: true,
// 开启gzip压缩
compress: true,
port: 8080,
open: true,
// 代理配置
proxy: {
'/api': {
target: 'http://localhost:3000',
pathRewrite: { '^/api': '' },
changeOrigin: true
}
}
},
// 5. 模块配置(Loader配置)
module: {
rules: [
// CSS处理
{
test: /\.css$/i,
use: [
'style-loader', // 将CSS插入到DOM
'css-loader' // 解析CSS文件
],
},
// SCSS/SASS处理
{
test: /\.s[ac]ss$/i,
use: [
'style-loader',
'css-loader',
'sass-loader'
],
},
// 图片资源处理
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
generator: {
filename: 'images/[hash][ext][query]'
}
},
// 字体文件处理
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/resource',
},
// Babel配置(JS/JSX转译)
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env',
'@babel/preset-react'
],
plugins: [
'@babel/plugin-transform-runtime'
]
}
}
},
// TypeScript处理
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
}
],
},
// 6. 插件配置
plugins: [
// 生成HTML文件
new HtmlWebpackPlugin({
title: 'Webpack5 Demo',
template: './public/index.html',
filename: 'index.html',
// 压缩HTML
minify: {
collapseWhitespace: true,
removeComments: true,
removeRedundantAttributes: true,
useShortDoctype: true
}
}),
// 复制静态文件(示例)
// new CopyWebpackPlugin({
// patterns: [
// { from: 'public/favicon.ico', to: 'favicon.ico' }
// ]
// })
],
// 7. 解析配置
resolve: {
// 自动解析扩展名
extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'],
// 路径别名
alias: {
'@': path.resolve(__dirname, 'src'),
'@components': path.resolve(__dirname, 'src/components'),
'@utils': path.resolve(__dirname, 'src/utils')
}
},
// 8. 优化配置
optimization: {
// 代码分割
splitChunks: {
chunks: 'all',
cacheGroups: {
// 第三方模块
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
},
// 公共模块
common: {
minChunks: 2,
name: 'common',
chunks: 'all',
priority: -10
}
}
},
// 最小化
minimizer: [
// 生产环境自动添加TerserPlugin(压缩JS)
`...`, // 继承默认的minimizer
],
},
// 9. 性能提示
performance: {
hints: 'warning', // 'error' | 'warning' | false
maxAssetSize: 200000, // 200kb
maxEntrypointSize: 400000, // 400kb
}
};
创建三个配置文件:
webpack.common.js - 公共配置webpack.dev.js - 开发环境配置webpack.prod.js - 生产环境配置const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].bundle.js',
},
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
}),
],
resolve: {
extensions: ['.js', '.jsx'],
alias: {
'@': path.resolve(__dirname, 'src'),
},
},
};
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'development',
devtool: 'eval-source-map', // 源码映射
devServer: {
static: './dist',
hot: true,
port: 8080,
open: true,
historyApiFallback: true, // 支持SPA路由
},
optimization: {
minimize: false, // 开发环境不压缩
},
// 开发环境性能提示关闭
performance: {
hints: false,
},
});
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
module.exports = merge(common, {
mode: 'production',
devtool: 'source-map', // 生产环境源码映射
module: {
rules: [
{
test: /\.css$/i,
use: [
MiniCssExtractPlugin.loader, // 提取CSS为单独文件
'css-loader',
],
},
],
},
plugins: [
// 提取CSS到单独文件
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css',
chunkFilename: '[id].[contenthash].css',
}),
],
optimization: {
minimizer: [
new TerserPlugin(), // 压缩JS
new CssMinimizerPlugin(), // 压缩CSS
],
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
},
},
},
runtimeChunk: 'single', // 运行时代码单独打包
},
performance: {
hints: 'warning',
maxEntrypointSize: 512000,
maxAssetSize: 512000,
},
});
{
"scripts": {
"start": "webpack serve --config webpack.dev.js",
"build": "webpack --config webpack.prod.js",
"build:analyze": "webpack --config webpack.prod.js --profile --json > stats.json",
"dev": "webpack serve --config webpack.dev.js",
"test": "echo \"Error: no test specified\" && exit 1"
}
}
| Loader | 作用 | 安装命令 |
|---|---|---|
| babel-loader | 转译ES6+代码 | npm install -D babel-loader @babel/core @babel/preset-env |
| css-loader | 解析CSS文件 | npm install -D css-loader |
| style-loader | 将CSS注入DOM | npm install -D style-loader |
| sass-loader | 编译Sass/SCSS | npm install -D sass-loader sass |
| less-loader | 编译Less | npm install -D less-loader less |
| postcss-loader | 处理CSS兼容性 | npm install -D postcss-loader postcss autoprefixer |
| file-loader | 处理文件资源 | npm install -D file-loader |
| url-loader | 小文件转base64 | npm install -D url-loader |
| ts-loader | 编译TypeScript | npm install -D ts-loader typescript |
| 插件 | 作用 | 安装命令 |
|---|---|---|
| HtmlWebpackPlugin | 生成HTML文件 | npm install -D html-webpack-plugin |
| MiniCssExtractPlugin | 提取CSS为单独文件 | npm install -D mini-css-extract-plugin |
| CleanWebpackPlugin | 清理输出目录 | npm install -D clean-webpack-plugin |
| CopyWebpackPlugin | 复制静态文件 | npm install -D copy-webpack-plugin |
| DefinePlugin | 定义环境变量 | Webpack内置 |
| ProvidePlugin | 自动加载模块 | Webpack内置 |
| BundleAnalyzerPlugin | 分析包大小 | npm install -D webpack-bundle-analyzer |
// webpack.config.js
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
'process.env.API_URL': JSON.stringify(process.env.API_URL),
}),
],
};
module.exports = {
cache: {
type: 'filesystem', // 使用文件系统缓存
cacheDirectory: path.resolve(__dirname, '.temp_cache'),
buildDependencies: {
config: [__filename], // 当配置文件改变时,使缓存失效
},
},
output: {
filename: '[name].[contenthash].js', // 内容hash
},
};
module.exports = {
externals: {
react: 'React',
'react-dom': 'ReactDOM',
lodash: '_',
jquery: 'jQuery',
},
};
使用多线程/多进程构建
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
optimization: {
minimizer: [
new TerserPlugin({
parallel: true, // 开启多线程
}),
],
},
};
合理配置splitChunks
optimization: {
splitChunks: {
chunks: 'all',
minSize: 20000, // 最小20kb
maxSize: 0,
minChunks: 1,
maxAsyncRequests: 30,
maxInitialRequests: 30,
automaticNameDelimiter: '~',
cacheGroups: {
defaultVendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10,
reuseExistingChunk: true,
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
},
},
},
}
配置source map
// 开发环境
devtool: 'cheap-module-source-map',
// 生产环境
devtool: 'source-map',
配置热更新
devServer: {
hot: true,
liveReload: false,
},
// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = (env, argv) => {
const isProduction = argv.mode === 'production';
return {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: isProduction
? '[name].[contenthash].js'
: '[name].bundle.js',
chunkFilename: isProduction
? '[name].[contenthash].chunk.js'
: '[name].chunk.js',
},
mode: isProduction ? 'production' : 'development',
devtool: isProduction ? 'source-map' : 'eval-source-map',
devServer: {
static: './dist',
hot: true,
port: 3000,
open: true,
historyApiFallback: true,
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: 'babel-loader',
},
{
test: /\.css$/,
use: [
isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
'css-loader',
'postcss-loader',
],
},
{
test: /\.(png|jpg|gif|svg)$/,
type: 'asset/resource',
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
}),
...(isProduction
? [new MiniCssExtractPlugin({
filename: '[name].[contenthash].css',
})]
: []
),
],
optimization: {
splitChunks: {
chunks: 'all',
},
},
};
};
Webpack 5 的配置虽然复杂,但理解其核心概念和配置项后,可以根据项目需求灵活配置。建议:
从简单配置开始,逐步添加功能 分离开发和生产环境,使用webpack-merge 合理使用缓存,提升构建速度 定期分析打包结果,优化打包体积 保持Webpack和相关依赖更新通过合理配置Webpack,可以显著提升开发效率和项目性能。