手写一个webpack插件(plugin)

news2024/11/20 3:23:40

熟悉 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

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

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

// 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,先看效果图。
Snipaste_2023-05-01_15-46-05.png

// 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

// config/webpack.config.js

// 引入插件
const TakeTimeWebpackPlugin = require('../plugins/take-time-webpack-plugin');
module.exports = {
  plugins: [
    // 调用插件
    new TakeTimeWebpackPlugin(),
  ],
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/591397.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用docker和minio实现对象存储

文章目录 使用docker和minio实现对象存储什么是minio安装minio使用minio 使用docker和minio实现对象存储 什么是minio ​ Minio是一个开源的分布式文件存储系统,它基于 Golang 编写,虽然轻量,却拥有着不错的高性能,可以将图片、视频、音乐、…

Sequelize:Node.js 中的强大 ORM 框架

❤️砥砺前行,不负余光,永远在路上❤️ 目录 前言优势:提高效率,不用SQL即可完成数据库操作。 那什么是 Sequelize?主要特性:1、模型定义和映射:2、关联和联接:3、事务管理&#xff…

Java性能权威指南-总结2

Java性能权威指南-总结2 性能测试方法原则2:理解批处理流逝时间、吞吐量和响应时间批处理流逝时间吞吐量测试 原则3:用统计方法应对性能的变化 性能测试方法 原则2:理解批处理流逝时间、吞吐量和响应时间 性能测试的第2条原则是多角度审视应用性能。应该测量哪个指标取决于对…

chatgpt赋能python:Python中的与非

Python中的与非 在Python编程中,我们经常会用到与非运算符,用来判断条件语句中的真假性。在本文中,我们将介绍Python中的与非运算符,并探讨其用法和实际应用场景。 什么是与非运算符? 与非运算符是一个布尔操作符&a…

NeRF-SLAM代码记录

前言 没运行成功,尤其是编译gtsam部分,每一步都有错,又是讨厌c++第一天。 这一行编译到92% 就会报错 python/CMakeFiles/gtsam_py.dir/build.make:250: recipe for target python/CMakeFiles/gtsam_py.dir/linear.cpp.o failed make[2

.NET 8 Preview 4 发布

作者:Jon Douglas - Principal Program Manager, NuGet 翻译:Alan Wang 排版:Alan Wang 我们很高兴与大家分享在 .NET 8 预览版 4 中的所有新功能和改进!这次发布是继预览版 3之后的更新。您将在这些月度发布中看到更多功能逐渐亮…

【无标题】win11打开VMware虚拟机蓝屏解决

win11打开VMware虚拟机蓝屏解决 win11打开虚拟机蓝屏!!!解决方案:win11支持16.2以上版本,其他版本不兼容,可用文末的卸载工具卸载之前已安装版本(深度卸载),然后下载16.2…

chatgpt赋能python:Python中的乘号:一个重要的数学运算符

Python中的乘号:一个重要的数学运算符 在 Python 编程语言中,乘号通常是使用“*”表示的数学运算符。这个运算符非常常用,它可以在各种情况下使用。本文将探讨 Python 中乘号的基本用法,以及更高级的用法。 基本用法 在 Python…

python+django高校人事管理系统vue

本高校人事管理系统以Django作为框架,Python语言,B/S模式以及MySql作为后台运行的数据库。本系统主要包括以下功能模块:用户、院长、职称申报、工资信息、绩效信息、奖惩信息、招聘、科系分类等模块。 本文着重阐述了高校人事管理系统的分析、…

easyX实践上手操作小项目

easyX实践上手操作小项目 效果展示主菜单的装饰玩法介绍界面开始游戏界面制作团队界面排行榜界面注:main()函数拓展数据库小结 这里我们学习过easyX的基础知识后,看看是否能实践操作一下,制作一个属于自己的游戏界面呢? 基础知识…

基于深度学习的高精度野生目标检测识别系统(PyTorch+Pyside6+YOLOv5模型)

摘要:基于深度学习的高精度野生目标检测识别系统可用于日常生活中检测与定位野生目标目标,利用深度学习算法可实现图片、视频、摄像头等方式的野生目标目标检测识别,另外支持结果可视化与图片或视频检测结果的导出。本系统采用YOLOv5目标检测…

开源SCRM营销平台MarketGo-账号管理

一、概述 企业在经营的过程中,因为业务、税收等各种因素的需要在各地成立分公司,这样针对公司来说管理成本,运营成本,营销成本都会提高,并且沟通的效率也会变低。 在用户营销的场景中,MarketGo在SCRM做了…

C++ stack容器介绍

🤔stack容器介绍: 📖 stack是一种数据结构,也可以被称为堆栈。它是一个容器,只允许在最顶层进行插入和删除,并且只能访问最后一个插入的元素。这个元素称为栈顶。所有新插入的元素都被放置在栈顶上面&#…

【C++入门】什么是引用

目录 一、引用概念 二、引用特性 三、常引用 四、使用场景 1. 做参数 2. 做返回值 五、传值,传引用效率比较 六、引用和指针的区别 一、引用概念 引用不是新定义一个变量,而是给已存在变量取一个别名,编译器不会为引用变量开辟内存空间…

【C/C++】之内存管理(超详细练气篇)

个人主页:平行线也会相交💪 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 平行线也会相交 原创 收录于专栏【C之路】💌 本专栏旨在记录C的学习路线,望对大家有所帮助🙇‍ 希望我们一起努力、成长&…

AI绘画能力的起源:通俗理解VAE、扩散模型DDPM、DETR、ViT/Swin transformer

前言 2018年我写过一篇博客,叫:《一文读懂目标检测:R-CNN、Fast R-CNN、Faster R-CNN、YOLO、SSD》,该文相当于梳理了2019年之前CV领域的典型视觉模型,比如 2014 R-CNN2015 Fast R-CNN、Faster R-CNN2016 YOLO、SSD2…

Seata 分布式事务-应用实例

Seata 分布式事务-应用实例 需求分析/图解 需求:完成下订单功能,由三个微服务模块协同完成, 涉及到多数据库, 多张表 分析 黑色线是执行顺序线 红色线是想Seata Server注册 最后紫色线是决定是否提交和回滚 项目目录 主题包结构都是一样的但是类名字…

eventfd 和 epoll 的结合使用

一.eventfd介绍 eventfd 是 Linux 的一个系统调用&#xff0c;创建一个文件描述符用于事件通知&#xff0c;自 Linux 2.6.22 以后开始支持。 接口及参数介绍 #include <sys/eventfd.h> int eventfd(unsigned int initval, int flags);eventfd() 创建一个 eventfd 对象&…

spring cloud Alibaba之Nacos Discovery--服务治理 (二)

接着上一篇文章 搭建的微服务环境, 实现nacos 注册中心实战操作案例 一. 服务治理介绍 先来思考一个问题 通过上一章的操作&#xff0c;我们已经可以实现微服务之间的调用。但是我们把服务提供者的网络地址 &#xff08;ip&#xff0c;端口&#xff09;等硬编码到了代码中&a…

【SpringCloud】SpringAMQP

文章目录 1、AMQP2、基本消息模型队列3、WorkQueue模型4、发布订阅模型5、发布订阅-Fanout Exchange6、发布订阅-DirectExchange7、发布订阅-TopicExchange 1、AMQP Advanced Message Queuing Protocol&#xff0c;高级消息队列协议。是用于在应用程序之间传递业务消息的开放标…