自定义Webpack插件

84 阅读2分钟

核心

  • Webpack插件通常是一个,里面包含apply方法,接收compiler对象
  • apply方法会在Webpack编译器实例化时被调用,并接收编译器对象(compiler)作为参数

基本核心结构

class MyWebpackPlugin {
    // 可选:接收插件配置参数
    construtor(option) {
        this.option = option
    }
    // 必须 核心
    apply(compiler) {
        // 在这里注册钩子事件
        // compiler.hooks.beforeRun.tap(MyWebpackPlugin, () => {}) 构建前
        // compiler.hooks.compile.tap(MyWebpackPlugin, () => {}) 编译时
        // compiler.hooks.emit.tap(MyWebpackPlugin, () => {}) 生成文件输出到目录前
        // compiler.hooks.afterEmit.tap(MyWebpackPlugin, () => {}) 生成文件输出到目录后
        // compiler.hooks.done.tap(MyWebpackPlugin, () => {}) 构建完成时
    }
}

apply方法解释

  • compiler
    • apply方法接收的参数,代表Webpack编译器实例
  • compiler.hooks
    • 提供了一系列钩子,用于监听不同的编译阶段
  • 常用钩子类型
    • tap()
      • 同步钩子
      • 用于注册事件监听器,第一个参数是插件名称,第二个参数是回调函数
    • tapAsync()
      • 异步串行钩子
    • tapPromise()
      • 异步并行钩子

常用钩子示例

  • 案例1: 在构建完成后执行
class MyWebpackPlugin {
    apply(compiler) {
        compiler.hooks.done.tap('MyWebpackPlugin', (stats) => {
            console.log('构建完成')
        })
    }
}
  • 案例2: 操作打包产物
class MyWebpackPlugin {
    apply(compiler) {
        compiler.hooks.done.tapAsync('MyWebpackPlugin', (compilation, callback) => {
            // 添加一个新建文件到产物
            compilation.assets['new-file.txt'] = {
                source: () => 'This is MyWebpackPlugin',
                size: () => 42
            }
            callback()
        })
    }
}
  • 完整案例: 生成版本文件插件
class GenerateVersionPlugin {
    construtor(options = {filename: 'version.js'}) {
        this.options = options
    }
    apply(compiler) {
        compiler.hooks.emit.tagAsync('GenerateVersionPlugin', (compilation, callback) => {
            const version = {
                timestamp: Date.now(),
                hash: compilation.hash,
                version: require('./package.json').version // 从 package.json 获取版本
            }

            // 将版本信息转为 JSON 字符串
            const content = JSON.stringify(version, null, 2)
            // 添加到打包产物
            compilation.assets[this.options.filename] = {
                source: () => content,
                size: () => content.length
            }

            callback()
        })
    }
}
  • 在webpack.config.js中使用
const GenerateVersionPlugin = require('./plugin/generate-version-plugin')
module.exports = {
    plugins: [
        new GenerateVersionPlugin({
            filename: 'app-version.js' // 自定义文件名
        })
    ]
}

关键概念说明

  • compiler
    • 代表完整的Webpack环境,贯穿整个构建生命周期
  • compilation
    • 代表单次构建过程的对象,包含模块,依赖,文件等

调试技巧

  • 在插件中打印compilation信息
console.log(Array.from(compilation.fileDependencies)) // 查看依赖文件
console.log(Object.keys(compilation.assets)) // 查看输出文件列表
  • 使用ndb调试
ndb node_modules/webpack/bin/webpack.js

可通过webpack实现

  1. 打包产物二次处理
  2. 定义构建日志分析
  3. 自动生成说明文档
  4. 部署文件上传
  5. 自定义构建监控等高级功能