编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

webpack系列学习-插件编写(webpack 插件编写)

wxchong 2024-10-10 12:28:49 开源技术 12 ℃ 0 评论

前言:笔者把学习的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
// 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 打印结果


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

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

  • 通过插件的构造函数获取
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('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包

  • 使用:jszip https://www.npmjs.com/package/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");
});

文件生成:需要使用emit

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

开始编写:

配置webpack

// 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查看结果

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表