首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Webpack中的plugin插件机制

Webpack中的plugin插件机制

原创
作者头像
gogo2027
发布于 2022-10-21 01:30:16
发布于 2022-10-21 01:30:16
84500
代码可运行
举报
运行总次数:0
代码可运行

大家有没有遇到过这些问题:

  • webpack 打包之后的文件没有压缩
  • 静态文件要手动拷贝到输出目录
  • 代码中写了很多环境判断的多余代码

上一篇 「webpack 核心特性」loader 说到 webpack 的 loader 机制,本文主要聊一聊另外一个核心特性:插件(plugin)。

插件机制就是为了完成项目中除了资源模块打包以外的其他自动化工作,解决上述的问题。

plugin 是用来扩展 webpack 功能的,通过在构建流程里注入钩子实现,它为 webpack 带来了很大的灵活性。

plugin 相对于 loader 有哪些区别?

loader 是转换器,将一种文件编译转换为另一个文件,操作的是文件。例如:将 .less 文件转换成 .css 文件。

plugin 是扩展器,它是针对 loader 结束之后,打包的整个过程。它并不直接操作文件,而是基于事件机制工作。在 webpack 构建流程中的特定时机会广播对应的事件,插件可以监听这些事件的发生,在特定的时机做对应的事情。包括:打包优化,资源管理,注入环境变量。

plugin 该怎么配置呢?

例如 HtmlWebpackPlugin 可以为我们生成一个 HTML 文件,其中包括使用 script 标签的 body 中的所有模块。看下如何配置:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const HtmlWebpackPlugin = require('html-webpack-plugin');

const webpackConfig = {
  ...
  plugins: [new HtmlWebpackPlugin()]
};

温馨提示:loader 在 module.rules 中配置,作为模块的解析规则,类型为数组。每一项都是一个对象,内部包含了 test(类型文件)、loader、options(参数)等属性。plugin 则单独配置,类型为数组,每一项是一个 plugin 的实例,参数都通过构造函数传入。

有哪些常见的 plugin?

下面整理的插件列表来自 webpack 中文官网,大家看见不熟悉的 plugin 可以点击名称跳转,看一看,了解一下具体玩法。

名称

描述

AggressiveSplittingPlugin

将原来的 chunk 分成更小的 chunk

BabelMinifyWebpackPlugin

使用 babel-minify进行压缩

BannerPlugin

在每个生成的 chunk 顶部添加 banner

CommonsChunkPlugin

提取 chunks 之间共享的通用模块

CompressionWebpackPlugin

预先准备的资源压缩版本,使用 Content-Encoding 提供访问服务

ContextReplacementPlugin

重写 require 表达式的推断上下文

CopyWebpackPlugin

将单个文件或整个目录复制到构建目录

DefinePlugin

允许在编译时(compile time)配置的全局常量

DllPlugin

为了极大减少构建时间,进行 dll 分包

EnvironmentPlugin

DefinePlugin 中 process.env 键的简写方式。

ExtractTextWebpackPlugin

从 bundle 中提取文本(CSS)到单独的文件

HotModuleReplacementPlugin

启用模块热替换(Enable Hot Module Replacement - HMR)

HtmlWebpackPlugin

简单创建 HTML 文件,用于服务器访问

I18nWebpackPlugin

为 bundle 增加国际化支持

IgnorePlugin

从 bundle 中排除某些模块

LimitChunkCountPlugin

设置 chunk 的最小/最大限制,以微调和控制 chunk

LoaderOptionsPlugin

用于从 webpack 1 迁移到 webpack 2

MinChunkSizePlugin

确保 chunk 大小超过指定限制

NoEmitOnErrorsPlugin

在输出阶段时,遇到编译错误跳过

NormalModuleReplacementPlugin

替换与正则表达式匹配的资源

NpmInstallWebpackPlugin

在开发时自动安装缺少的依赖

ProvidePlugin

不必通过 import/require 使用模块

SourceMapDevToolPlugin

对 source map 进行更细粒度的控制

EvalSourceMapDevToolPlugin

对 eval source map 进行更细粒度的控制

UglifyjsWebpackPlugin

可以控制项目中 UglifyJS 的版本

ZopfliWebpackPlugin

通过 node-zopfli 将资源预先压缩的版本

怎么写一个 plugin?

在说怎么写插件之前,先简单介绍几个好玩的东西:tapablecompilercompilation

tapable

tapable 是一个类似于 nodejsEventEmitter 的库, 主要是控制钩子函数的发布与订阅。当然,tapable 提供的 hook 机制比较全面,分为同步和异步两个大类(异步中又区分异步并行和异步串行),而根据事件执行的终止条件的不同,由衍生出 Bail / Waterfall / Loop 类型。

基本使用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const { SyncHook } = require('tapable');
const hook = new SyncHook(['name']);
hook.tap('hello', (name) => {
  console.log(`hello ${name}`);
});
hook.tap('hi', (name) => {
  console.log(`hi ${name}`);
});

hook.call('july');

// hello july
// hi july

小结:

tapable 基本逻辑是,先通过类实例的 tap 方法注册对应 hook 的处理函数,然后通过 call 方法触发回调函数。

compiler

compiler 对象包含 webpack 环境所有配置信息,包含 options、loaders 和 plugins 等信息。可以简单理解为 webpack 实例。代表整个 webpack 从启动到关闭的生命周期

compile 的内部实现:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Compiler extends Tapable {
  constructor(context) {
    super();
    this.hooks = {
      /** @type {SyncBailHook<Compilation>} */
      shouldEmit: new SyncBailHook(["compilation"]),
      /** @type {AsyncSeriesHook<Stats>} */
      done: new AsyncSeriesHook(["stats"]),
      /** @type {AsyncSeriesHook<>} */
      additionalPass: new AsyncSeriesHook([]),
      /** @type {AsyncSeriesHook<Compiler>} */
      ...
    };
    ...
}

小结:

compile 继承了 tapable ,然后在实例上绑定了一个 hook 对象。

compilation

compilation 对象包含了当前的模块资源、编译生成资源和变化的文件等。仅代表一次新的编译

compilation 的实现:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Compilation extends Tapable {
  /**   * Creates an instance of Compilation.   * @param {Compiler} compiler the compiler which created the compilation   */
  constructor(compiler) {
    super();
    this.hooks = {
      /** @type {SyncHook<Module>} */
      buildModule: new SyncHook(["module"]),
      /** @type {SyncHook<Module>} */
      rebuildModule: new SyncHook(["module"]),
      /** @type {SyncHook<Module, Error>} */
      failedModule: new SyncHook(["module", "error"]),
      /** @type {SyncHook<Module>} */
      succeedModule: new SyncHook(["module"]),
      /** @type {SyncHook<Dependency, string>} */
      addEntry: new SyncHook(["entry", "name"]),
      /** @type {SyncHook<Dependency, string, Error>} */
    };
  }
}

当运行 webpack 开发环境中间件时,每当检测到一个文件变化,就会创建一个新的 compilation,从而生成一组新的编译资源。一个 compilation 对象表现了当前的模块资源、编译生成资源、变化的文件、以及被跟踪依赖的状态信息。compilation 对象也提供了很多关键时机的回调,以供插件做自定义处理时选择使用。

参考webpack视频讲解:进入学习

热身

写一个最基础的 plugin

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 一个 JavaScript 命名函数。
function SimplePlugin() {}

// 在插件函数的 prototype 上定义一个 `apply` 方法。
SimplePlugin.prototype.apply = function (compiler) {
  // 指定一个挂载到 webpack 自身的事件钩子。
  compiler.plugin("webpacksEventHook", function (
    compilation /* 处理 webpack 内部实例的特定数据。*/,    callback  ) {
    console.log("This is an simple plugin!!!");

    // 功能完成后调用 webpack 提供的回调。
    callback();
  });
};

webpack 启动后,做了下面几件事情:

  • 在读取配置的过程中先执行 new SimplePlugin(),初始化一个 SimplePlugin 并获得其实例。
  • 在初始化 compiler 对象后,再调用 SimplePlugin.apply(compiler) 为插件实例传入 compiler 对象。
  • 插件实例在获取到 compiler 对象后,就可以通过 compiler.plugin("webpacksEventHook", function(compilation, callback){}) 监听到 webpack 广播的事件,并且通过 compiler 对象去操作 webpack。

实战

下面写一个实用的插件。

作用是在 webpack 马上关闭时做一些事情。例如告知用打包完成,是否执行成功。或者执行一些 script 脚本。我们将其命名为 AfterWebpackPlugin 。用法如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
module.exports = {
  plugins: [
    // 分别传入成功和失败时的回调函数
    new AfterWebpackPlugin(
      () => {
        // 可以通知用户构建成功,执行发布脚本
      },
      (err) => {
        // 构建失败时,抛出异常
        console.error(err);
      }
    ),
  ],
};

这里实现过程需要借助以下两个钩子:

  • done:在成功构建并且输出文件后,webpack 马上退出时发生。
  • failed:在构建异常时导致构建失败,webpack 马上退出时发生。

实现代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class AfterWebpackPlugin {
  constructor(doneCb, failedCb) {
    // 传入回调函数
    this.doneCb = doneCb;
    this.failedCb = failedCb;
  }

  apply(compiler) {
    compiler.plugin("done", (res) => {
      // webpack 生命周期 `done` 中的回调
      this.doneCb(res);
    });
    compiler.plugin("failed", (err) => {
      // webpack 生命周期 `failed` 中的回调
      this.failedCb(err);
    });
  }
}

module.exports = AfterWebpackPlugin;

开发插件小结:

  • 注意在 webpack 生命周期中找到合适的钩子去完成功能。
  • 注意理解 webpack 生命周期中各个钩子的细微区别。

拓展

webpack 输出阶段会发生的事件及解释如下:

事件名

解释

should-emit

所有需要输出的文件已经生成,询问插件有哪些文件需要输出,有哪些不需要输出

emit

确定好要输出哪些文件后,执行文件输出,可以在这里获取和修改输出的内容

after-emit

文件输出完毕

done

成功完成一次完整的编译和输出流程

failed

如果在编译和输出的流程遇到异常,导致 webpack 退出,就会直接跳转到本步骤,插件可以在本事件中获取具体错误原因

系列文章

  • 「webpack 核心特性」loader
  • 「webpack 核心特性」插件(plugin)
  • 「webpack 核心特性」模块热替换(HMR)

感谢

  • 如果本文对你有帮助,就点个赞支持下吧!感谢阅读。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
如何在 Windows 上将项目上传到 SVN 仓库(完整指南)
Subversion(SVN)是一个广泛使用的版本控制系统,适用于团队协作和代码管理。本文将详细介绍 如何在 Windows 环境下将本地项目上传到指定的 SVN 仓库,涵盖 TortoiseSVN 图形界面和命令行两种方式,并解决常见问题。
码事漫谈
2025/07/07
3760
如何在 Windows 上将项目上传到 SVN 仓库(完整指南)
git fatal detected dubious ownership in repository 的解决方法
我换了一台电脑,将旧电脑的硬盘换到新电脑上;我装了双系统,切换到另一个系统时;我发现了 git 代码仓库无法执行 git 命令,不断报错 fatal: detected dubious ownership in repository at ‘C:\lindexi\Code\Foo’ is owned by: ‘S-1-5-21-469934170-xxx-xxx-1001’ but the current user is: ‘S-1-5-21-469994170-aaa-bbb-1001’ 失败。本文记录此问题的解决方法
林德熙
2023/04/07
10.6K0
git fatal detected dubious ownership in repository 的解决方法
解决fatal: not a git repository (or any of the parent directories): .git问题
在现代软件开发中,版本控制系统扮演着至关重要的角色,Git作为其中最流行和强大的工具之一,为我们提供了高效的代码管理和团队协作能力。然而,在使用Git的过程中,难免会遇到各种问题。其中,"fatal: not a git repository (or any of the parent directories): .git"是一个常见的错误,经常出现在我们意图执行Git命令的时候,提示Git无法找到.git目录,从而无法继续执行相应操作。这个问题可能会让初学者感到困惑和不知所措。
老虎也淘气
2024/01/30
5.7K0
解决fatal: not a git repository (or any of the parent directories): .git问题
git 把项目托管到 码云出现的错误集合
https://blog.csdn.net/weixin_49931650/article/details/132416285?spm=1001.2014.3001.5501
打不着的大喇叭
2024/03/11
3000
git 把项目托管到 码云出现的错误集合
解决 Mac brew install xxx fatal: not in a git directory 问题
1.执行 brew install xxx 命令报错fatal: unsafe repository ('/usr/local/Homebrew/Library/Taps/homebrew/homebrew-cask' is owned by someone else)To add an exception for this directory, call:git config --global --add safe.directory /usr/local/Homebrew/Library/Taps/ho
特特
2022/08/11
12.9K0
git相关问题解析,你想要的都有🔥
本地同步默认分支最近n次的commit信息,克隆默认分支master最近一次commit
甜点cc
2022/12/21
1.5K0
git相关问题解析,你想要的都有🔥
windows git 使用的一些问题和解决方案
没这个习惯都把私钥叫id_rsa这个名字, 通常也不会放在 ~/.ssh目录下 , 但是他默认就在那儿=>C盘,我非要放D盘怎么弄?
chuchur
2022/10/25
9020
深度解决 Git “fatal: refusing to merge unrelated histories” 错误解析什么是历史分支优雅草卓伊凡
这个错误发生在你尝试合并两个没有共同历史的分支时。Git 默认会拒绝这样的操作以防止意外合并不相关的项目。
卓伊凡
2025/06/30
3030
Git 安装、配置并把项目托管到码云 Gitee
https://blog.csdn.net/weixin_49931650/article/details/132460492
打不着的大喇叭
2024/03/11
2370
git报错git pull报错问题error: cannot open .git/FETCH_HEAD: Permission denied解决方案-优雅草央千
正常Linux系统 centos 登录用户为root Ubuntu 为ubuntu
卓伊凡
2025/01/07
3140
部署启动程序出现“A fatal error has been detected by the Java Runtime Environment”的解决办法
原因是:JIT在做编译优化的时候处理 某个方法时出错。 如何知道自己哪个方法编译出错? 错误输出中会告诉你错误日志文件地址,如上:D:\Program Files\eclipse-jee-oxygen-R-win32\eclipse\hs_err_pid9188.log
飞奔去旅行
2019/06/13
8.4K0
如何完美解决在kspDebugKotlin中报Caused by: org.gradle.api.InvalidUserCodeException: Inconsistent JVM-target c
Gradle 是一个流行的构建工具,而在使用 Kotlin 和 Java 混合开发时,常常会遇到 Inconsistent JVM-target compatibility 错误。本文将深入分析这一问题的原因,并提供详细的解决方案,帮助开发者轻松解决这一常见构建错误。
猫头虎
2025/06/01
2660
如何完美解决在kspDebugKotlin中报Caused by: org.gradle.api.InvalidUserCodeException: Inconsistent JVM-target c
解决git reset --soft HEAD^撤销commit时报错
问题: 在进行完commit后,想要撤销该commit,于是使用了git reset --soft HEAD^命令,但是出现如下报错:
天天Lotay
2023/10/15
6370
解决git reset --soft HEAD^撤销commit时报错
Git拉代码,“连不上GitHub”还显示`port 443`?别慌,最强解决方案直接给你!
fatal: unable to access ' ': Failed to connect to github.com port 443 真的是最烦的东西,从开始从事编程就开始看见
程序元元
2025/06/19
2000
Git拉代码,“连不上GitHub”还显示`port 443`?别慌,最强解决方案直接给你!
2018-09-11 Svn升级Git不需要那么痛URL that points to a project root(may be the same as Subversion repository
一. 介绍 SubGit是用java语言编写的。SubGit是一种subversion与git代码库之间双向同步工具。如何在本地subversion版本库上安装SubGit请参考下片文章。本片文章主要说明使用SubGit创建git镜像远程subversion版本库。
Albert陈凯
2018/09/20
1K0
2018-09-11 Svn升级Git不需要那么痛URL that points to a project root(may be the same as Subversion repository
将项目复制到新电脑之后, 无法通过git 进行拉取代码/查看历史提交记录等操作
将项目代码整体打包到新环境(新电脑), 在idea/pycharm下载好git相关插件并打开项目之后, 通过git拉取代码失败(gitlab/git/gtee)
时间静止不是简史
2023/07/10
8910
将项目复制到新电脑之后, 无法通过git 进行拉取代码/查看历史提交记录等操作
腾讯安全威胁情报中心推出2024年5月必修安全漏洞清单
所谓必修漏洞,就是运维人员必须修复、不可拖延、影响范围较广的漏洞,被黑客利用并发生入侵事件后,会造成十分严重的后果。
安全攻防团队
2024/06/26
7360
腾讯安全威胁情报中心推出2024年5月必修安全漏洞清单
git各种命令介绍以及碰到的各种坑
一.各种命令介绍:  git pull:从其他的版本库(既可以是远程的也可以是本地的)将代码更新到本地,例如:'git pull origin master'就是将origin这个版本库的代码更新到本地的master主枝,该功能类似于SVN的update git add:是将当前更改或者新增的文件加入到Git的索引中,加入到Git的索引中就表示记入了版本历史中,这也是提交之前所需要执行的一步,例如'git add app/model/user.rb'就会增加app/model/user.rb文件到Git的索
hbbliyong
2018/03/06
1.9K0
修复 SSL Certificate Problem,如何定位及解决问题
在开发过程中,使用 curl 进行请求或 git 克隆远程仓库时,可能会经常遇见一些 https 证书相关的错误,我们整理了一些常见的错误以及解决方案的汇总,保持更新,也欢迎你在评论中提供其他更好的方案。
Lone神
2021/11/01
12.1K0
一篇文章带你全面了解 Rust 与 安全
在技术和工程领域中,"Safety"(功能安全性)和 "Security"(信息安全保障)是两个关键概念,它们虽然听起来相似,但代表着不同的关注点。尤其是中文翻译,这两个英文单词都被翻译为「安全」一词,所以会让一些人造成一些困惑。
张汉东
2024/04/15
6480
一篇文章带你全面了解 Rust 与 安全
推荐阅读
如何在 Windows 上将项目上传到 SVN 仓库(完整指南)
3760
git fatal detected dubious ownership in repository 的解决方法
10.6K0
解决fatal: not a git repository (or any of the parent directories): .git问题
5.7K0
git 把项目托管到 码云出现的错误集合
3000
解决 Mac brew install xxx fatal: not in a git directory 问题
12.9K0
git相关问题解析,你想要的都有🔥
1.5K0
windows git 使用的一些问题和解决方案
9020
深度解决 Git “fatal: refusing to merge unrelated histories” 错误解析什么是历史分支优雅草卓伊凡
3030
Git 安装、配置并把项目托管到码云 Gitee
2370
git报错git pull报错问题error: cannot open .git/FETCH_HEAD: Permission denied解决方案-优雅草央千
3140
部署启动程序出现“A fatal error has been detected by the Java Runtime Environment”的解决办法
8.4K0
如何完美解决在kspDebugKotlin中报Caused by: org.gradle.api.InvalidUserCodeException: Inconsistent JVM-target c
2660
解决git reset --soft HEAD^撤销commit时报错
6370
Git拉代码,“连不上GitHub”还显示`port 443`?别慌,最强解决方案直接给你!
2000
2018-09-11 Svn升级Git不需要那么痛URL that points to a project root(may be the same as Subversion repository
1K0
将项目复制到新电脑之后, 无法通过git 进行拉取代码/查看历史提交记录等操作
8910
腾讯安全威胁情报中心推出2024年5月必修安全漏洞清单
7360
git各种命令介绍以及碰到的各种坑
1.9K0
修复 SSL Certificate Problem,如何定位及解决问题
12.1K0
一篇文章带你全面了解 Rust 与 安全
6480
相关推荐
如何在 Windows 上将项目上传到 SVN 仓库(完整指南)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档