继上回介绍了如何开发webpack loader 之后。趁热打铁,来继续看下webpack另一个核心组成:plugin。

下面也和loader一样,让我们一起从基本的官方文档着手看起。

loader和plugin的差别

  • loader : 顾名思义,某种类型资源文件的加载器,作用于某种类型的文件上。webpack本身也是不能直接打包这些非js文件的,需要一个转化器即loader。 loader本身是单一,简单的,不能将多个功能放在一个loader里。
  • plugin比loaders更加先进一点,你可以扩展webpack的功能来满足自己的需要,换句话说,loader不能满足的时候,就需要plugin了。

如何开发一个plugin

插件将webpack引擎所有的能力暴露给第三方开发者。通过阶梯式的build回调,开发者可以在webpack编译过程中加入自己的行为。开发插件比loaders更加先进一点,因为你需要理解webpack一些底层构成来添加钩子回调。准备好读一些源码吧。

开发一个插件

一个webpack的插件由以下几方面组成:

  • 一个非匿名的js函数
  • 在它的原型对象上定义apply方法
  • 指明挂载自身的webpack钩子事件
  • 操作webpack内部情况的特定数据
  • 方法完成时唤起webpack提供的回调
// A named JavaScript function.
function MyExampleWebpackPlugin() {
//
};
// Defines `apply` method in it's prototype.
MyExampleWebpackPlugin.prototype.apply = function(compiler) {
// Specifies webpack's event hook to attach itself.
compiler.plugin('webpacksEventHook', function(compilation /* Manipulates webpack internal instance specific data. */, callback) {
console.log("This is an example plugin!!!");
// Invokes webpack provided callback after functionality is complete.
callback();
});
};

编译器和编译

开发插件过程中最重要的两个对象就是compiler 和compilation。理解他们的职责是扩展webpack功能最重要的第一步

编译器对象就是webpack完整的配置环境。该对象一经webpack开始执行就创建,并且通过所有可操作的设置项来设置,例如options,loaders,和plugins。当在webpack环境中应用一个插件时,该插件将会接受到一个指向该编译器的引用。使用该编译器来访问主要的webpack环境。

compilation对象是一个单独的关于版本资源的创建。当执行webpack 开发中间件时,当一个文件的更改被检测到就会创建一个新的compilation对象,因此产生了一些可被编译的资源。一个compilation展现了一些信息关于当前模块资源状态、编译资源、改变的文件、监视的依赖等信息。同样提供了很多关键的回调,当插件扩展自定义行为时

这两个组件是webpack 插件必需的组成部分(特别是compilation),所以开发者如果熟悉下面这些源文件将会获益不小。

插件的基本结构

插件是在原型中带有一个apply方法的实例化对象,当安装插件的时候,这个apply方法就会被webpack调用一次。apply方法提供一个指向当前活动的webpack compiler的引用,该引用允许访问compiler的回调。一个简单的插件结构如下:

function HelloWorldPlugin(options) {
// Setup the plugin instance with options...
} HelloWorldPlugin.prototype.apply = function(compiler) {
compiler.plugin('done', function() {
console.log('Hello World!');
});
}; module.exports = HelloWorldPlugin;

然后安装一个插件,仅仅需要在你的 webpack config 中plugins对应的数组中,增加一个插件的实例即可

var HelloWorldPlugin = require('hello-world');

var webpackConfig = {
// ... config settings here ...
plugins: [
new HelloWorldPlugin({options: true})
]
};

访问编译

通过使用编译器对象,你可能会绑定提供指向每个新的compilation应用的回调。这些compilations提供了编译过程中很多步骤的回调函数。

function HelloCompilationPlugin(options) {}

HelloCompilationPlugin.prototype.apply = function(compiler) {

  // Setup callback for accessing a compilation:
compiler.plugin("compilation", function(compilation) { // Now setup callbacks for accessing compilation steps:
compilation.plugin("optimize", function() {
console.log("Assets are being optimized.");
});
});
}; module.exports = HelloCompilationPlugin;

如果想了解更多关于在编译器、编译中哪些回调是可用的和其他一些更重要的对象,轻戳plugin文档

异步插件

一些编译插件步骤是异步的并且提供了一个当你的插件结束编译时必须调用的回调方法

function HelloAsyncPlugin(options) {}

HelloAsyncPlugin.prototype.apply = function(compiler) {
compiler.plugin("emit", function(compilation, callback) { // Do something async...
setTimeout(function() {
console.log("Done with async work...");
callback();
}, 1000); });
}; module.exports = HelloAsyncPlugin;

示例

一旦我们打开了webpack编译器和每个单独编译的大门,我们可以使用引擎做的事情是无限可能的。我们可以重新格式化存在的文件、创建派生文件、完全伪造一个新文件

让我们写个简单的示例插件,目的是生成一个新的名字为filelist.md的文件。内容如下:列出构建过程中所有的生成文件。这个插件大概如下:

function FileListPlugin(options) {}

FileListPlugin.prototype.apply = function(compiler) {
compiler.plugin('emit', function(compilation, callback) {
// Create a header string for the generated file:
var filelist = 'In this build:\n\n'; // Loop through all compiled assets,
// adding a new line item for each filename.
for (var filename in compilation.assets) {
filelist += ('- '+ filename +'\n');
} // Insert this list into the webpack build as a new file asset:
compilation.assets['filelist.md'] = {
source: function() {
return filelist;
},
size: function() {
return filelist.length;
}
}; callback();
});
}; module.exports = FileListPlugin;

不同类型的插件

插件可以依据其注册的事件来分成不同的类型,每个事件钩子决定了在触发时如何调用该插件。

同步类型

这种类型的实例使用如下方式来调用插件

applyPlugins(name: string, args: any...)

applyPluginsBailResult(name: string, args: any...)

这意味着每一个插件的回调将伴随特定参数args依次被调用。对插件而言这是最简单的格式。很多有用的事件例如"compile", "this-compilation",是期望插件同步执行的。

流式类型

waterfall Plugins 通过下面的方式调用

applyPluginsWaterfall(name: string, init: any, args: any...)

异步类型

当所有的插件被使用下面的方法异步调用的时候,即为异步插件

applyPluginsAsync(name: string, args: any..., callback: (err?: Error) -> void)

插件控制方法被调用,参数是所有的args和带有这种标志(err?: Error) -> void的回调。handler方法按照注册回调在所有handlers被调用之后的顺序来调用。对于"emit", "run"事件来说这是很常用的模式。

异步流

这种插件将按照流失方式来被异步使用

applyPluginsAsyncWaterfall(name: string, init: any, callback: (err: Error, result: any) -> void)

这种插件的handler被调用时,参数是当前value和带有这种标志(err?: Error) -> void的回调。当被调用时,nextValue是下一个handler的当前值。第一个handler的当前值是init。所有的handler被调用之后,最后一个值将会被赋给回调。如果有的handler传递了一个err的值,回调将会接受err,并且不会有其他handler被第阿勇。这种插件模式使用与于"before-resolve" and "after-resolve"之类的事件。

异步系列

这种和异步插件很相似,不同在于如果有点插件注册失败,将不会调用任何插件

applyPluginsAsyncSeries(name: string, args: any..., callback: (err: Error, result: any) -> void)

结束语

至此,如何开发一个基本的webpack plugin 我相信大家已经知道了,如果还不太清楚的话,可以移步w-loader查看。

另外,对于我这种英语渣渣来说,翻译起来确实难度蛮大的。此处抛砖引玉,希望大家共同探讨学习。

此文为原创文章,转载请注明出处!

如何开发webpack plugin的更多相关文章

  1. 简单webpack plugin 开发

    重要是学习下怎么开发webpack plugin,同时记录下 插件模型 webpack 是一个插件,可以是javascript class ,或者具名 class 定义apply 方法 指定一个绑定到 ...

  2. YYDS: Webpack Plugin开发

    目录 导读 一.cdn常规使用 二.开发一个webpack plugin 三.cdn优化插件实现 1.创建一个具名 JavaScript 函数(使用ES6的class实现) 2.在它的原型上定义 ap ...

  3. 揭秘webpack plugin

    前言 Plugin(插件) 是 webpack 生态的的一个关键部分.它为社区提供了一种强大的方法来扩展 webpack 和开发 webpack 的编译过程.这篇文章将尝试探索 webpack plu ...

  4. vue(9)—— 组件化开发 - webpack(3)

    前面两个终于把webpack相关配置解析完了.现在终于进入vue的开发了 vue组件化开发预热 前期准备 创建如下项目: app.js: footer.js: main.js: webpack.con ...

  5. vue(8)—— 组件化开发 - webpack(2)

    webpack的常用loder和插件 loder和插件是什么,现在暂且不表,看到后面你就懂了 引入css问题 直接用link标签导入css 在前面的 vue(7)—— 组件化开发 — webpack( ...

  6. Webpack Plugin

    [Webpack Plugin] Since Loaders only execute transforms on a per-file basis, plugins are most commonl ...

  7. 案例实战之如何写一个webpack plugin

    案例实战之如何写一个webpack plugin 1.写一个生成打包文件目录的file.md文件 // 生成一个目录项目目录的文件夹 class FileListPlugin { constructo ...

  8. 开发 IDEA Plugin 引入探针,基于字节码插桩获取执行SQL

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 片面了! 一月三舟,托尔斯泰说:"多么伟大的作家,也不过就是在书写自己的片 ...

  9. 如何开发webpack loader

    关于webpack 作为近段时间风头正盛的打包工具,webpack基本占领了前端圈.相信你都不好意思说不知道webpack. 有兴趣的同学可以参考下我很早之前的webpack简介 . 确实webpac ...

随机推荐

  1. 团队作业8----第二次项目冲刺(Beta阶段) 第五天

    BETA阶段冲刺第五天 1.小会议ing 2.每个人的工作 (1)昨天已完成的工作 文件读取的方式采用按钮的: (2) 今天计划完成的工作 (3) 工作中遇到的困难: 林莹:源代码的部分我们已经初步完 ...

  2. 201521123020《Java程序设计》第8周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结集合与泛型相关内容. 2. 书面作业 本次作业题集集合 1.List中指定元素的删除(题目4-1) 1.1 实验总结 运用到了equ ...

  3. 201521123002《Java程序设计》第9周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结集合与泛型相关内容. 2. 书面作业 本次作业题集异常 1.常用异常 题目5-1 1.1 截图你的提交结果(出现学号) 1.2 自己 ...

  4. SAP高可用性(HA)

    1.SAP系统高可用的要求 高可用性是从终端用户的角度来需求,及要求最大化系统的可用性.其目的是降低意外系统关闭时间(服务器生效.存储失效.操作系统失败--),减少预期系统关闭时间(系统及架构的维护. ...

  5. Java简单实用方法一

    整理以前的笔记,在学习Java时候,经常会用到一些方法.虽然简单但是经常使用.因此做成笔记,方便以后查阅 这篇博文先说明构造和使用这些方法. 1,判断String类型数据是否为空 String类型的数 ...

  6. 这是一名Java学者关于学习方向的建议

    无可厚非,编程是一门艺术.但是辉煌的背后必须是一段辛苦的奋斗过程,而过程的引导方向就是最重要的一环.Java语言可谓是引领了编程的潮流,你会是怎样去学的呢? 这是一名Java学者的学习方向的建议 注: ...

  7. Azure Powershell使用已有Image创建ARM非托管磁盘虚拟机

    生成Image映像文件,记录好Image的URL(下面URL为测试URL,具体请参考实际):ImageURL:https://hlmrgstoragen.blob.core.chinacloudapi ...

  8. oracle pl/sql 包

    包用于在逻辑上组合过程和函数,它由包规范和包体两部分组成.1).我们可以使用create package命令来创建包,如:i.创建一个包sp_packageii.声明该包有一个过程update_sal ...

  9. Java 中与(&)短路与(&&)以及 或(|)短路或(||)的关系

    一.逻辑运算符的使用 1)逻辑运算符的连接的是布尔表达式,要与位运算符做区分. 2)使用方法: public class Test {  public static void main(String[ ...

  10. Spring-boot:5分钟整合Dubbo构建分布式服务

    概述: Dubbo是Alibaba开源的分布式服务框架,它最大的特点是按照分层的方式来架构,使用这种方式可以使各个层之间解耦合(或者最大限度地松耦合).从服务模型的角度来看,Dubbo采用的是一种非常 ...