webpack编写一个plugin插件
插件向第三方开发者提供了 webpack 引擎中完整的能力。使用阶段式的构建回调,开发者可以引入它们自己的行为到 webpack 构建流程中。创建插件比创建 loader 更加高级,因为你将需要理解一些 webpack 底层的内部特性来实现相应的钩子。
一、插件由以下部分构成
1、一个具名 JavaScript 函数
2、在它的原型上定义 apply 方法。
3、指定一个触及到 webpack 本身的 事件钩子。
4、操作 webpack 内部的实例特定数据。
5、在实现功能后调用 webpack 提供的 callback。
// 一个 JavaScript class
class MyExampleWebpackPlugin {
// 将 `apply` 定义为其原型方法,此方法以 compiler 作为参数
apply(compiler) {
// 指定要附加到的事件钩子函数
compiler.hooks.emit.tapAsync(
'MyExampleWebpackPlugin',
(compilation, callback) => {
console.log('This is an example plugin!');
console.log('Here’s the `compilation` object which represents a single build of assets:', compilation); // 使用 webpack 提供的 plugin API 操作构建结果
compilation.addModule(/* ... */); callback();
}
);
}
}
二、基本插件架构
插件是由一个构造函数(此构造函数上的 prototype 对象具有 apply 方法)的所实例化出来的。这个 apply方法在安装插件时,会被 webpack compiler 调用一次。apply 方法可以接收一个 webpack compiler 对象的引用,从而可以在回调函数中访问到 compiler 对象。
class HelloWorldPlugin {
apply(compiler) {
compiler.hooks.done.tap('Hello World Plugin', (
stats /* 在 hook 被触及时,会将 stats 作为参数传入。 */
) => {
console.log('Hello World!');
});
}
}
module.exports = HelloWorldPlugin;
然后,要使用这个插件,在你的 webpack 配置的 plugins 数组中添加一个实例:
// webpack.config.js
var HelloWorldPlugin = require('hello-world'); module.exports = {
// ... 这里是其他配置 ...
plugins: [new HelloWorldPlugin({ options: true })]
};
三、compiler 和 compilation
在插件开发中最重要的两个资源就是 compiler 和 compilation 对象。理解它们的角色是扩展 webpack 引擎重要的第一步。
class HelloCompilationPlugin {
apply(compiler) {
// tap(触及) 到 compilation hook,而在 callback 回调时,会将 compilation 对象作为参数,
compiler.hooks.compilation.tap('HelloCompilationPlugin', compilation => {
// 现在,通过 compilation 对象,我们可以 tap(触及) 到各种可用的 hooks 了
compilation.hooks.optimize.tap('HelloCompilationPlugin', () => {
console.log('正在优化资源。');
});
});
}
}
module.exports = HelloCompilationPlugin;
这里列出 compiler, compilation 和其他重要对象上可用 hooks,请查看 插件 API 文档。
四、异步事件钩子
有些插件 hooks 是异步的。想要 tap(触及) 某些 hooks,我们可以使用同步方式运行的 tap 方法,或者使用异步方式运行的 tapAsync 方法或 tapPromise 方法。
tapAsync
在我们使用 tapAsync 方法 tap 插件时,我们需要调用 callback,此 callback 将作为最后一个参数传入函数。
class HelloAsyncPlugin {
apply(compiler) {
compiler.hooks.emit.tapAsync('HelloAsyncPlugin', (compilation, callback) => {
// 做一些异步的事情……
setTimeout(function() {
console.log('Done with async work...');
callback();
}, 1000);
});
}
}
module.exports = HelloAsyncPlugin;
tapPromise
在我们使用 tapPromise 方法 tap 插件时,我们需要返回一个 promise,此 promise 将在我们的异步任务完成时 resolve。
class HelloAsyncPlugin {
apply(compiler) {
compiler.hooks.emit.tapPromise('HelloAsyncPlugin', compilation => {
// 返回一个 Promise,在我们的异步任务完成时 resolve……
return new Promise((resolve, reject) => {
setTimeout(function() {
console.log('异步工作完成……');
resolve();
}, 1000);
});
});
}
}
module.exports = HelloAsyncPlugin;
五、示例
一旦能我们深入理解 webpack compiler 和每个独立的 compilation,我们就能通过 webpack 引擎本身做到无穷无尽的事情。我们可以重新格式化已有的文件,创建衍生的文件,或者制作全新的生成文件。
我们来写一个简单的示例插件,生成一个叫做 filelist.md 的新文件;文件内容是所有构建生成的文件的列表。这个插件大概像下面这样:
class FileListPlugin {
apply(compiler) {
// emit 是异步 hook,使用 tapAsync 触及它,还可以使用 tapPromise/tap(同步)
compiler.hooks.emit.tapAsync('FileListPlugin', (compilation, callback) => {
// 在生成文件中,创建一个头部字符串:
var filelist = 'In this build:\n\n';
// 遍历所有编译过的资源文件,
// 对于每个文件名称,都添加一行内容。
for (var filename in compilation.assets) {
filelist += '- ' + filename + '\n';
}
// 将这个列表作为一个新的文件资源,插入到 webpack 构建中:
compilation.assets['filelist.md'] = {
source: function() {
return filelist;
},
size: function() {
return filelist.length;
}
};
callback();
});
}
}
module.exports = FileListPlugin;
六、参考博客:
https://juejin.im/post/5d00aa5e5188255a57151c8a
webpack编写一个plugin插件的更多相关文章
- 从零开始编写一个vue插件
title: 从零开始编写一个vue插件 toc: true date: 2018-12-17 10:54:29 categories: Web tags: vue mathjax 写毕设的时候需要一 ...
- 如何自己编写一个easyui插件续
接着如何自己编写一个easyui插件继续分享一下如何从上一节写的“hello”插件继承出一个“hello2”. 参考了combobox的源码中继承combo,当然我这个简单很多了.都是根据自己的理解来 ...
- 如何编写一个gulp插件
很久以前,我们在"细说gulp"随笔中,以压缩JavaScript为例,详细地讲解了如何利用gulp来完成前端自动化. 再来短暂回顾下,当时除了借助gulp之外,我们还利用了第三方 ...
- 自己动手编写一个VS插件(五)
作者:朱金灿 来源:http://blog.csdn.net/clever101 继续编写VisualStudio插件.这次我编写的插件叫DevAssist(意思是开发助手).在看了前面的文章之后你知 ...
- webpack中如何编写一个plugin
loader和plugin有什么区别呢?什么是loader,什么是plugin. 当我们在源代码里面去引入一个新的js文件或者一个其他格式的文件的时候,这个时候,我们可以借助loader去帮我们处理引 ...
- 自己动手编写一个Mybatis插件:Mybatis脱敏插件
1. 前言 在日常开发中,身份证号.手机号.卡号.客户号等个人信息都需要进行数据脱敏.否则容易造成个人隐私泄露,客户资料泄露,给不法分子可乘之机.但是数据脱敏不是把敏感信息隐藏起来,而是看起来像真的一 ...
- 如何自己编写一个easyui插件
本文介绍如何通过参考1.4.2版本的progressbar的源码自己编写一个HelloWorld级别的easyui插件,以及如何拓展插件的功能. 有利于我们理解easyui插件的实现,以及了解如何对e ...
- 自己动手编写一个VS插件(八)
作者:朱金灿 来源:http://blog.csdn.net/clever101 利用业余时间继续开发一个VS插件.我要开发的插件是一个代码库插件,主要是用于积累我平时要使用的代码.在之前我已经实现了 ...
- 自己动手编写一个VS插件(七)
作者:朱金灿 来源:http://blog.csdn.net/clever101 继续开发VS插件.今天在添加ATL控件时出现一个"未能返回新代码元素"的错误,如下图: 解决办法是 ...
随机推荐
- crawler 使用jQuery风格实现
以前写过java版的crawler,最近看了Groovy的XmlSlurper,效果还是不太满意,直到这篇文章启发了我:how-to-make-a-simple-web-crawler-in-java ...
- DDCTF-2019-writeup(7web+5misc)
一年前第一次参加了DDCTF,再次参加简单记录下web与misc的writeup Web Web1 滴~ 1.jpg参数可以包含文件,参数经过两次base64和一次16进制编码,将index.php编 ...
- FutureTask用法及解析
1 FutureTask概念 FutureTask一个可取消的异步计算,FutureTask 实现了Future的基本方法,提空 start cancel 操作,可以查询计算是否已经完成,并且可以获取 ...
- VMware Workstation 与 Device/Credential Guard 不兼容
之前在本机搭建Docker for Windows的时候,启用了win10自带的虚拟Hyper-V,但是win10的虚拟与VMware Workstation的虚拟有冲突,运行VMware Works ...
- MySQL 中<=>用法(长知识)
https://www.runoob.com/mysql/mysql-operator.html MySQL 运算符 本章节我们主要介绍 MySQL 的运算符及运算符的优先级. MySQL 主要有以下 ...
- koa 实现下载文件
文件下载需要使用到koa-send这个插件,该插件是一个静态文件服务的中间件,它可以用来实现文件下载的功能. 1.下载页面 static/download.html <!DOCTYPE html ...
- Python——sklearn提供的自带的数据集
sklearn提供的自带的数据集 sklearn 的数据集有好多个种 自带的小数据集(packaged dataset):sklearn.datasets.load_<name> 可在线下 ...
- 影响mysql性能的因素
一.服务器硬件. CPU不够快,内存不够多,磁盘IO太慢. 对于计算密集型的应用,CPU越可能去影响系统的性能,此时,CPU和内存将越成为系统的瓶颈. 当热数据大小远远超过系统可用内存大小时,IO资源 ...
- Mybatis中表名当做变量
做业务时,有时候会遇到不同SQL语句之中,只有使用的表名不用而已,其他参数和取得值都是一样的情况.这种时候必然想到把表名当做一个变量传到共通的SQL语句中. 当然正常的传入参数的方式#{param}肯 ...
- uni-app 实现热更新
前端打包 app 即把写好的静态资源文件套壳打包成 app ,而热更新即下载并替换 app 内部的静态资源文件,实现 app 的版本升级. 在uni-app 中,我们是如何实现热更新的呢?下面来看代码 ...