webpack plugin

1、基本写法及使用

这里用到 emit 钩子 及make 钩子,前者是串行后者是并行

/**
 *  1.webpack加载webpack.config.js中所有配置,此时就会new TestPlugin(),执行插件的constructor
    2.webpack创建compiler对象
    3.遍历所有plugins中插件,调用插件的apply方法
    4.执行剩下编译流程《触发各个hooks事件)
 */

class TestPlugin {
    constructor() {
        console.log('testPlugin-constructor');
    }

    apply(compiler) {
        console.log('testPlugin-apply');
        // 由文档可知,environment是同步钩子,所以需要使用tap注册
        compiler.hooks.environment.tap("TestPlugin",() => (console.log("TestPlugin environment")))

        // 由文档可知,emit是异步串行钩子 AsyncSeriesHook
        // 串行则顺讯执行
        compiler.hooks.emit.tap("TestPlugin", (compilation) => {
            console.log("TestPlugin emit 111");
        })
        compiler.hooks.emit.tapAsync("TestPlugin", (compilation, callback) =>{
            setTimeout(() => {
                console.log("Testplugin emit 222");
                callback();
            }, 2000)
        })

        compiler.hooks.emit.tapPromise("TestPlugin", (compilation) => {
            return new Promise((resolve) => {
                setTimeout(() => {
                    console.log("TestPlugin emit 333"); resolve();
                },1000);
            })
        })

        // 由文档可知,make是异步并行钩子 AsyncParallelHook
        compiler.hooks.make.tapAsync("TestPlugin", (compilation, callback) => {
            compilation.hooks.seal.tap("TetsPlugin", ()=>{
                console.log("TestPlugin seal");
            })


            setTimeout(() => {
                console.log("Testplugin make 111");
                callback();
            }, 3000);
        })

        compiler.hooks.make.tapAsync("TestPlugin", (compilation, callback) => {
            setTimeout(() => {
                console.log("Testplugin make 222");
                callback();
            }, 1000);
        })

        compiler.hooks.make.tapAsync("TestPlugin", (compilation, callback) => {
            setTimeout(() => {
                console.log("Testplugin make 333");
                callback();
            }, 2000);
        })
    }
}
module.exports = TestPlugin

webpack.config.js中的配置

// 引入插件
const  TestPlugin  = require('./plugins/test-plugin')



// 使用插件
new TestPlugin()

打印结果

2、BannerPlugin

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

  apply(compiler) {
    // 在资源输出之前触发
    compiler.hooks.emit.tap("BannerWebpackPlugin", (compilation) => {
      // debugger;
      const extensions = ["css", "js"];
      // 1. 获取即将输出的资源文件:compilation.assets
      // 2. 过滤只保留js和css资源
      const assets = Object.keys(compilation.assets).filter((assetPath) => {
        // 将文件名切割 ['xxxx', 'js'] ['xxxx', 'css']
        const splitted = assetPath.split(".");
        // 获取最后一个文件扩展名
        const extension = splitted[splitted.length - 1];
        // 判断是否保护
        return extensions.includes(extension);
      });

      const prefix = `/*
* Author: ${this.options.author}
*/
`;
      // 3. 遍历剩下资源添加上注释
      // console.log(assets);
      assets.forEach((asset) => {
        // 获取原来内容
        const source = compilation.assets[asset].source();
        // 拼接上注释
        const content = prefix + source;

        // 修改资源
        compilation.assets[asset] = {
          // 最终资源输出时,调用source方法,source方法的返回值就是资源的具体内容
          source() {
            return content;
          },
          // 资源大小
          size() {
            return content.length;
          },
        };
      });
    });
  }
}

module.exports = BannerWebpackPlugin;

3、CleanWebpackPlugin

class CleanWebpackPlugin {
  apply(compiler) {
    // 2. 获取打包输出的目录
    const outputPath = compiler.options.output.path;
    const fs = compiler.outputFileSystem;
    // 1. 注册钩子:在打包输出之前 emit
    compiler.hooks.emit.tap("CleanWebpackPlugin", (compilation) => {
      // 3. 通过fs删除打包输出的目录下的所有文件
      this.removeFiles(fs, outputPath);
    });
  }

  removeFiles(fs, filepath) {
    // 想要删除打包输出目录下所有资源,需要先将目录下的资源删除,才能删除这个目录
    // 1. 读取当前目录下所有资源
    const files = fs.readdirSync(filepath);
    // console.log(files); // [ 'images', 'index.html', 'js' ]
    // 2. 遍历一个个删除
    files.forEach((file) => {
      // 2.1 遍历所有文件,判断是文件夹还是文件
      const path = `${filepath}/${file}`;
      const fileStat = fs.statSync(path);
      // console.log(fileStat);
      if (fileStat.isDirectory()) {
        // 2.2 是文件夹,就得删除下面所有文件,才能删除文件夹
        this.removeFiles(fs, path);
      } else {
        // 2.3 是文件,直接删除
        fs.unlinkSync(path);
      }
    });
  }
}

module.exports = CleanWebpackPlugin;

4、AnalyzeWebpackPlugin

class AnalyzeWebpackPlugin {
  apply(compiler) {
    compiler.hooks.emit.tap("AnalyzeWebpackPlugin", (compilation) => {
      // 1. 遍历所有即将输出文件,得到其大小
      /*
        将对象变成一个二维数组:
          对象:
            {
              key1: value1,
              key2: value2 
            }
          二维数组:
            [
              [key1, value1],
              [key2, value2]
            ]
      */
      const assets = Object.entries(compilation.assets);

      /*
          md中表格语法:
            | 资源名称 | 资源大小 |
            | --- | --- |
            | xxx.js | 10kb |
      */
      let content = `| 资源名称 | 资源大小 |
| --- | --- |`;

      assets.forEach(([filename, file]) => {
        content += `\n| ${filename} | ${Math.ceil(file.size() / 1024)}kb |`;
      });

      // 2. 生成一个md文件
      compilation.assets["analyze.md"] = {
        source() {
          return content;
        },
        size() {
          return content.length;
        },
      };
    });
  }
}

module.exports = AnalyzeWebpackPlugin;

生成md文件

5、InlineChunkWebpackPlugin

 让 小的js 文件直接内联到 html中

const HtmlWebpackPlugin = require("safe-require")("html-webpack-plugin");

class InlineChunkWebpackPlugin {
  constructor(tests) {
    this.tests = tests;
  }

  apply(compiler) {
    compiler.hooks.compilation.tap("InlineChunkWebpackPlugin", (compilation) => {
      // 1. 获取html-webpack-plugin的hooks
      const hooks = HtmlWebpackPlugin.getHooks(compilation);
      // 2. 注册 html-webpack-plugin的hooks -> alterAssetTagGroups
      hooks.alterAssetTagGroups.tap("InlineChunkWebpackPlugin", (assets) => {
        // 3. 从里面将script的runtime文件,变成inline script
        assets.headTags = this.getInlineChunk(assets.headTags, compilation.assets);
        assets.bodyTags = this.getInlineChunk(assets.bodyTags, compilation.assets);
      });

      // 删除runtime文件
      hooks.afterEmit.tap("InlineChunkWebpackPlugin", () => {
        // 3. 从里面将script的runtime文件,变成inline script
        Object.keys(compilation.assets).forEach((filepath) => {
          if (this.tests.some((test) => test.test(filepath))) {
            delete compilation.assets[filepath];
          }
        });
      });
    });
  }

  getInlineChunk(tags, assets) {
    /*
      目前:[
        {
          tagName: 'script',
          voidTag: false,
          meta: { plugin: 'html-webpack-plugin' },
          attributes: { defer: true, type: undefined, src: 'js/runtime~main.js.js' }
        },
      ]

      修改为:
        [
          {
            tagName: 'script',
            innerHTML: runtime文件的内容
            closeTag: true 
          },
        ]
    */

    return tags.map((tag) => {
      if (tag.tagName !== "script") return tag;
      // 获取文件资源路径
      const filepath = tag.attributes.src;
      if (!filepath) return tag;

      if (!this.tests.some((test) => test.test(filepath))) return tag;

      return {
        tagName: "script",
        innerHTML: assets[filepath].source(),
        closeTag: true,
      };
    });
  }
}

module.exports = InlineChunkWebpackPlugin;

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

jQuery的学习(一篇文章齐全)

目录 Day29 jQuery 1、jQuery介绍 2、jQuery的选择器 2.1、直接查找 2.2、导航查找 3、jQuery的绑定事件 案例1:绑定取消事件 案例2:模拟事件触发 4、jQuery的操作标签 tab切换案例jQuery版本: 案例1: 案例2&#xff…

ios打包,证书获取

HBuilderX 打包ios界面: Bundle ID(AppID): 又称应用ID,是每一个ios应用的唯一标识,就像一个人的身份证号码; 每开发一个新应用,首先都需要先去创建一个Bundle ID Bundle ID 格式: 一般为&…

数据治理之考评指标类

正则表达式 [] 表述一个字符应该是什么样子 [abc] 表示一个字符可以是a\b\c[a-z] 表示所有小写[a-zA-Z]所有大小写[ a-zA-Z0-9_ ] 所有大小写字母及数字和下划线 -> \w[0-9] \d\s 空格. 表示任意字符 {} 表示有多少个这样的字符 [a-z]{1,10}最少有一个,最多有10…

虚拟机VMware+Ubuntu系统的自定义安装教程(详细图文教程)

VMware可以帮助你在一个操作系统的环境下安装和运行另一个操作系统,从而提高IT效率,降低运维成本,加快工作负载部署速度,提高应用性能,提高服务器可用性,消除服务器数量剧增情况和复杂性。 目录 一、VMwar…

python爬虫教程:selenium常用API用法和浏览器控制

文章目录 selenium apiwebdriver常用APIwebelement常用API 控制浏览器 selenium api selenium新版本(4.8.2)很多函数,包括元素定位、很多API方法均发生变化,本文记录以selenium4.8.2为准。 webdriver常用API 方法描述get(String url)访问目标url地址&…

Redis的持久化(新)

Redis中数据都保存在内存,但是内存中的数据变换很快,也很容易丢失,比如连接断开、宕机停机等等。而Redis提供的数据持久化机制有RDB(Redis DataBase)和AOF(Append Only File)。 1.RDB RDB是指在指定的时间间隔内将内存中的数据集快照写入到磁…

python-opencv划痕检测-续

python-opencv划痕检测-续 这次划痕检测,是上一次划痕检测的续集。 处理的图像如下: 这次划痕检测,我们经过如下几步: 第一步:读取灰度图像 第二步:进行均值滤波 第三步:进行图像差分 第四步&#xff1…

Web前端—移动Web第四天(媒体查询、Bootstrap、综合案例-alloyTeam)

版本说明 当前版本号[20231122]。 版本修改说明20231122初版 目录 文章目录 版本说明目录移动 Web 第五天01-媒体查询基本写法书写顺序案例-左侧隐藏媒体查询-完整写法关键词 / 逻辑操作符媒体类型媒体特性 媒体查询-外部CSS 02-Bootstrap简介使用步骤下载使用 栅格系统全局…

解决 requests 库中 verify 属性问题的方法

在使用 Python 的 requests 库进行网络请求时,我们常常需要确保通信的安全性,这涉及到验证服务器的 SSL/TLS 证书。 这个问题的背后是 requests 库的设计,为了解决这个问题,我们可以考虑修改 requests 库的源代码,以确…

webGL技术开发的软件类型

WebGL 是一种在浏览器中渲染 2D 和 3D 图形的 JavaScript API。通过 WebGL,你可以创建各种类型的软件项目,特别是那些需要强大图形渲染能力的项目。以下是一些你可以使用 WebGL 实现的软件项目类型,希望对大家有所帮助。北京木奇移动技术有限…

shell 条件语句

目录 测试 test测试文件的表达式 是否成立 格式 选项 比较整数数值 格式 选项 字符串比较 常用的测试操作符 格式 逻辑测试 格式 且 (全真才为真) 或 (一真即为真) 常见条件 双中括号 [[ expression ]] 用法 &…

虚拟主播解决方案

虚拟主播作为一种新兴的技术,正在逐渐改变我们的生活和工作方式。美摄科技,作为行业的领导者,致力于为企业提供一站式的虚拟主播技术解决方案,帮助企业实现数字化转型。 美摄科技的虚拟主播解决方案,是一种将文本内容…

软文如何打动用户,媒介盒子教你几招

软文写得好就能传递品牌形象,提高产品销量,但是软文想要打动用户,不是光靠闷头写就行,还需要一定的技巧,今天媒介盒子就来和大家聊聊,软文如何才能打动用户。 一、 明确目标受众需求 软文属于营销的一种形…

vue3项目中使用富文本编辑器

前言 适配 Vue3 的富文本插件不多,我看了很多插件官网,也有很多写的非常棒的,有UI非常优雅让人耳目一新的,也有功能非常全面的。 如: Quill,简单易用,功能全面。editorjs,UI极其优…

什么是视频直播美颜SDK?美颜SDK对比评测与实战应用

为了满足用户对于高质量美颜的需求,各种美颜技术应运而生,其中最为关键的工具之一就是视频直播美颜SDK。 一、视频直播美颜SDK简介 美颜SDK专注于提供实时美颜效果,使得在视频直播过程中能够实现肤色均匀、磨皮、瘦脸等效果,提高…

安卓手机termux上安装MariaDB数据库并实现公网环境下的远程连接

文章目录 前言1.安装MariaDB2.安装cpolar内网穿透工具3. 创建安全隧道映射mysql4. 公网远程连接5. 固定远程连接地址 前言 Android作为移动设备,尽管最初并非设计为服务器,但是随着技术的进步我们可以将Android配置为生产力工具,变成一个随身…

飞书CEO谢欣:绝大部分企业希望拥抱AI,但并未做好准备

11月22日,飞书在北京举办了产品发布会,正式发布“飞书智能伙伴”等系列AI产品。“飞书智能伙伴”有知识、有记忆,有主动性,也能深入到业务中。在内容创作、内容总结、数据分析、场景构建、系统搭建等业务场景,用户均可…

c语言编程(模考1)代码

计算1-10之间数的乘积 #include<stdio.h> int main(){int i;long sum 1;for(i1;i<10;i)sum sum*i;printf("the sum of add is %ld",sum);} 运行结果 从键盘输入两个数&#xff0c;求出最大值&#xff08;要求使用函数完成求最大值&#xff0c;并且用…

【考研数学】数学一“背诵”手册(一)| 高数部分(2)

文章目录 引言一、高数级数空间解析几何球坐标变换公式零碎公式 写在最后 引言 高数一篇文章还是写不太下&#xff0c;再分一些到这里来吧 一、高数 级数 阿贝尔定理&#xff1a;若级数 ∑ a n x n \sum a_nx^n ∑an​xn 当 x x 0 xx_0 xx0​ 时收敛&#xff0c;则适合不…

Python配置与测试利器:Hydra + pytest的完美结合

简介&#xff1a;Hydra 和 pytest 可以一起使用&#xff0c;基于 Hydra Pytest 的应用可以轻松地管理复杂配置&#xff0c;并编写参数化的单元测试&#xff0c;使得Python开发和测试将变得更为高效。 安装&#xff1a; pip install hydra-core pytest案例源码&#xff1a;my…