乐趣区

关于webpack:如何编写一个-Webpack-Plugin

前言

上次写了 如何编写一个 Webpack Loader,明天来说说如何编写一个 Webpack Plugin。

webpack 外部执行流程

一次残缺的 webpack 打包大抵是这样的过程:

  • 将命令行参数与 webpack 配置文件 合并、解析失去参数对象。
  • 参数对象传给 webpack 执行失去 Compiler 对象。
  • 执行 Compiler 的 run 办法开始编译。每次执行 run 编译都会生成一个 Compilation 对象。
  • 触发 Compiler 的 make 办法剖析入口文件,调用 compilation 的 buildModule 办法创立主模块对象。
  • 生成入口文件 AST(形象语法树),通过 AST 剖析和递归加载依赖模块。
  • 所有模块剖析实现后,执行 compilation 的 seal 办法对每个 chunk 进行整顿、优化、封装。
  • 最初执行 Compiler 的 emitAssets 办法把生成的文件输入到 output 的目录中。

Plugin 作用

按我的了解,Webpack 插件的作用就是在 webpack 运行到某个时刻的时候,帮咱们做一些事件。

在 Webpack 运行的生命周期中会播送出许多事件,Plugin 能够监听这些事件,在适合的机会通过 Webpack 提供的 API 扭转输入后果。

官网解释是:

插件向第三方开发者提供了 webpack 引擎中残缺的能力。应用阶段式的构建回调,开发者能够引入它们本人的行为到 webpack 构建流程中。

编写 Plugin

webpack 插件的组成:

  • 一个 JS 命名函数或一个类(能够想下咱们平时应用插件就是 new XXXPlugin()的形式)
  • 在插件类 / 函数的 (prototype) 上定义一个 apply 办法。
  • 通过 apply 函数中传入 compiler 并插入指定的事件钩子,在钩子回调中取到 compilation 对象
  • 通过 compilation 解决 webpack 外部特定的实例数据
  • 如果是插件是异步的,在插件的逻辑编写完后调用 webpack 提供的 callback

比方咱们写一个插件,生成一个版权的文件。

根本雏形

function CopyrightWebpackPlugin() {}

CopyrightWebpackPlugin.prototype.apply = function (compiler) {}

module.exports = CopyrightWebpackPlugin

也能够写成类的模式:

class CopyrightWebpackPlugin {apply(compiler) {console.log(compiler)
  }
}

module.exports = CopyrightWebpackPlugin

webpack 在启动之后,在读取配置的过程中会先执行 new CopyrightWebpackPlugin(options) 操作,初始化一个 CopyrightWebpackPlugin 实例对象。在初始化 compiler 对象之后,会调用上述实例对象的 apply 办法并将 compiler 对象传入。

apply 办法中,通过 compiler 对象来监听 webpack 生命周期中播送进去的事件,咱们也能够通过 compiler 对象来操作 webpack 的输入。

Compiler 和 Compilation

在插件开发中最重要的两个对象是 compilercompilation 对象。

compiler 对象代表了残缺的 webpack 环境配置,在初始化 compiler 对象之后,通过调用插件实例的 apply 办法,作为其参数传入。这个对象在启动 webpack 时被一次性建设,并蕴含了 webpack 环境的所有的配置信息,包含 options,loader 和 plugin。当在 webpack 环境中利用一个插件时,插件将收到此 compiler 对象的援用。能够应用它来拜访 webpack 的主环境。

compilation 对象会作为 plugin 内置事件回调函数的参数,一个 compilation 对象蕴含了以后的模块资源、编译生成资源、变动的文件以及被跟踪依赖的状态信息。当 Webpack 以开发模式运行时,每当检测到一个文件变动,一次新的 compilation 将被创立。compilation 对象也提供了很多事件回调供插件做扩大。通过 compilation 也能读取到 compiler 对象。

编码

上面代码为生成一个版权 txt 文件,新建文件src/plugins/copyright-webpack-plugin.js

class CopyrightWebpackPlugin {apply(compiler) {
    // emit 钩子是生成资源到 output 目录之前执行,emit 是一个异步串行钩子,须要用 tapAsync 来注册
    compiler.hooks.emit.tapAsync('CopyrightWebpackPlugin', (compilation, callback) => {
      // 回调形式注册异步钩子
      const copyrightText = '版权归 JackySummer 所有'
      // compilation 寄存了这次打包的所有内容
      // 所有待生成的文件都在它的 assets 属性上
      compilation.assets['copyright.txt'] = {
        // 增加 copyright.txt
        source: function () {return copyrightText},
        size: function () {
          // 文件大小
          return copyrightText.length
        },
      }
      callback() // 必须调用})
  }
}

module.exports = CopyrightWebpackPlugin

webpack 中许多对象扩大自 Tapable 类。这个类裸露 tap, tapAsync 和 tapPromise 办法,能够应用这些办法,注入自定义的构建步骤,这些步骤将在整个编译过程中不同机会触发。

应用 tapAsync 办法来拜访插件时,须要调用作为最初一个参数提供的回调函数。

在 webpack.config.js

const path = require('path')
const CopyrightWebpackPlugin = require('./src/plugins/copyright-webpack-plugin')

module.exports = {
  mode: 'production',
  entry: './src/index.js',
  output: {path: path.resolve(__dirname, 'dist'),
    filename: '[name].js',
  },
  plugins: [new CopyrightWebpackPlugin()],
}

执行 webpack 命令,就会看到 dist 目录下生成 copyright.txt 文件

如果在配置文件应用 plugin 时传入参数该怎么取得呢,能够在插件类增加构造函数拿到:

 plugins: [
  new CopyrightWebpackPlugin({name: 'jacky',}),
],

copyright-webpack-plugin.js

class CopyrightWebpackPlugin {constructor(options = {}) {console.log('options', options) // options {name: 'jacky'}
  }
}

参考文章:揭秘 webpack plugin

  • ps:集体技术博文 Github 仓库,感觉不错的话欢送 star,给我一点激励持续写作吧~
退出移动版