手写一个webpack插件(plugin)

熟悉 vue 和 react 的小伙伴们都知道,在执行过程中会有各种生命周期钩子,其实webpack也不例外,在使用webpack的时候,我们有时候需要在 webpack 构建流程中引入自定义的行为,这个时候就可以在 hooks 钩子中添加自己的方法。

创建插件

webpack 加载 webpack.config.js 中所有配置,此时 webpack 创建 compiler 对象,遍历所有 plugins 中插件,调用插件的 apply 方法,执行剩下编译流程(触发各个 hooks 事件),具体使用什么钩子和钩子是同步还是异步,请移步compiler 钩子

  1. 创建一个 JavaScript 命名函数或 JavaScript 类
  2. 在插件函数的 prototype 上定义一个 apply 方法
  3. 绑定到 webpack 自身的事件钩子上
  4. 导出这个JavaScript 命名函数或 JavaScript 类
  5. 在 webpack.config.js 文件中引入并调用方法

自定义 banner-webpack-plugin 插件,该插件会在每一个打包后的 js 、css 文件第一行添加注释,先看效果图。

  • emit 钩子是输出 asset 到 output 目录之前执行
  • 获取即将输出的资源文件:compilation.assets
  • 遍历 assets,只处理js和css资源,其他文件不处理
  • 通过 content = entcompilation.assets[filename].source() 获取原来内容
  • 拼接上注释 content = prefix + content
  • 修改资源的 source 和 size
js 复制代码
// plugins/banner-webpack-plugin.js

class BannerWebpackPlugin {
  constructor(options = {}) {
    this.options = options;
  }

  apply(compiler) {
    // 在资源输出之前触发
    compiler.hooks.emit.tap("BannerWebpackPlugin", (compilation) => {
      const extensions = ["css", "js"];
      const prefix = `/*
          * Author: ${this.options.author}
          * Build Time: ${new Date()}
          */
          `;
      // 获取即将输出的资源文件:compilation.assets
      for (const filename in compilation.assets) {
        if (compilation.assets.hasOwnProperty(filename)) {
          // 将文件名进行切割
          const splitted = filename.split(".");
          // 获取文件扩展名
          const extension = splitted[splitted.length - 1];
          // 只处理js和css资源,其他文件不处理
          if (extensions.includes(extension)) {
            const asset = compilation.assets[filename];
            // 获取原来内容
            let content = asset.source();
            // 拼接上注释
            content = prefix + content;
            // 修改资源
            compilation.assets[filename] = {
              // 最终资源输出时,调用source方法,source方法的返回值就是资源的具体内容
              source: () => content,
              // 资源大小
              size: () => content.length,
            };
          }
        }
      }
    });
  }
}
module.exports = BannerWebpackPlugin;

调用 BannerWebpackPlugin

js 复制代码
// config/webpack.config.js

// 引入插件
const BannerWebpackPlugin = require('../plugins/banner-webpack-plugin');
module.exports = {
  plugins: [
    // 调用插件
    new BannerWebpackPlugin({
      author: "小小愿望",
    }),
  ],
};

自定义 take-time-webpack-plugin

自定义 take-time-webpack-plugin 插件,该插件输出 "webpack 构建正在启动!",打包完成后输出 webpack 构建已完成!总耗时 { time } ms,先看效果图。

js 复制代码
// plugins/take-time-webpack-plugin.js

// 一个命名的 Javascript 方法 或 JavaScript 类
class TakeTimeWebpackPlugin {
  time = 0;
  // 原型上需要定义 apply 的方法
  apply(compiler) {
    // 生命周期钩子函数,是由 compiler 暴露
    // 通过 compiler 获取 webpack 内部的钩子,获取 Webpack 打包过程中的各个阶段
    compiler.hooks.environment.tap("TakeTimeWebpackPlugin", (compilation) => {
      console.log("\x1B[36m", "webpack 构建正在启动!");
      this.time = new Date().getTime();
    });
    // 通过 compiler 获取 webpack 内部的钩子,获取 Webpack 打包过程中的各个阶段
    compiler.hooks.afterEmit.tapAsync("TakeTimeWebpackPlugin", (compilation, callback) => {
      const nowTime = new Date().getTime();
      this.time = nowTime - this.time;
      const str = `webpack 构建已完成!总耗时 ${this.time} ms`
      console.log("\x1B[32m", str);
      // 分为同步和异步的钩子,异步钩子在功能完成后,必须执行对应的回调
      callback();
    });
  }
}
module.exports = TakeTimeWebpackPlugin;

调用 TakeTimeWebpackPlugin

在 config/webpack.config.js 文件中引入并执行 TakeTimeWebpackPlugin

js 复制代码
// config/webpack.config.js

// 引入插件
const TakeTimeWebpackPlugin = require('../plugins/take-time-webpack-plugin');
module.exports = {
  plugins: [
    // 调用插件
    new TakeTimeWebpackPlugin(),
  ],
};
相关推荐
ZC跨境爬虫几秒前
批量爬取小说章节并优化排版(附完整可运行脚本)
前端·爬虫·python·自动化
ZC跨境爬虫3 分钟前
海南大学交友平台登录页开发实战day4(解决python传输并读取登录信息的问题)
开发语言·前端·python·flask·html
来一颗砂糖橘6 分钟前
pnpm:现代前端开发的高效包管理器
前端·pnpm
前端摸鱼匠6 分钟前
Vue 3 的defineProps编译器宏:详解<script setup>中defineProps的使用
前端·javascript·vue.js·前端框架·ecmascript
木斯佳7 分钟前
前端八股文面经大全: 美团财务科技前端一面 (2026-04-09)·面经深度解析
前端·实习面经·前端初级
LIO10 分钟前
React 零基础入门,一篇搞懂核心用法(适合新手)
前端·react.js
TeamDev25 分钟前
JxBrowser 8.18.2 版本发布啦!
java·前端·跨平台·桌面应用·web ui·jxbrowser·浏览器控件
netkiller-BG7NYT25 分钟前
yoloutils - Openclaw Agent Skill
前端·webpack·node.js
北城笑笑30 分钟前
FPGA 51,基于 ZYNQ 7Z010 的 FPGA 高速路由转发加速系统架构设计(Xilinx ZYNQ-MINI 7Z010 CLG400 -1)
前端·fpga开发·系统架构·fpga
蜡台34 分钟前
JavaScript async和awiat 使用
开发语言·前端·javascript·async·await