如何开发webpack plugin
继上回介绍了如何开发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的更多相关文章
- 简单webpack plugin 开发
重要是学习下怎么开发webpack plugin,同时记录下 插件模型 webpack 是一个插件,可以是javascript class ,或者具名 class 定义apply 方法 指定一个绑定到 ...
- YYDS: Webpack Plugin开发
目录 导读 一.cdn常规使用 二.开发一个webpack plugin 三.cdn优化插件实现 1.创建一个具名 JavaScript 函数(使用ES6的class实现) 2.在它的原型上定义 ap ...
- 揭秘webpack plugin
前言 Plugin(插件) 是 webpack 生态的的一个关键部分.它为社区提供了一种强大的方法来扩展 webpack 和开发 webpack 的编译过程.这篇文章将尝试探索 webpack plu ...
- vue(9)—— 组件化开发 - webpack(3)
前面两个终于把webpack相关配置解析完了.现在终于进入vue的开发了 vue组件化开发预热 前期准备 创建如下项目: app.js: footer.js: main.js: webpack.con ...
- vue(8)—— 组件化开发 - webpack(2)
webpack的常用loder和插件 loder和插件是什么,现在暂且不表,看到后面你就懂了 引入css问题 直接用link标签导入css 在前面的 vue(7)—— 组件化开发 — webpack( ...
- Webpack Plugin
[Webpack Plugin] Since Loaders only execute transforms on a per-file basis, plugins are most commonl ...
- 案例实战之如何写一个webpack plugin
案例实战之如何写一个webpack plugin 1.写一个生成打包文件目录的file.md文件 // 生成一个目录项目目录的文件夹 class FileListPlugin { constructo ...
- 开发 IDEA Plugin 引入探针,基于字节码插桩获取执行SQL
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 片面了! 一月三舟,托尔斯泰说:"多么伟大的作家,也不过就是在书写自己的片 ...
- 如何开发webpack loader
关于webpack 作为近段时间风头正盛的打包工具,webpack基本占领了前端圈.相信你都不好意思说不知道webpack. 有兴趣的同学可以参考下我很早之前的webpack简介 . 确实webpac ...
随机推荐
- 团队作业4——第一次项目冲刺 FiRsT DaY
项目冲刺--first blood 今天是阳光明媚的一天[明明是阴天好吗= =],今天是心情愉悦的一天[每天都要提交博客高兴个水水哦-3-] 天霸动霸.tua小队迎来了第一敏捷冲刺,小伙伴们是时候打起 ...
- JAVA基础第一组(前5道题)
1.[程序1] 题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一 对兔子,假如兔子都不死,问每个月的兔子总数为多少? 1.程序分析: 兔 ...
- 团队作业八——第二次团队冲刺(Beta版本)第4天
团队作业八--第二次团队冲刺(Beta版本)第4天 一.每个人的工作 (1) 昨天已完成的工作 做一下用户注册的功能和登录功能. (2) 今天计划完成的工作 完成界面跳转 (3) 工作中遇到的困难 界 ...
- 201521123103 《Java学习笔记》 第五次学习总结
一.本周学习总结 1.1 尝试使用思维导图总结有关多态与接口的知识点. 1.2 可选:使用常规方法总结其他上课内容. (1).接口更灵活.更方便,可以方便的为现有的系统添加新的功能. (2).is-a ...
- Java课程设计 ————五子棋 (个人博客)
JAVA课程设计 五子棋(博客个人版) •团队课程设计博客链接 http://www.cnblogs.com/mz201521044152/p/7065575.html •个人负责模块或任务说明 1. ...
- mybatis-mapper文件介绍
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-/ ...
- 树状数组(Binary Indexed Tree,BIT)
树状数组(Binary Indexed Tree) 前面几篇文章我们分享的都是关于区间求和问题的几种解决方案,同时也介绍了线段树这样的数据结构,我们从中可以体会到合理解决方案带来的便利,对于大部分区间 ...
- 走进AngularJS
前 言 xiaoq AngularJS 通过新的属性和表达式扩展了 HTML. 使用起来非常方便. 1. AngularJS的指令与表达式 AngularJS 通过 指令 扩展了 HTML,且通 ...
- DialogFragment的应用
一.DialogFragment简单介绍: 1.基本概念 DialogFrament 指一个与fragment建立了关联的Dialog, 随fragment生, 随fragment死, 即Dialog ...
- DOM中document对象的常用属性方法
每个载入浏览器的 HTML 文档都会成为 Document 对象. Document 对象使我们可以从脚本中对 HTML 页面中的所有元素进行访问. 属性 1 document.anchors 返 ...