Webpack 的配置看似繁杂,但本质上只围绕五个核心概念展开。把这五个概念弄明白,就能读懂绝大多数 Webpack 配置文件,也能针对项目需求进行定制。
入口(Entry)
入口是 Webpack 构建依赖图的起点。 Webpack 从入口文件开始,递归找出所有直接或间接依赖的模块(JS、CSS、图片等),然后将它们打包成一个或多个输出文件。
在配置文件中,用 entry 字段声明入口:
// webpack.config.js
module.exports = {
// 单入口(最常见的 SPA 场景)
entry: './src/index.js',
// 多入口(多页面应用)
entry: {
home: './src/home.js',
about: './src/about.js',
}
};
实际选择:单页面应用通常一个入口就够;多页面应用(如后台管理系统)会为每个页面设置独立入口,Webpack 会分别构建,避免所有代码打包到一个巨大的文件中。在 Vue/React 项目中,入口文件通常就是挂载根组件的入口 JS。
输出(Output)
输出告诉 Webpack 打包好的文件放在哪里,以及如何命名。 经过 Loader 处理和 Plugin 加工后,最终生成的 bundle 会输出到这个目录。
配置通过 output 字段,必须是一个对象:
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
// 输出目录(绝对路径)
path: path.resolve(__dirname, 'dist'),
// 输出文件名
filename: 'bundle.js', // 单入口时常用
// 多入口时用占位符区分
filename: '[name].[contenthash:8].js',
// 公共路径(CDN 或子路径部署时使用)
publicPath: '/',
},
};
关键细节:
[name]会被替换为入口的键名(如home、about),[contenthash]根据文件内容生成哈希,文件内容变则哈希变,可有效利用浏览器缓存。publicPath决定了最终引用资源的 URL 前缀:部署到 CDN 时设置为 CDN 地址,放到子目录下时设置为子路径,确保 HTML 中的script和link标签指向正确位置。
Loader
Loader 让 Webpack 能够处理非 JavaScript 文件。 Webpack 本身只理解 JS 和 JSON 文件,对于 CSS、图片、TypeScript、JSX 等资源,必须通过 Loader 将它们转换为有效的模块,然后才能加入依赖图。
Loader 的配置写在 module.rules 中,每个规则包含 test(匹配文件类型)和 use(使用的 loader):
module.exports = {
module: {
rules: [
{
// 匹配 .css 结尾的文件
test: /\.css$/,
// 使用多个 loader,从右往左(从下往上)执行
use: ['style-loader', 'css-loader'],
},
{
test: /\.(png|jpg|gif|svg)$/,
// 文件资源:小于 8KB 的转成 base64,否则输出到 dist 目录
type: 'asset',
parser: { dataUrlCondition: { maxSize: 8 * 1024 } },
},
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: { presets: ['@babel/preset-env'] },
},
},
],
},
};
常用 Loader 一览:
css-loader:解析 CSS 中的@import和url(),使其能被模块化引用。style-loader:将 CSS 通过<style>标签注入 DOM(开发环境常用)。babel-loader:将 ES6+ 语法转译为 ES5,确保浏览器兼容。ts-loader/@babel/preset-typescript:处理 TypeScript。vue-loader/svelte-loader:解析.vue/.svelte单文件组件。file-loader/asset modules:处理字体、图片等静态资源。
一个实用建议:查看错误信息时,如果出现 “You may need an appropriate loader to handle this file type”,说明 Webpack 遇到了不认识的模块,去安装并配置对应的 loader 就行。
Plugin
Plugin 比 Loader 能力更强,可以介入 Webpack 构建流程的各个环节,完成打包优化、资源管理、环境变量注入等全局性任务。 Loader 只在解析模块时工作,Plugin 则像是一个个“钩子”,可以监听 Webpack 的生命周期事件,并执行自定义操作。
配置在 plugins 数组中,通常需要先 require 或 import 对应的插件:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
plugins: [
// 自动生成 HTML 并注入打包后的脚本
new HtmlWebpackPlugin({ template: './public/index.html' }),
// 每次构建前清理输出目录
new CleanWebpackPlugin(),
// 注入环境变量
new webpack.DefinePlugin({
'process.env.API_URL': JSON.stringify('https://api.example.com'),
}),
],
};
高频使用场景:
HtmlWebpackPlugin:自动生成 HTML 入口文件,并自动引入打包后的 JS/CSS(多页面时需配合多入口实例化多个)。MiniCssExtractPlugin:将 CSS 提取为独立的.css文件(取代style-loader,用于生产环境)。CleanWebpackPlugin:每次构建清空dist目录,避免旧文件残留。DefinePlugin:定义编译期的全局常量,常用于区分环境。
Plugin 和 Loader 的分工记忆:遇到某类文件不会处理,找 Loader;需要完成更宏观的任务(生成 HTML、抽取 CSS、压缩代码、拷贝静态资源),找 Plugin。
模式(Mode)
模式是 Webpack 内置的预设,根据开发或生产场景一键启用对应的优化策略。 通过设置 mode 参数,可以快速让 Webpack 在不同环境下表现不同。
可选值:'development'、'production' 或 'none'(默认)。
module.exports = {
mode: 'development', // 或 'production'
};
两种模式的区别:
| | development | production |
|--------------------|--------------------------------------|----------------------------------------|
| 目标 | 构建速度快,调试体验好 | 构建结果体积小,运行效率高 |
| 模块名 | 使用相对路径,便于定位源码 | 缩短为数字 ID,减少输出体积 |
| Source Map | 默认生成高质量的 eval-source-map | 默认不生成(可手动开启) |
| 代码压缩 | 不压缩 | 使用 TerserPlugin 自动压缩 JS 和 CSS |
| Tree Shaking | 不启用 | 自动移除未引用代码 |
实际开发中,我们通常不会只用 mode 就走天下,因为不同环境往往还需要其他差异配置(如 API 地址)。最佳实践是拆分配置:webpack.common.js 存放公共配置,webpack.dev.js 和 webpack.prod.js 分别继承并扩展,然后用 webpack-merge 工具组合。这样既清晰,又能精细化控制。
小结:构建工具的配置看起来庞大,但只要抓住入口(从哪开始)、输出(到哪去)、Loader(怎么处理各种文件)、Plugin(构建过程中做什么)、模式(什么场景用什么优化)这五个概念,剩下就是查文档、按需求组合。这也是前端工程化中必须跨越的一道门槛,跨过去以后,你会发现 Webpack 不过是一部精确运作的打包机器。