webpack系列学习-插件编写
字节爱好者 558 5

前言:笔者把学习的webpack知识从基础到原理写个系列,以便回顾。希望能帮助到更多正在学习webpack的小伙伴。

webpack系列学习-初体验

webpack系列学习-基本用法一

webpack系列学习-各种loader使用

webpack系列学习-热更新和压缩

webpack系列学习-使用eslint和发布npm包

webpack系列学习-构建webpack配置

webpack系列学习-详细的实现简易webpack

webpack系列学习-loader编写

前言:plugin只能在webpack里面运行

插件的基本结构


// 基本结构
class MyPlugin {
  apply(compiler){
    compiler.hooks.done.tap('My Plugin',(
    // 插件的hooks
    ) => {
      // 插件处理逻辑
    })
  }
}
module.exports = MyPlugin

// 插件使用:
plugins: [new MyPlugin()]

下面通过一个例子看下:

  • 1.编写简单的一个plugins

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

apply(compiler) { console.log('my plugin is done'); console.log('compiler', this.options); } };

+ 2.在webpack中引入MyPlugin
```js
// webpack.config.js
const path = require('path');
const MyPlugin = require('./plugins/my-plugin');
module.exports = {
  entry: './src/index.js',
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'main.js',
  },
  mode: 'production',
  plugins: [
    new MyPlugin({
      name: 'curry',
    }),
  ],
};
  • 3.运行 npm run build 打印结果 webpack系列学习-插件编写

下面看下复杂的插件场景:

插件中如何获取传递的参数?

  • 通过插件的构造函数获取

module.exports = class MyPlugin { constructor(options){ this.options = options; }

apply(){ console.log('apply', this.options) } }

#### 插件的错误处理?
+ 1.参数校验阶段可以直接 throw 方式抛出
```js
throw new Error('error message')
  • 2.通过 compilation 对象的 warnings 和 errors 接收

    compilation.warnings.push('warning')
    compilation.errors.push('erros')

    如何进行文件读写

  • 通过 compilation进行文件读写,文件写入需要webpack-sources

    const { RawSources } = require('webpack-sources')
    module.exports = class MyPlugin {
    constructor(options){
      this.options = options;
    }
    
    apply(compiler){
      const { name } = this.options;
      compiler.hooks('emit', (compilation, cb) => {
        compilation.assets[name] = new RawSources('demo')
        cb()
      })
    }
    }

下面进行以下实战:编写一个压缩构建资源为zip包的插件

要求:

  • 1.生成的zip包文件名称可以通过插件传入
  • 2.需要使用compiler对象上的特地hooks进行资源的生成

准备知识:nodejs里面将文件压缩为zip包

zip.file("Hello.txt", "Hello World\n");

var img = zip.folder("images"); img.file("smile.gif", imgData, {base64: true});

zip.generateAsync({type:"blob"}).then(function(content) { // see FileSaver.js saveAs(content, "example.zip"); });

#### 文件生成:需要使用emit
+ Compiler 上负责文件生成的hooks是emit ,一个异步的hook
+ emit 生成文件阶段,读取的是compilation.assets 对象的值,可以将zip资源包设置到compilation.assets 对象上

### 开始编写:
#### 配置webpack
```js
// webpack.config.js
const path = require('path');
const ZipPlugin = require('./plugins/zip-plugin');
module.exports = {
  entry: './src/index.js',
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'main.js',
  },
  mode: 'production',
  plugins: [
    new ZipPlugin({
      filename: 'offline',
    }),
  ],
};

编写zip-plugin


// plugins/zip-plugin.js
const JSZip = require('jszip');
const path = require('path');
const { RawSource } = require('webpack-sources');

const zip = new JSZip();

module.exports = class ZipPlugin {
  constructor(options) {
    this.options = options;
  }

  apply(compiler) {
    compiler.hooks.emit.tapAsync('ZipPlugin', (compilation, callback) => {
      const folder = zip.folder(this.options.filename);
      for (let filename in compilation.assets) {
        const source = compilation.assets[filename].source();
        folder.file(filename, source);
      }
      zip
        .generateAsync({
          type: 'nodebuffer',
        })
        .then(content => {
          const outpath = path.join(compilation.options.output.path, `${this.options.filename}.zip`);
          const outputRelativePath = path.relative(compilation.options.output.path, outpath);
          compilation.assets[outputRelativePath] = new RawSource(content);
          callback();
        });
    });
  }
};

运行npm run build查看结果

webpack系列学习-插件编写

评论区

索引目录