# webpack 插件的开发

  • 插件没有像 loader 那样的独立运行环境
  • 只能在 webpack 里面运行

# 插件的基本结构

class MyPlugin { // 插件名称
    constructor(options) {
    	this.options = options    
    }
    
    apply(complier) { // 插件上的 apply 方法
        // 插件 hooks
        compiler.hooks.done.tap('My Plugin', (stats) => {
            console.log('hello') // 插件逻辑
        })
    }
}
module.exports = MyPlugin
1
2
3
4
5
6
7
8
9
10
11
12
13

插件使用

plugins: [ new MyPlugin() ]
1

# 错误处理

  • 参数校验阶段可以直接 throw 的方式抛出

    throw new Error('error')
    
    1
  • 通过 compilation 对象的 warnings 和 errors 接收

    compilation.warnings.push('warning')
    compilation.errors.push('error')
    
    1
    2

# 通过 Compilation 文件写入

Compilation 上的 assets 可以用于文件写入

  • 可以将 zip 资源包设置到 compilation.assets 对象上

文件写入 webpack-sources

const { RawSource } = require('webpack-sources')
module.exports = class DemoPlugin {
    constructor(options) {
        this.options = options
    }
    apply(compiler) {
        const { name } = this.options
        // 触发 emit hook
        compiler.plugin('emit', (compilation, cb) => {
            compilation.assets[name] = new RawSource('demo')
            cb()
        })
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

插件也可以通过暴露 hooks 的方式进行自身扩展

# zip 插件

  • jszip 写入zip文件

    npm i jszip -D
    
    var zip = new JSZip();
    
    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");
    });
    
    /*
    Results in a zip containing
    Hello.txt
    images/
        smile.gif
    */
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
  • Hooks 是 emit,是一个异步的 hook

  • emit 生成文件阶段,读取的是 compilation.assets 对象的值

    • 可以将 zip 资源包设置到 compilation.assets 对象上

# zip-plugin

// zip-plugin,js
const JSZip = require('jszip');
const path = require('path');
const RawSource = require('webpack-sources').RawSource;
const zip = new JSZip();

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

    apply(compiler) {
        // webpack 编译钩子对象 文件生成节点
        compiler.hooks.emit.tapAsync('ZipPlugin', (compilation, callback) => {
            const folder = zip.folder(this.options.filename); // 创建zip文件包
			
            // 处理文件
            for (let filename in compilation.assets) {
                const source = compilation.assets[filename].source(); // 文件source内容
                folder.file(filename, source); // 写入文件包
            }

            zip.generateAsync({
                type: 'nodebuffer'
            }).then((content) => {
                const outputPath = path.join(
                    compilation.options.output.path, 
                    this.options.filename + '.zip'
                );
				
                // 绝对路径转成相对路径
                const outputRelativePath = path.relative(
                    compilation.options.output.path, // 相对路径
                    outputPath // 绝对路径
                );
                
                // 转换成source内容
                compilation.assets[outputRelativePath] = new RawSource(content);

                callback();
            });
        });
    }
}

// webpack.config.js
const ZipPlugin = require('./zip-plug')
module.exports = {
    ...
    plugins: [
        new ZipPlugin()
    ]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
更新于: 2/12/2020, 8:50:45 AM