首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
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 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
前端插件机制剖析及业界案例分析
导语 如果你的工具型面对的对象有很丰富的场景需求,或者不想再为频繁的增减需求而频繁迭代,是时候考虑为你的系统设计一款插件系统。 插件机制 插件机制: Core-Plugin 架构的组成 Core:基础功能,提供插件运行的环境,管理插件的注册与卸载(可拔插)以及运行,也即管理插件的生命周期。 PluginApi:插件运行的接口,由 Core 抽象出来的接口。(颗粒度尽可能小) Plugin:每个插件都是一个独立的功能模块。 Core-Plugin 模式的好处,总结几点: 提高扩展性; 减少因功能改变而引起的
用户1097444
2022/06/29
7790
前端插件机制剖析及业界案例分析
webpack-插件机制杂记 系列文章前言Tapablecompilecompilation编写一个插件compiler和compilation一些比较重要的事件钩子总结引用
webpack本身并不难,他所完成的各种复杂炫酷的功能都依赖于他的插件机制。或许我们在日常的开发需求中并不需要自己动手写一个插件,然而,了解其中的机制也是一种学习的方向,当插件出现问题时,我们也能够自己来定位。
菜的黑人牙膏
2019/03/15
1.3K0
Webpack原理与实践(一):打包流程
在阅读 webpack4.x 源码的过程中,参考了《深入浅出webpack》一书和众多大神的文章,结合自己的一点体会,总结如下。
用户2356368
2019/04/03
8950
Webpack原理与实践(一):打包流程
揭秘webpack插件工作流程和原理
通过插件我们可以扩展webpack,在合适的时机通过Webpack提供的 API 改变输出结果,使webpack可以执行更广泛的任务,拥有更强的构建能力。 本文将尝试探索 webpack 插件的工作流程,进而去揭秘它的工作原理。同时需要你对webpack底层和构建流程的一些东西有一定的了解。
前端迷
2020/05/26
1.9K0
Webpack编写自己的Loader和Plugin
Loader就像是一个翻译员,能把源文件经过转化后输出新的结果,并且一个文件还可以链式的经过多个翻译员翻译。 以处理SCSS文件为例:
javascript.shop
2019/09/04
7640
前端推荐!玩转Webpack共需几步?
导语 | 本文主要介绍webpack的打包流程,及其插件系统Tabable,并手写了一下简易打包器。通过这篇文章读者可以了解webpack的具体实现过程,并且自己也可以理解其打包原理,有利于更好的使用这些工具。 一、开始 Webpack打包原理是从入口文件开始分析AST,递归收集依赖,然后生成最终的code。Webpack的插件是贯穿始终的,其插件系统借助了Tapable,Tapable也是Webpack团队开发的,其本质是一种发布订阅模式。 深入理解插件对于深入理解Webpack非常重要。想一下,任何复杂
腾讯云开发者
2022/02/10
5330
Webpack Plugin知识分享
原创不易,未经作者允许禁止转载!! 认识Plugin Loader是用于特定的模块类型进行转换; Plugin可以用于执行更加广泛的任务,比如打包优化、资源管理、环境变量注入等; 常用Plugin CleanWebpackPlugin 每次修改了一些配置,重新打包时,都需要手动删除dist文件夹: 我们可以借助于一个插件来帮助我们完成,这个插件就是CleanWebpackPlugin; 安装: npm install clean-webpack-plugin --save 配置: const { Clea
前端LeBron
2021/12/08
4580
Webpack揭秘——走向高阶前端的必经之路
随着前端工程化的不断发展,构建工具也在不断完善。作为大前端时代的新宠,webpack渐渐成为新时代前端工程师不可或缺的构建工具,随着webpack4的不断迭代,我们享受着构建效率不断提升带来的快感,配置不断减少的舒适,也一直为重写的构建事件钩子机制煞费苦心,为插件各种不兼容心灰意冷,虽然过程痛苦,但结果总是美好的。经历了一番繁琐的配置后,我常常会想,这样一个精巧的工具,在构建过程中做了什么?我也是抱着这样的好奇,潜心去翻阅相关书籍和官方文档,终于对其中原理有所了解,那么现在,就让我们一起来逐步揭开webpack这个黑盒的神秘面纱,探寻其中的运行机制吧。
IMWeb前端团队
2019/12/03
5150
Webpack揭秘——走向高阶前端的必经之路
Webpack揭秘——走向高阶前端的必经之路
随着前端工程化的不断发展,构建工具也在不断完善。作为大前端时代的新宠,webpack渐渐成为新时代前端工程师不可或缺的构建工具,随着webpack4的不断迭代,我们享受着构建效率不断提升带来的快感,配置不断减少的舒适,也一直为重写的构建事件钩子机制煞费苦心,为插件各种不兼容心灰意冷,虽然过程痛苦,但结果总是美好的。经历了一番繁琐的配置后,我常常会想,这样一个精巧的工具,在构建过程中做了什么?我也是抱着这样的好奇,潜心去翻阅相关书籍和官方文档,终于对其中原理有所了解,那么现在,就让我们一起来逐步揭开webpack这个黑盒的神秘面纱,探寻其中的运行机制吧。
疯狂的技术宅
2019/03/27
6250
Webpack揭秘——走向高阶前端的必经之路
一文搞懂Webpack的构建流程
在运行过程中会广播事件,插件只需要监听它所关心的事件,就能加入到这条webpack机制中,去改变webpack的运作,使得整个系统扩展性良好
@超人
2021/09/17
1.5K0
一文搞懂Webpack的构建流程
全方位探究Webpack5中核心Plugin机制
所谓插件即是 webpack 生态中最关键的部分, 它为社区用户提供了一种强有力的方式来直接触及 webpack 的编译过程(compilation process)。
19组清风
2022/02/28
7070
手把手带你入门Webpack Plugin
? 这是第 101 篇不掺水的原创,想要了解更多,请戳上方蓝色字体:政采云前端团队 关注我们吧~ 本文首发于政采云前端团队博客:手把手带你入门Webpack Plugin https://www.z
政采云前端团队
2021/06/15
7170
手把手带你入门Webpack Plugin
通过 Webpack 的 compiler 对象的 Hooks 学会编写 Webpack 插件的编写
webpack 处理完 entry 配置项后触发,这是一个同步串行的 SyncBailHook 钩子,只要监听函数有一个函数的返回值不为undefined,则直接跳过剩下逻辑
用户1515472
2019/07/24
3.8K0
通过 Webpack 的 compiler 对象的 Hooks 学会编写 Webpack 插件的编写
Webpack打包流程分析
webpack 在前端工程领域起到了中流砥柱的作用,理解它的内部实现机制会对你的工程建设提供很大的帮助(不论是定制功能还是优化打包)。
gogo2027
2022/12/07
9730
webpack 插件机制分析及开发调试
webpack 插件机制是整个 webpack 工具的骨架,而 webpack 本身也是利用这套插件机制构建出来的。
winty
2019/12/20
1.7K0
10 分钟了解 webpack 核心内容
Tapable 是 webpack 核心工具之一,提供了插件接口。webpack 中许多对象扩展自 Tapable 类(如,负责编译的 Compiler 和负责创建 bundles 的 Compilation)。这个类暴露 tap, tapAsync 和 tapPromise 方法,可以使用这些方法,注入自定义的构建步骤,这些步骤将在整个编译过程中不同时机触发。
奋飛
2020/07/11
4810
10 分钟了解 webpack 核心内容
Webpack——从基础使用到手动实现(万字长文)
这个其实不用多说了,如今的前端项目哪里还有用不到打包工具的呢,而webpack又作为打包工具中的王者我们又有什么理由不去搞明白它呢。
coder_koala
2020/07/15
1.1K0
Webpack——从基础使用到手动实现(万字长文)
Webpack 详解
webpack是现代前端开发中最火的模块打包工具,只需要通过简单的配置,便可以完成模块的加载和打包。那它是怎么做到通过对一些插件的配置,便可以轻松实现对代码的构建呢?
前端教程
2018/07/27
6130
Webpack 详解
Webpack 深入浅出之公司级分享总结(内附完整ppt)
前段时间,在公司做了个 Webpack 的分享。听众40多人,感觉还不错。所以总结一下,先看一下ppt的目录:
winty
2019/12/21
2.5K4
webpack编写一个插件
插件向第三方开发者提供了 webpack 引擎中完整的能力。使用阶段式的构建回调,开发者可以引入它们自己的行为到 webpack 构建流程中。创建插件比创建 loader 更加高级,因为你将需要理解一些 webpack 底层的内部特性来实现相应的钩子,所以做好阅读一些源码的准备!
前端迷
2019/06/19
1.4K0
相关推荐
前端插件机制剖析及业界案例分析
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档