webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具。当 webpack 处理应用程序时,它会在内部从一个或多个入口点构建一个 依赖图(dependency graph),然后将你项目中所需的每一个模块组合成一个或多个 bundles,它们均为静态资源,用于展示你的内容。
通俗的讲:相当于将你写的代码编译成浏览器所能解析的代码,处理资源之间的关系,再将代码压缩打包减小体积再运行)
一、webpack.config.js 文件基本配置
webpack 默认只会处理和压缩 js 文件,需解析其他文件的话就要在module配置项里配置loader
注意:文件中所用到的依赖包: webpack 和 webpack-cli 是基础的,其他依赖根据文件中所用自行下载
npm i -D webpack webpack-cli
const path = require('path')
// 语法检查插件
const ESLintPlugin = require('eslint-webpack-plugin')
// 打包输出html文件
const HtmlWebpackPlugin = require('html-webpack-plugin')
// 将css代码提取成单独文件
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
// 压缩css文件
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin")
// 压缩静态图片
const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin")
module.exports = {
// 入口文件配置项
entry: "./src/main.js",
// 打包输出配置项
output: {
path: path.resolve(__dirname,"../dist"),
filename: "static/js/[name].js",
// 给打包输出的其他文件命名(动态引入文件等),加 .chunk 以区别主文件
chunkFilename: "static/js/[name].chunk.[contenthash:10].js",
// 图片、字体等资源打包后,统一通过type:asset 处理资源命名方式命名
assetModuleFilename: "static/media/[hash:10][ext][query]",
// 清除输出目录中上一次打包的资源
clean: true,
},
// 解析各模块的loader配置项
module: {
rules: [
// 解析css类文件
{
test: /\.css$/,
use: ["style-loader","css-loader"]
},
// 解析图片类文件
{
test: /\.(png|jpe?g|gif|webp|svg)$/,
type: "asset"
},
// 解析字体图标或音视频类文件
{
test: /\.(ttf|woff2?|map3|map4|avi)$/,
type: "asset/resource"
},
// 解析js文件的 es6+ 的语法,需另外配置一个 babel.config.js 文件
{
test: /\.js$/,
// 排除哪些文件不编译
exclude: /node_modules/,
use: ["babel-loader"],
}
],
},
// 插件配置项
plugins: [
// 对文件代码进行语法检查,需另外配置一个 eslint.config.js 文件
new ESLintPlugin({
// 检查些文件
context: path.resolve(__dirname,"../src"),
// 用exclude排除不需要处理的文件,默认开启
exclude: "node_modules",
}),
// 将html文件一起打包到输出目录,并自动引入所需资源
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../public/index.html")
}),
// 提取css代码提取为单独文件
new MiniCssExtractPlugin({
// 文件名
filename: "static/css/[name].css",
// 动态引入时的文件名
chunkFilename: "static/css/[name].chunk.css"
}),
],
// 优化操作配置项
optimization: {
// 用于存放用于压缩的插件
minimizer: [
// 压缩css文件
new CssMinimizerPlugin(),
// 压缩静态图片
new ImageMinimizerPlugin({
// 压缩配置,复制即可无需记
minimizer: {
implementation: ImageMinimizerPlugin.imageminGenerate,
// 这里采用无损压缩
options: {
plugins: [
["gifsicle",{interlaced: true}],
["jpegtran",{progressive:true}],
["optipng",{optimizationLevel: 5}],
[
"svgo",
{
plugins: [
"preset-default",
"prefixIds",
{
name: "sortAttrs",
params: {
xmlnsOrder: "alphabetical",
}
}
]
}
]
]
}
}
}),
],
// 分割代码配置
splitChunks: {
// 对所有资源,符合条件的将会被分割为独立文件
chunks: "all",
},
},
// 打包模式配置项,这里是生产模式
mode: "production"
}
二、核心生命周期阶段
Webpack 的构建流程可划分为以下主要阶段:
1. 初始化阶段
-
读取配置文件:执行打包命令后(例如:npm run build),首先加载你项目根目录中的 webpack.config.js 文件 或 命令行参数(例如:npx webpack --config ./config/webpack.prod.js),解析文件里的配置象
-
创建 Compiler 实例:初始化核心对象,管理整个构建过程(后续的打包流程都是再compiler对象中实现)
-
加载插件:先执行所有插件的 constructor(option) 方法,再依次执行所有插件的 apply(compiler) 方法,注册生命周期钩子
-
注册 ModuleFactory 和 Resolver:准备模块解析和构建的基础设施(准备打包所需要的依赖)
2. 编译阶段
-
触发 Compile 钩子:标识编译开始(所有文件的编译打包都在compiler对象中完成)
-
创建 Compilation 对象:负责单次构建的上下文,存储模块和资源信息(负责一种资源单次的编译和打包过程)
-
解析入口文件:通过
entry
配置找到入口模块(意思是从哪个文件开始编译) -
构建模块依赖图:递归分析所有依赖关系(根据入口文件内对其他文件和资源的引用的关系形成树图)
3. 模块构建阶段(在compilation对象中进行)
-
加载模块内容:通过 resolve 找到文件路径
-
执行 Loader 链:按 从后往前 顺序应用 Loaders(例如
['sass-loader', 'css-loader', 'style-loader']
) -
收集依赖:识别
require
/import
语句,递归处理子模块
4. 优化阶段(在compilation对象中进行)
-
触发
make
钩子:完成所有模块构建后 -
执行 SplitChunks 优化:代码分割(若配置)
-
Tree Shaking:移除未使用代码(用 es 语法引入的模块才会移除,例如一个模块中定义了多个方法默认暴露了出去,但是父模块只导入其中一个方法,那其他方法的代码不会被打包)
-
应用插件优化:如
TerserPlugin
压缩代码,MiniCssExtractPlugin
提取 CSS(若配置)
5. 生成资源阶段(所有资源文件编译、解析完后)
-
触发
emit
钩子:生成最终资源前最后修改机会 -
创建 Chunk:根据入口和动态导入生成输出块 对应 初始化的chunk、延迟加载的chunk
-
生成最终文件:根据
output
配置生成bundle.js
等文件(根据 output配置项 中定义的文件名,给打包后的资源命名) -
写入文件系统:将资源输出到
dist
目录(打包到 output配置项 指定的目录)
6. 收尾阶段
-
触发
done
钩子:构建完成 -
统计信息输出:显示构建时间和资源大小
-
监听模式(Watch Mode):持续监听文件变化,准备重新构建(开发模式下)
三、compiler和compilation中的关键钩子(hook)
compiler对象相当于编译器,webpack会将所有资源文件和环境都放入compiler对象中,而compilation对象就相当于编译器中负责编译资源文件的工具
以下黄色部分为compilation对象中的关键钩子,其他为compiler对象的关键钩子,他们的钩子都存在各自对象的hooks属性中,例如:compiler.hooks.run ;compilatioin.hooks.buildModule 。
钩子名称 | 触发时机 | 典型用途 |
---|---|---|
initialize | compiler对象初始化后 | 检查运行环境 |
beforeRun | 构建开始前 | 清理旧构建结果 |
run | 构建开始 | 记录构建启动时间 |
compile | Compilation对象创建前 | 初始化编译环境(loader等) |
compilation | Compilation对象创建后 | 注册编译器的插件 |
make | 开始分析入口文件 | 自定义模块处理 |
buildModule | 单个模块构建前 | 修改模块源码 |
succeedModule | 单个模块构建完成 | 模块级缓存处理 |
finishModules | 所有模块构建完成 | 提交优化任务 |
optimize | 开始优化阶段 | 代码压缩、Tree Shaking |
afterCompile | Compilation对象编译资源全部结束后 | 分析模块大小、数量,设置缓存 |
emit | 打包资源到输出目录前 | 添加自定义文件 |
afterEmit | 打包资源到输出目录后 | 清理临时文件 |
done | 构建完成 | 输出统计信息 |
failed | 构建失败 | 错误处理 |