插件基本结构

在之前的源码解析中,我们知道webpack是提供了很多hook给插件去挂载(比如compiler和compilation实例都有很多hook),然后基于他的事件流触发他的钩子也就是触发插件的运行。

插件的运行环境

插件没有像loader那样的独立运行环境,只能在webpack中运行

插件的基本结构

image.png
可以看到插件有一个apply方法,这也是之前说到的 插件应用到compiler上面的方式,在apply中可以挂在compiler或者compilation上面的hook上。

搭建插件的运行环境

在配置文件的plugin配置属性中添加就可以
image.png

开发一个简单的插件

这个简单的插件,在webpack准备阶段,compiler实例刚刚被创建的时候,apply的时候就结束了所有的代码执行,就是在这个时候console了。

  1. const path = require('path');
  2. const MyPlugin = require('./plugins/my-plugin');
  3. module.exports = {
  4. entry: './src/index.js',
  5. output: {
  6. path: path.join(__dirname, 'dist'),
  7. filename: 'main.js'
  8. },
  9. plugins: [
  10. new MyPlugin({
  11. name: 'my plugin'
  12. })
  13. ]
  14. }
  15. // my-plugin
  16. module.exports = class MyPlugin {
  17. constructor (options) {
  18. this.options = options;
  19. }
  20. apply(compiler) {
  21. console.log('My plugin is executed!');
  22. console.log('My plugin options', this.options );
  23. }
  24. }

更复杂的插件开发场景

回想loader的开发过程,参数需要借助loader-utils这个npm包来获取,这个包还有其他功能比如说获取参数name中的占位符,并且根据具体占位符生成具体的输出文件名。

但是在插件中要获取参数比较简单,因为在webpack位置文件中,引入插件的时候就会创建实例,而参数就在创建实例的时候传进去了。因此插件的参数可以通过插件的构造函数获取。

// my-plugin
module.exports = class MyPlugin {
    constructor (options) {
        this.options = options;
    }

    apply(compiler) {
        console.log('My plugin is executed!');
        console.log('My plugin options', this.options );
    }
}

参数的错误处理

  1. 在接受参数的阶段可以做参数的判断,比如需要的参数是否齐全,参数数据类型是否正确。这个阶段可以直接通过throw关键字抛出Error对象来抛出错误
  2. 如果在挂载阶段没问题,在触发的时候,hooks.xxx.call()时传参有问题,可以通过获取compiler中的compilation对象,使用compilation对象的warning和errors传递错误信息。

image.png

通过compilation进行文件写入

这里写错了compiler.plugin()应该改为compiler.hooks.emit.tap(),只传一个函数作为参数就可以了
image.png

插件扩展

image.png

实战开发一个压缩构建资源为zip包的插件

要求:
image.png

前提准备

我们需要知道怎么去生成一个zip包,这里使用一个npm包——jszip。还有怎么把这个包写入到磁盘中。

JSZip

image.png

Compiler上负责文件生成的hooks

image.png