webpack__Plugin

30 阅读3分钟
plugin是什么

plugin 本质上是一个具有 apply 方法 javascript 对象,而他的这个 apply 方法会被 webpack 在compiler 阶段调用,并且在整个编译生命周期都可以访问 compiler 对象

Plugin工作原理

webpack的工作流程就像一个流水线,经过一系列处理流程后才能将源文件转换为目标文件;每个流程是单一职责的,流程相互之间是同步机制;插件就是插入到流水线的一个功能,在特定的时机对生产线上的资源进行处理,webpack通过Tapable来组织这条流水线,webpack在运行过程中会广播事件,插件需要监听所有与他有关的事,这样才能加入到流水线中去改变生产线的运作

找到钩子事件并挂载上自己的任务就是注册事件,这样当webpack构建的时候,插件注册的事件执行。

什么是钩子

钩子的本质是事件,为了方便我们介入和控制编译的过程,webpack把编译过程中触发的各类事件,封装成事件接口暴露出来,这些接口被称为hooks钩子,开发插件也离不开钩子

Tapable

Tapable为webpack提供了统一的插件接口定义类型,是webpack的核心功能库,webpack库中目前有十种类型hooks他们是:

  • SyncHook
  • SyncBailHook
  • SyncWaterfallHook
  • SyncLoopHook
  • AsyncParallelHook
  • AsyncParallelBailHook
  • AsyncSeriesHook
  • AsyncSeriesBailHook
  • AsyncSeriesWaterfallHook

Tapable还暴露了三个方法给插件,用于注入不同类型的自定义构建行为

  • tap:可以注册同步钩子和异步钩子
  • tapAsync:回调方法注册异步钩子
  • tapPromise:Promise方式注册异步钩子
Plugin构建对象

Complier

Complier保存着webpack环境配置,每次启动webpack构建时都是独一无二的,只会创建一次,这个对象在webpack首次启动时构建,我们可以通过complier对象访问到webpack的主环境配置,如loader,plugin...配置信息

它的主要属性有:

  • complier.options:启动时webpack的所有配置文件
  • complier.inputFileSystem 和 complier.outputFileSystem 可以进行文件操作相当于Node.js的fs
  • complier.hooks:可以注册Tapable的不同种类Hook,从而在complier生命周期中植入不同的逻辑。具体内容可以去官网阅读

Compilation

Compilation表示一次资源构建,Compilation实例能访问到所有模块和他们的依赖。 一个compilation对象会对构建依赖途中的所有模块,进行编译,在编译阶段,模块会加载(load),封存(seal),优化(optimize),分块(chunk),哈希(hash)和重建(restore)

主要的属性

  • compilation.modules可以访问所有模块,打包每一个文件和每一个模块。
  • compilation.chunks由多个modules组成的一个代码块。
  • compilation.assets可以访问到打包生成的所有文件结果
  • compilation.hooks可以注册tapable的不同类型Hook,用于compilation编译模块阶段进行逻辑添加及修改

在了解了执行流程之后

自定义插件
  1. 新建一个测试插件 在 src/plugin新建一个文件
class TestP {
    constructor() {
        console.log('test  TestPlugin')
    }
    apply(complier) {
        console.log('test  TestPluginApply')
    }
}
module.exports = TestP

在webpack配置中修改plugins配置

const TesPlugin = require('./src/plugin/test')
module.exports = {
......
   configureWebpack: (config) => {
       .....
        config.plugins.push(new TesPlugin())
        ....
        })

}

这里的执行步骤是

  1. webpack加载webpack.config.js的所有配置此时会new TestP() 执行插件的构造器
  2. webpack创建complier对象
  3. 遍历所有plugins中的插件,调用插件的apply,再执行剩下的编译流程
  4. 执行剩下的编译流程触发各个hooks

通过控制台输出的时间顺序可以看出

image.png

chainWebpack和configureWebpack的区别

chainWebpack 配置项允许我们更细粒度的控制 webpack 的内部配置,可以让我们能够使用链式操作来修改配置。使用webpack-chain维护 eg:

chainWebpack: config => { 
// 移除 prefetch 插件
config.plugins.delete('prefetch') 
config.module 
.rule('file')
.test(/\.(zip|xls|pdf|doc|docx)(\?.*)?$/)
.use('file-loader') 
.loader('url-loader') 
.options({ limit: 1, name: 'file/[name].[ext]' }) 
.end()

configureWebpack 更倾向于整体替换和修改 configureWebpack 可以直接是一个对象,也可以是一个函数,如果是对象它会直接使用 webpack-merge 对其进行合并处理,如果是函数,你可以直接使用其 config 参数来修改 webpack 中的配置,或者返回一个对象来进行 merge 处理 eg:

    // 开发环境不需要gzip
    if (process.env.NODE_ENV === 'production') {
      config.plugins.push(
        new CompressionWebpackPlugin({
          // 正在匹配需要压缩的文件后缀
          test: /\.(js|css|svg|woff|ttf|json|html)$/,
          // 大于10kb的会压缩
          threshold: 10240
          // 其余配置查看compression-webpack-plugin
          // deleteOriginalAssets: true // 删除原文件
          // minRatio:0.8, // 只有压缩率小于这个值的资源才会被处理
          // filename: '[path].gz[query]',
        })
      )
    }
  },