Hi,我是前端人类学(之前叫布兰妮甜)!
Webpack 是现代前端开发中不可或缺的模块打包工具,它的强大功能和灵活性使其成为构建复杂前端应用的首选。本文将深入探讨Webpack 5
的配置细节,带你从基础配置到高级优化,全面掌握 Webpack 5 的使用技巧。
文章目录
一、环境准备与核心概念
1.1. 安装
npm i -D webpack webpack-cli webpack-dev-server@latest
1.2 核心概念
- 入口(Entry):指定 webpack 从哪个模块开始构建依赖图
- 输出(Output):告诉 webpack 在哪里输出它创建的 bundle 文件
- 加载器(Loader):让 webpack 能够处理非 JavaScript 文件「翻译官」
- 插件(Plugins):执行范围更广的任务,从打包优化到资源管理「任务管家」
- 模式(Mode):可以设置为 development、production 或 none
二、基础配置
// webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'main.js',
clean: true // 5.20+ 自动清空 dist
},
mode: 'development'
};
这个配置告诉 webpack:
- 从 src/index.js 开始打包
- 输出到 dist/main.js
- 使用开发模式(不压缩代码,有 source map 等)
三、入口/出口(entry/output)深度解析
-
多入口
entry: { home: './src/home.js', about: './src/about.js', }
-
输出占位符
[name]
[contenthash:8]
[fullhash]
[id]
output: { filename: 'js/[name].[contenthash:8].js', assetModuleFilename: 'assets/[name].[hash][ext]', // 图片/字体统一路径 }
四、处理不同类型的资源
4.1 JS/TS
npm i -D babel-loader @babel/core @babel/preset-env core-js@3
{
test: /\.[jt]sx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
['@babel/preset-env', { useBuiltIns: 'usage', corejs: 3 }],
'@babel/preset-typescript',
['@babel/preset-react', { runtime: 'automatic' }],
],
},
},
},
4.2 CSS/LESS/Sass
npm i -D css-loader mini-css-extract-plugin postcss-loader autoprefixer cssnano
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
{
test: /\.s?css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: ['autoprefixer', ...(process.env.NODE_ENV === 'production' ? ['cssnano'] : [])],
},
},
},
'sass-loader',
],
},
plugins: [
new MiniCssExtractPlugin({ filename: 'css/[name].[contenthash:8].css' }),
],
这里我们使用了四个 loader:
css-loader
- 作用:解析 CSS 文件中的
@import
和url()
等引用 - 功能:处理 CSS 模块之间的依赖关系,将 CSS 转换为 JavaScript 模块
- 作用:解析 CSS 文件中的
postcss-loader
- 作用:通过 PostCSS 处理 CSS 代码
- 功能:
- 使用
autoprefixer
插件为 CSS 属性添加浏览器厂商前缀 - 在生产环境(
NODE_ENV === 'production'
)下使用cssnano
插件压缩和优化 CSS
- 使用
MiniCssExtractPlugin.loader
- 作用:将 CSS 从 JavaScript bundle 中提取到单独的 CSS 文件
- 功能:替代了
style-loader
,用于生产环境优化
sass-loader
- 作用:将 Sass/SCSS 文件编译为 CSS
- 功能:支持使用 Sass 语法编写样式文件
这四个 loader 共同构成了完整的 CSS 处理链,从 Sass 编译到 CSS 提取和优化。
4.3 图片/字体/资源
module.exports = {
// ...其他配置
module: {
rules: [
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/resource',
},
],
},
};
Webpack 5 引入了资源模块(asset modules),可以替代 file-loader 和 url-loader。
五、使用插件增强功能
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
// ...其他配置
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: 'My App',
template: './src/index.html'
}),
],
};
CleanWebpackPlugin
:在每次构建前清理输出目录HtmlWebpackPlugin
:自动生成 HTML 文件并注入打包后的资源
六、开发环境配置
为了提高开发体验,我们需要配置开发服务器和 source map:
module.exports = {
// ...其他配置
devtool: 'inline-source-map',
devServer: {
contentBase: './dist',
hot: true,
},
};
然后安装 webpack-dev-server:
npm install --save-dev webpack-dev-server
在 package.json 中添加脚本:
"scripts": {
"start": "webpack serve --open"
}
七、生产环境优化
const TerserPlugin = require('terser-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
module.exports = {
mode: 'production',
optimization: {
minimizer: [
new TerserPlugin(),
new CssMinimizerPlugin(),
],
splitChunks: {
chunks: 'all',
},
},
performance: {
hints: false,
maxEntrypointSize: 512000,
maxAssetSize: 512000
},
};
TerserPlugin
:压缩 JavaScriptCssMinimizerPlugin
:压缩 CSSsplitChunks
:代码分割,提取公共依赖
八、高级配置技巧
8.1 环境变量配置
我们可以区分开发和生产环境:
const webpack = require('webpack');
module.exports = (env) => {
return {
// ...其他配置
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(env.production ? 'production' : 'development')
}),
],
};
};
8.2 多页面应用配置
module.exports = {
entry: {
pageOne: './src/pageOne/index.js',
pageTwo: './src/pageTwo/index.js',
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
},
plugins: [
new HtmlWebpackPlugin({
template: './src/pageOne/index.html',
filename: 'pageOne.html',
chunks: ['pageOne']
}),
new HtmlWebpackPlugin({
template: './src/pageTwo/index.html',
filename: 'pageTwo.html',
chunks: ['pageTwo']
}),
],
};
8.3 自定义 loader 和插件
创建自定义 loader:
// my-loader.js
module.exports = function(source) {
return source.replace('World', 'Webpack');
};
创建自定义插件:
// my-plugin.js
class MyPlugin {
apply(compiler) {
compiler.hooks.done.tap('MyPlugin', (stats) => {
console.log('编译完成!');
});
}
}
module.exports = MyPlugin;
九、Webpack 5 新特性
-
持久化缓存:显著提高构建速度
module.exports = { cache: { type: 'filesystem', }, };
-
资源模块:内置处理资源文件的能力,不再需要 file-loader 等
-
模块联邦:实现微前端架构
// 作为远程模块 new ModuleFederationPlugin({ name: 'app1', filename: 'remoteEntry.js', exposes: { './Button': './src/Button', }, }); // 作为主机使用远程模块 new ModuleFederationPlugin({ name: 'app2', remotes: { app1: 'app1@http://localhost:3001/remoteEntry.js', }, });
-
Tree Shaking 改进:更好地消除未使用代码
-
长期缓存改进:通过确定的 chunk、模块 ID 和导出名称实现
十、性能优化
10.1 构建速度优化
module.exports = {
// ...其他配置
resolve: {
extensions: ['.js', '.jsx', '.json'],
alias: {
'@': path.resolve(__dirname, 'src/'),
},
modules: [path.resolve(__dirname, 'src'), 'node_modules'],
},
};
10.2 输出文件优化
module.exports = {
output: {
filename: '[name].[contenthash].js',
path: path.resolve(__dirname, 'dist'),
},
};
使用 contenthash
可以实现长期缓存,只有文件内容变化时 hash 才会改变。
10.3 代码分割
module.exports = {
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
},
},
},
runtimeChunk: 'single',
},
};
十一、常见问题解决方案
-
处理路径问题
module.exports = { resolve: { alias: { Assets: path.resolve(__dirname, 'src/assets/') } } };
-
处理 polyfill
Webpack 5 不再自动包含 Node.js 核心模块的 polyfill,需要手动添加:module.exports = { resolve: { fallback: { "crypto": require.resolve("crypto-browserify"), "stream": require.resolve("stream-browserify"), "assert": require.resolve("assert"), "http": require.resolve("stream-http"), "https": require.resolve("https-browserify"), "os": require.resolve("os-browserify"), "url": require.resolve("url"), "buffer": require.resolve("buffer"), } } };
-
处理大型项目构建慢的问题
- 使用
thread-loader
并行处理 - 使用
cache-loader
缓存 loader 结果 - 使用
DLLPlugin
预编译不常变化的模块
- 使用
十二、完整配置示例
最后,我们来看一个完整的 webpack 配置示例:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
module.exports = (env) => {
const isProduction = env.production;
return {
entry: './src/index.js',
output: {
filename: isProduction ? '[name].[contenthash].js' : '[name].js',
path: path.resolve(__dirname, 'dist'),
publicPath: '/',
},
mode: isProduction ? 'production' : 'development',
devtool: isProduction ? 'source-map' : 'eval-cheap-module-source-map',
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: 'babel-loader',
},
{
test: /\.css$/i,
use: [
isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
'css-loader',
'postcss-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',
generator: {
filename: 'fonts/[hash][ext][query]',
},
},
],
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: './src/index.html',
minify: isProduction ? {
collapseWhitespace: true,
removeComments: true,
} : false,
}),
isProduction && new MiniCssExtractPlugin({
filename: '[name].[contenthash].css',
}),
].filter(Boolean),
optimization: {
minimizer: [
new TerserPlugin(),
new CssMinimizerPlugin(),
],
splitChunks: {
chunks: 'all',
},
runtimeChunk: 'single',
},
devServer: {
contentBase: './dist',
hot: true,
historyApiFallback: true,
},
resolve: {
extensions: ['.js', '.jsx'],
alias: {
'@': path.resolve(__dirname, 'src/'),
},
},
performance: {
hints: isProduction ? 'warning' : false,
},
cache: {
type: 'filesystem',
},
};
};
Webpack 5 的配置不是「越复杂越好」,而是「按需组合」。先跑通最小配置,再逐步叠加功能,配合持久化缓存和合理拆分,可以把冷启动时间从分钟级降到秒级。祝构建愉快!