插件的运行环境

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

插件的基本结构

  基本结构:
  // 插件名称
  class MyPlugin {
    // 插件上的apply方法                                                    
    apply(compiler) { 
      // 插件的hooks
      compiler.hooks.done.tap(' My Plugin', ( 
        stats /* stats is passed as argument when done hook is tapped. */ 
        ) => { 
          // 插件处理逻辑
          console.log('Hello World!');
        }); 
    } 
  }
  module.exports = MyPlugin;

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

搭建插件运行环境

  const path = require("path"); 
  const DemoPlugin = require("./plugins/demo-plugin.js"); 
  const PATHS = { 
    lib: path.join(__dirname, "app", "shake.js"), 
    build: path.join(__dirname, "build"), 
    };
  module.exports = { 
    entry: { lib: PATHS.lib, },
    output: { path: PATHS.build, 
    filename: "[name].js", },
    plugins: [new DemoPlugin()], 
  };

一个简单插件

  src/demo-plugin.js
  module.exports = class DemoPlugin { 
    constructor(options) { 
      this.options = options; 
    }
    apply() { 
      console.log("apply", this.options); 
    }
  };

  加入到 webpack 配置中
  module.exports = {
    ...
    plugins: [new DemoPlugin({ name: "demo" })] 
  }

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

  通过插件的构造函数进行获取
  module.exports = class MyPlugin { 
    constructor(options) { 
      this.options = options; 
    }
    apply() { 
      console.log("apply", this.options); 
    } 
  };

插件的错误处理

  1.参数校验阶段可以直接 throw 的方式抛出
      throw new Error(“ Error Message”)
  2.通过 compilation 对象的 warnings 和 errors 接收
      compilation.warnings.push("warning");
      compilation.errors.push("error");

通过 Compilation 进行文件写入

  Compilation 上的 assets 可以用于文件写入
  ·可以将 zip 资源包设置到 compilation.assets 对象上

  文件写入需要使用 webpack-sources:https://www.npmjs.com/package/webpack-sources

  const { RawSource } = require("webpack-sources"); 
  module.exports = class DemoPlugin { 
    constructor(options) { 
      this.options = options; 
    }
    apply(compiler) { 
      const { name } = this.options; 
      compiler.hooks.emit.tap('DemoPlugin', ( 
        stats /* stats is passed as argument when done hook is tapped. */ 
        ) => { 
          // 插件处理逻辑
          compilation.assets[name] = new RawSource("demo"); cb(); 
        }); 
    } 
  }

插件扩展:编写插件的插件

    插件自身也可以通过暴露 hooks 的方式进行自身扩展,以 html- webpack-plugin 为例:
    ·html-webpack-plugin-alter-chunks (Sync)
    ·html-webpack-plugin-before-html-generation (Async)
    ·html-webpack-plugin-alter-asset-tags (Async)
    ·html-webpack-plugin-after-html-processing (Async)
    ·html-webpack-plugin-after-emit (Async)

编写一个压缩构建资源为zip包的插件

    要求: 
    ·生成的 zip 包文件名称可以通过插件传入
    ·需要使用 compiler 对象上的特地 hooks 进行资源的生成
Node.js 里面将文件压缩为 zip 包
    jszip: https://www.npmjs.com/package/jszip

    jszip 使用示例

    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");
    });
目录结构

zip_plugin

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'
          })
      ]
  }
package.json
  {
    "name": "loader-order",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1",
      "build": "webpack"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "devDependencies": {
      "loader-utils": "^1.2.3",
      "webpack": "^4.39.1",
      "webpack-cli": "^3.3.6",
      "yazl": "^2.5.1"
    },
    "dependencies": {
      "jszip": "^3.2.2"
    }
  }
plugins/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) {
          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 outputPath = path.join(
                      compilation.options.output.path, 
                      this.options.filename + '.zip'
                  );

                  const outputRelativePath = path.relative(
                      compilation.options.output.path,
                      outputPath
                  );
                  compilation.assets[outputRelativePath] = new RawSource(content);

                  callback();
              });
          });
      }
  }
src/index.js
  const a = 1;
执行结果
  npm run build

zip_plugin_result