结构化理解Webpack配置项
前言
在如今的前端环境下,Webpack已经成为每一位前端工程师都绕不开的构建工具,我本人只是会一些简单配置项,或是直接使用vue-cli
、create-react-app
、@angular/cli
等脚手架工具快速生成项目文件。
为了不让自己继续停留在"配置工程师"这个层面,于是决定由浅入深、循序渐进的将Webpack整体学习一遍。本系列文章是基于范文杰大佬写的《Webpack5 核心原理与应用实践》掘金小册进行总结的,其中会掺杂一些个人的理解,类似于学习笔记,如果有错误,欢迎大家提出指正~
如何结构化的理解Webpack配置项
Webpack原生提供了上百种配置项,单看这些配置项时,很难从中看出来什么关联,不利于我们学习记忆,而这些配置项到最后都会作用于Webpack构建流程中的不同阶段,所以我们可以从构建流程的角度出发,从而结构化的理解Webpack配置项。 Webpack的打包过程十分复杂,但大概可以简化为以下流程:

- 输入:从文件系统读入代码文件;
- 模块递归处理:调用 Loader 转译 Module 内容,并将结果转换为 AST,从中分析出模块依赖关系,进一步递归调用模块处理过程,直到所有依赖文件都处理完毕;
- 后处理:所有模块递归处理完毕后开始执行后处理,包括模块合并、注入运行时、产物优化等,最终输出 Chunk 集合;
- 输出:将 Chunk 写出到外部文件系统;
从上述打包流程角度,Webpack 配置项大体上可分为两类:
- 流程类:作用于打包流程某个或若干个环节,直接影响编译打包效果的配置项
- 工具类:打包主流程之外,提供更多工程化工具的配置项
流程类相关配置介绍
- 输入输出:
entry
:用于定义项目入口文件,Webpack 会从这些入口文件开始按图索骥找出所有项目文件;context
:项目执行上下文路径;output
:配置产物输出路径、名称等;
- 模块处理:
resolve
:用于配置模块路径解析规则,可用于帮助 Webpack 更精确、高效地找到指定模块module
:用于配置模块加载规则,例如针对什么类型的资源需要使用哪些 Loader 进行处理externals
:用于声明外部资源,Webpack 会直接忽略这部分资源,跳过这些资源的解析、打包操作
- 后处理:
optimization
:用于控制如何优化产物包体积,内置 Dead Code Elimination、Scope Hoisting、代码混淆、代码压缩等功能target
:用于配置编译产物的目标运行环境,支持 web、node、electron 等值,不同值最终产物会有所差异mode
:编译模式短语,支持development
、production
等值,可以理解为一种声明环境的短语
Webpack 首先需要根据输入配置(entry/context) 找到项目入口文件;之后根据模块处理(module/resolve/externals 等) 所配置的规则逐一处理模块文件,处理过程包括转译、依赖分析等;最后再根据后处理相关配置项(optimization/target 等)合并模块资源、注入运行时依赖、优化产物结构等。

工具类相关配置介绍
- 开发效率类:
watch
:用于配置持续监听文件变化,持续构建devtool
:用于配置产物 Sourcemap 生成规则devServer
:用于配置与 HMR 强相关的开发服务器功能
- 性能优化类:
cache
:Webpack 5 之后,该项用于控制如何缓存编译过程信息与编译结果performance
:用于配置当产物大小超过阈值时,如何通知开发者
- 日志类:
stats
:用于精确地控制编译过程的日志内容,在做比较细致的性能调试时非常有用infrastructureLogging
:用于控制日志输出方式,例如可以通过该配置将日志输出到磁盘文件
- 等等
逻辑上,每一个工具类配置都在主流程之外提供额外的工程化能力,例如 devtool 用于配置产物 Sourcemap 生成规则,与 Sourcemap 强相关;devServer 用于配置与 HMR 相关的开发服务器功能;watch 用于实现持续监听、构建。

这里总结下上述所说的流程类与工具类,我个人认为流程类就是Webpack的主流程,也是它的主要目的,就是将我们一块一块的Module通过流程转化成浏览器可以直接访问的html
、css
、js
。而工具类则是在我们完成主要目的之后的衍生需求,例如我们想在修改完代码就立马看到浏览器上发生变化,编译过后的项目报错我们可以对应到具体出错的那一行代码,当我们项目越来越大时,我们想要优化构建时间,并且了解构建时都发生了什么事,这些在主流程之外为了更好的服务我们的配置,就可以当作是工具类。
配置项综合实例
接下来做一个简单的示例,项目文件结构如下:
.
├── src
| └── index.js
└── webpack.config.js
假设src/index.js
是我们的入口文件,webpack.config.js
则是我们的配置文件。
首先我们需要配置项目入口:
module.exports = {
entry: './src/index.js',
};
其次设置打包后文件的输出路径:
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: "[name].js",
path: path.join(__dirname, './dist'), // 这里设置的是/dist目录下
},
};
现在我们可以支持编译一个最简单的项目了,但前端项目一般都需要处理js之外的资源文件,如css
、ts
、图片文件等,我们需要在配置文件中声明,当遇到这些文件时,用对应的哪些加载器去编译。这里举个less
文件的配置实例:
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: "[name].js",
path: path.join(__dirname, './dist'),
},
module: {
rules: [
{
test: /\.less$/i,
include: {
and: [path.join(__dirname, './src')]
},
use: [
"style-loader",
"css-loader",
{
loader: "less-loader",
}
]
}
]
}
};
当解析到.less
文件时,Webpack则会调用对应的loader去编译,这样我们一个简单的配置示例就完成了。
常用的脚手架工具
在实际开发过程中,我们的Webpack往往都是更复杂的,会牵涉到很多Loader、Plugin以及性能和效率方面的考虑,所以社区中提供了很多脚手架工具来快速生成项目:
- Vue CLI:用于帮助用户快速创建、运行 Vue.js 项目脚手架的命令行工具;
- create-react-app:用于创建 React 项目脚手架的命令行工具;
- @angular/cli:用于创建 angular 项目的命令行工具;
- webpack-cli:Webpack 官方提供的命令行工具,提供了一套交互式生成配置文件的指令集,以及项目编译、开发、迁移等功能;
- Neutrino:用于快速创建、运行现代 JavaScript 应用的工具,同时支持 React、Preact、Vue、Web、Node.js、Library 等场景;
- react-starter-kit:用于创建 React + Relay + GraphQL 应用的脚手架工具,内置 SSR 支持。