webpack plugins 插件

448 阅读3分钟

定义

   webpack plugins是一个通过注册webpack自身编译过程中触发的生命周期钩子来实现访问和处理编译过程的javaScript函数或class。插件的使用范围从打包优化、压缩,一直到重新定义环境中的变量。

插件类型

  • 按照插件所注册的事件分类
    • 同步钩子
      • SyncHook(同步钩子,被一个接一个地调用)
      • Bail Hooks(同SyncHook类似,如果该类型任何插件返回了除undefined之外的任意值,则值由该钩子返回并不会执行剩余的该类型钩子,如optimizeChunksoptimizeChunkModules等)
      • Waterfall Hooks(同SyncHook类似,但将每个钩子的返回值传递给下一个钩子,如ModuleTemplateChunkTemplate等)
    • 异步钩子
      • Async Series Hooks(与SyncHook类似,但钩子的回调函数是异步的,该钩子被一个接一个地调用)
      • Async waterfall Hooks(与Waterfall Hooks类似,但钩子的回调函数是异步的)
      • Async Series Bail Hooks(与Bail Hooks类似,但钩子的回调函数是异步的)
      • Async Parallel Hooks(与Async Series Hooks类似,但被并行调用)
  • 按照所属模块分类
    • Compiler 钩子,Compiler对象代表了完整的webpack环境配置;
    • Compilation 钩子,Compilation对象代表了一次资源版本构建;

常用的插件

  • webpackbar webpack 优雅的进度条和分析器;
  • webpack.DefinePlugin 在编译时使用特定值或表达式定义全局变量;
  • webpack.HotModuleReplacementPlugin 热更新插件(webpack v4 默认启用HMR);
  • friendly-errors-webpack-plugin 识别并整理、排序webpack 错误,为开发者提供更好的体验;
  • webpack.optimize.CommonsChunkPlugin 将公共模块组合到新的文件,减少公共代码的冗余;
  • mini-css-extract-plugin 将CSS提取成单独的文件,支持异步加载、不需重复编译;
  • extract-text-webpack-plugin 【已废弃】从一个或多个bundle中提取文本到一个单独的文件中;
  • html-webpack-plugin 创建 html 文件;
  • fork-ts-checker-webpack-plugin 在一个单独的进程上运行typeScript 类型检查;
  • moment-locales-webpack-plugin 轻松删除moment.js中未使用的locales
  • hard-source-webpack-plugin 为模块提供一个中间缓存;
  • VueLoaderPlugin 配合vue-loader 15.x使用,用来处理vue 模块的module rule
  • copy-webpack-plugin 将已存在的单个文件或整个目录复制到构建目录;
  • webpack-bundle-analyzer 树状图形式的bundle内容分析工具;

用法

const HtmlWebpackPlugin = require('html-webpack-plugin'); // 生成html的插件
const webpack = require('webpack');

const config = {
  module: {
    rules: [
      { test: /\.txt$/, use: 'raw-loader' }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({template: './src/index.html'}) // 使用new 操作符新建插件实例进而添加插件,通过选项(option)自定义。
  ]
};

module.exports = config;

运行原理

插件的本质是一个注册到Compiler钩子或Compilation钩子上的对象,而Compiler钩子或Compilation钩子均是继承自Tabable Hooks 类,该类支持使用tap或tapAsync、tapPromise来注册钩子处理函数,然后webpack 会在特定编译时机通过call或callAsync执行钩子处理函数,整个处理过程类似Node.js的EventEmitter 类。

制作插件

// plugins.js
const pluginName = 'testWebpackPlugins';

class MyWebpackPlugins {
  // 插件实例化的入参
  constructor(props){
    console.log("props:", props);
  }
  // 在原型上定义的apply方法
  apply(compiler){
    // 使用beforeRun钩子
    compiler.hooks.beforeRun.tapAsync(pluginName, (compiler, callback) => {
      /* 逻辑处理 */
      console.log("compiler:", compiler);
      console.log("webpack即将构建");
      callback()
    })
    // 使用emit钩子
    compiler.hooks.emit.tapAsync(pluginName, (compilation, callback) => {
      /* 逻辑处理 */
      console.log("compilation:", compilation);
      console.log("即将生成资源到 output 目录");
      callback()
    });
  }
}
module.exports =  {
  MyWebpackPlugins,
}

// webpack-config.js 
const { MyWebpackPlugins} = require("./plugins"); // 引入插件
module.exports = {
  // ... configuration settings here ...
  plugins: [new MyWebpackPlugins({test:123})] // 注册插件
};