Plugin
约 547 字大约 2 分钟
2026-02-11
如果 Loader 解决的是“模块怎么转”,Plugin 解决的就是“编译过程怎么控”。
换句话说:Loader 面向文件内容,Plugin 面向构建生命周期。
为什么需要 Plugin
很多能力 Loader 做不到,例如:
- 自动生成 HTML 并注入产物。
- 全局常量替换(环境变量注入)。
- 构建完成后产物分析、压缩包生成。
- 自定义编译日志与质量门禁。
这些都依赖 Plugin 在不同生命周期钩子上工作。
常用 Plugin 组合
下面这组插件基本覆盖“开发可用 + 生产可发”的主线需求。
// webpack.config.cjs(节选)
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const isProd = process.env.NODE_ENV === 'production';
module.exports = {
plugins: [
// 自动注入打包产物到 HTML
new HtmlWebpackPlugin({
template: './public/index.html',
minify: isProd,
}),
// 注入全局常量(注意:是编译期替换)
new webpack.DefinePlugin({
__APP_ENV__: JSON.stringify(process.env.NODE_ENV || 'development'),
__ENABLE_MOCK__: JSON.stringify(!isProd),
}),
// 生产环境抽离 CSS
...(isProd
? [
new MiniCssExtractPlugin({
filename: 'css/[name].[contenthash:8].css',
chunkFilename: 'css/[name].[contenthash:8].chunk.css',
}),
]
: []),
],
};DefinePlugin 的关键注意点
它不是“运行时读环境变量”,而是“编译时文本替换”。
错误示例(容易误用):
new webpack.DefinePlugin({
NODE_ENV: 'production',
});正确示例:
new webpack.DefinePlugin({
NODE_ENV: JSON.stringify('production'),
});不 JSON.stringify 会导致替换后不是合法字符串字面量。
自定义 Plugin 最小示例
当你需要内部规范检查或构建后处理时,自定义 Plugin 才有意义。
// plugins/build-log-plugin.cjs
class BuildLogPlugin {
apply(compiler) {
compiler.hooks.done.tap('BuildLogPlugin', (stats) => {
const hasError = stats.hasErrors();
const time = stats.endTime - stats.startTime;
console.log(`[BuildLogPlugin] done in ${time}ms, hasError=${hasError}`);
});
}
}
module.exports = BuildLogPlugin;// webpack.config.cjs(节选)
const BuildLogPlugin = require('./plugins/build-log-plugin.cjs');
module.exports = {
plugins: [new BuildLogPlugin()],
};使用注意事项
建议
- 每个 Plugin 引入前明确“解决哪个问题”。
- 开发和生产分环境启用,减少无效开销。
- 对自定义 Plugin 增加错误兜底和日志。
常见错误
- 把 Plugin 当 Loader 用(职责错位)。
- 所有环境都开分析插件,拖慢开发反馈。
DefinePlugin忘记JSON.stringify。
最佳实践
- Plugin 列表尽量精简,关注收益/成本比。
- 生产构建只保留真正有价值的插件链路。
- 自定义 Plugin 要可观测、可回滚、可替换。
