• webpack plugin


    1、基本写法及使用

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

    1. /**
    2. * 1.webpack加载webpack.config.js中所有配置,此时就会new TestPlugin(),执行插件的constructor
    3. 2.webpack创建compiler对象
    4. 3.遍历所有plugins中插件,调用插件的apply方法
    5. 4.执行剩下编译流程《触发各个hooks事件)
    6. */
    7. class TestPlugin {
    8. constructor() {
    9. console.log('testPlugin-constructor');
    10. }
    11. apply(compiler) {
    12. console.log('testPlugin-apply');
    13. // 由文档可知,environment是同步钩子,所以需要使用tap注册
    14. compiler.hooks.environment.tap("TestPlugin",() => (console.log("TestPlugin environment")))
    15. // 由文档可知,emit是异步串行钩子 AsyncSeriesHook
    16. // 串行则顺讯执行
    17. compiler.hooks.emit.tap("TestPlugin", (compilation) => {
    18. console.log("TestPlugin emit 111");
    19. })
    20. compiler.hooks.emit.tapAsync("TestPlugin", (compilation, callback) =>{
    21. setTimeout(() => {
    22. console.log("Testplugin emit 222");
    23. callback();
    24. }, 2000)
    25. })
    26. compiler.hooks.emit.tapPromise("TestPlugin", (compilation) => {
    27. return new Promise((resolve) => {
    28. setTimeout(() => {
    29. console.log("TestPlugin emit 333"); resolve();
    30. },1000);
    31. })
    32. })
    33. // 由文档可知,make是异步并行钩子 AsyncParallelHook
    34. compiler.hooks.make.tapAsync("TestPlugin", (compilation, callback) => {
    35. compilation.hooks.seal.tap("TetsPlugin", ()=>{
    36. console.log("TestPlugin seal");
    37. })
    38. setTimeout(() => {
    39. console.log("Testplugin make 111");
    40. callback();
    41. }, 3000);
    42. })
    43. compiler.hooks.make.tapAsync("TestPlugin", (compilation, callback) => {
    44. setTimeout(() => {
    45. console.log("Testplugin make 222");
    46. callback();
    47. }, 1000);
    48. })
    49. compiler.hooks.make.tapAsync("TestPlugin", (compilation, callback) => {
    50. setTimeout(() => {
    51. console.log("Testplugin make 333");
    52. callback();
    53. }, 2000);
    54. })
    55. }
    56. }
    57. module.exports = TestPlugin

    webpack.config.js中的配置

    1. // 引入插件
    2. const TestPlugin = require('./plugins/test-plugin')
    3. // 使用插件
    4. new TestPlugin()

    打印结果

    2、BannerPlugin

    1. class BannerWebpackPlugin {
    2. constructor(options = {}) {
    3. this.options = options;
    4. }
    5. apply(compiler) {
    6. // 在资源输出之前触发
    7. compiler.hooks.emit.tap("BannerWebpackPlugin", (compilation) => {
    8. // debugger;
    9. const extensions = ["css", "js"];
    10. // 1. 获取即将输出的资源文件:compilation.assets
    11. // 2. 过滤只保留js和css资源
    12. const assets = Object.keys(compilation.assets).filter((assetPath) => {
    13. // 将文件名切割 ['xxxx', 'js'] ['xxxx', 'css']
    14. const splitted = assetPath.split(".");
    15. // 获取最后一个文件扩展名
    16. const extension = splitted[splitted.length - 1];
    17. // 判断是否保护
    18. return extensions.includes(extension);
    19. });
    20. const prefix = `/*
    21. * Author: ${this.options.author}
    22. */
    23. `;
    24. // 3. 遍历剩下资源添加上注释
    25. // console.log(assets);
    26. assets.forEach((asset) => {
    27. // 获取原来内容
    28. const source = compilation.assets[asset].source();
    29. // 拼接上注释
    30. const content = prefix + source;
    31. // 修改资源
    32. compilation.assets[asset] = {
    33. // 最终资源输出时,调用source方法,source方法的返回值就是资源的具体内容
    34. source() {
    35. return content;
    36. },
    37. // 资源大小
    38. size() {
    39. return content.length;
    40. },
    41. };
    42. });
    43. });
    44. }
    45. }
    46. module.exports = BannerWebpackPlugin;

    3、CleanWebpackPlugin

    1. class CleanWebpackPlugin {
    2. apply(compiler) {
    3. // 2. 获取打包输出的目录
    4. const outputPath = compiler.options.output.path;
    5. const fs = compiler.outputFileSystem;
    6. // 1. 注册钩子:在打包输出之前 emit
    7. compiler.hooks.emit.tap("CleanWebpackPlugin", (compilation) => {
    8. // 3. 通过fs删除打包输出的目录下的所有文件
    9. this.removeFiles(fs, outputPath);
    10. });
    11. }
    12. removeFiles(fs, filepath) {
    13. // 想要删除打包输出目录下所有资源,需要先将目录下的资源删除,才能删除这个目录
    14. // 1. 读取当前目录下所有资源
    15. const files = fs.readdirSync(filepath);
    16. // console.log(files); // [ 'images', 'index.html', 'js' ]
    17. // 2. 遍历一个个删除
    18. files.forEach((file) => {
    19. // 2.1 遍历所有文件,判断是文件夹还是文件
    20. const path = `${filepath}/${file}`;
    21. const fileStat = fs.statSync(path);
    22. // console.log(fileStat);
    23. if (fileStat.isDirectory()) {
    24. // 2.2 是文件夹,就得删除下面所有文件,才能删除文件夹
    25. this.removeFiles(fs, path);
    26. } else {
    27. // 2.3 是文件,直接删除
    28. fs.unlinkSync(path);
    29. }
    30. });
    31. }
    32. }
    33. module.exports = CleanWebpackPlugin;

    4、AnalyzeWebpackPlugin

    1. class AnalyzeWebpackPlugin {
    2. apply(compiler) {
    3. compiler.hooks.emit.tap("AnalyzeWebpackPlugin", (compilation) => {
    4. // 1. 遍历所有即将输出文件,得到其大小
    5. /*
    6. 将对象变成一个二维数组:
    7. 对象:
    8. {
    9. key1: value1,
    10. key2: value2
    11. }
    12. 二维数组:
    13. [
    14. [key1, value1],
    15. [key2, value2]
    16. ]
    17. */
    18. const assets = Object.entries(compilation.assets);
    19. /*
    20. md中表格语法:
    21. | 资源名称 | 资源大小 |
    22. | --- | --- |
    23. | xxx.js | 10kb |
    24. */
    25. let content = `| 资源名称 | 资源大小 |
    26. | --- | --- |`;
    27. assets.forEach(([filename, file]) => {
    28. content += `\n| ${filename} | ${Math.ceil(file.size() / 1024)}kb |`;
    29. });
    30. // 2. 生成一个md文件
    31. compilation.assets["analyze.md"] = {
    32. source() {
    33. return content;
    34. },
    35. size() {
    36. return content.length;
    37. },
    38. };
    39. });
    40. }
    41. }
    42. module.exports = AnalyzeWebpackPlugin;

    生成md文件

    5、InlineChunkWebpackPlugin

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

    1. const HtmlWebpackPlugin = require("safe-require")("html-webpack-plugin");
    2. class InlineChunkWebpackPlugin {
    3. constructor(tests) {
    4. this.tests = tests;
    5. }
    6. apply(compiler) {
    7. compiler.hooks.compilation.tap("InlineChunkWebpackPlugin", (compilation) => {
    8. // 1. 获取html-webpack-plugin的hooks
    9. const hooks = HtmlWebpackPlugin.getHooks(compilation);
    10. // 2. 注册 html-webpack-plugin的hooks -> alterAssetTagGroups
    11. hooks.alterAssetTagGroups.tap("InlineChunkWebpackPlugin", (assets) => {
    12. // 3. 从里面将script的runtime文件,变成inline script
    13. assets.headTags = this.getInlineChunk(assets.headTags, compilation.assets);
    14. assets.bodyTags = this.getInlineChunk(assets.bodyTags, compilation.assets);
    15. });
    16. // 删除runtime文件
    17. hooks.afterEmit.tap("InlineChunkWebpackPlugin", () => {
    18. // 3. 从里面将script的runtime文件,变成inline script
    19. Object.keys(compilation.assets).forEach((filepath) => {
    20. if (this.tests.some((test) => test.test(filepath))) {
    21. delete compilation.assets[filepath];
    22. }
    23. });
    24. });
    25. });
    26. }
    27. getInlineChunk(tags, assets) {
    28. /*
    29. 目前:[
    30. {
    31. tagName: 'script',
    32. voidTag: false,
    33. meta: { plugin: 'html-webpack-plugin' },
    34. attributes: { defer: true, type: undefined, src: 'js/runtime~main.js.js' }
    35. },
    36. ]
    37. 修改为:
    38. [
    39. {
    40. tagName: 'script',
    41. innerHTML: runtime文件的内容
    42. closeTag: true
    43. },
    44. ]
    45. */
    46. return tags.map((tag) => {
    47. if (tag.tagName !== "script") return tag;
    48. // 获取文件资源路径
    49. const filepath = tag.attributes.src;
    50. if (!filepath) return tag;
    51. if (!this.tests.some((test) => test.test(filepath))) return tag;
    52. return {
    53. tagName: "script",
    54. innerHTML: assets[filepath].source(),
    55. closeTag: true,
    56. };
    57. });
    58. }
    59. }
    60. module.exports = InlineChunkWebpackPlugin;

  • 相关阅读:
    2023-09-05力扣每日一题
    停车场系统、智慧城市停车、智慧社区、物业管理、新能源充电、人脸门禁 uniapp 系统源码
    Typescript:(一)基本使用
    Sql Server 数据库中的所有已定义的唯一约束 (列名称 合并过了)
    vue js 禁用控件一分钟,并显示倒计时
    CNCC2023
    七天入门node.js(04)
    pinia原理
    数据存储(非数据库版)
    python-json校验-jsonpath
  • 原文地址:https://blog.csdn.net/weixin_44832362/article/details/134561058