插件向第三方开发者提供了webpack引擎中完整的能力。使用阶段式的构建回调,开发者可以引入他们自己的行为到webpack构建流程中。创建插件比创建loader更加高级。
为什么需要一个插件
- webpack基础配置无法满足需求
- 插件几乎能够任意更改webpack编译结果
- webpack内部也是通过大量的内部插件实现的
创建插件
- 插件是一个类
- 类上有一个apply的实例方法
apply的参数是compiler
class [ClassName] {constructor(options) {this.otpions = options;}apply(compiler){...}}
compiler和compilation的区别
compiler 对象代表了完整的webpack环境配置,这个对象在启动webpack时被一次性建立,并配置好所有的可操作性设置,包括options,loader和plugin,当在webpack环境中应用一个插件时候,插件将受到此compiler的引用,可以使用它来访问webpack的主环境
compilation 对象代表了一次资源版本的构建,当运行webpack开发环境中间件时,每当检测到一个文件的变化,就会创建有一个新的compilation,从而生成一组新的编译资源。一个 compilation 对象表现了当前的模块资源、编译生成资源、变化的文件、以及被跟踪依赖的状态信息。compilation 对象也提供了很多关键时机的回调,以供插件做自定义处理时选择使用。
简单的自定义插件
done-plugin.js 编译结束执行的插件
class DonePlugin {constructor(options) {this.options = options;}apply(compier) {compiler.hooks.done.tap('DonePlugin', () => {console.log('DonePlugin')})}}

Assets-plugin.js 打印资源块 和 对应文件名
class AssetsPlugin {constructor(options) {this.options = options;}apply(compiler) {compiler.hooks.compilation.tap('AssetsPlugin', (compilation) => {compilation.hooks.chunkAssets.tap('AssetsPlugin', (chunk, filename) => {console.log('chunk, filename)});})}}module.exports = AssetsPlugin

Archive-plugin.js 把打包出来的文件做一个压缩包的备份
const JSZip('jszip');class ArchivePlugin {constructor(options){this.options = options;}apply(compiler) {compiler.hooks.emit.tapPromise('ArchivePlugin', (compilation) => {// 本次编译出来的静态资源文件let assets = compilation.assets;let zip = new JSZip();for (let filename in assets) {// 获取文件对应的源代码const source = assets[filename].source();// 向压缩包添加文件,文件名是filename,文件内容是sourcezip.file(filename, source);}return zip.generateAsync({type: 'nodebuffer'}).then(content => {// 向输出的文件列表中添加一个新的文件assets['Archive_' + Date.now() + '.zip'] = {source() {return content}};})});}}module.exports = ArchivePlugin;
