Webpack插件开发小技巧汇总~ 持续更新中

352 阅读1分钟

前言

由于经常研究webpack的一些插件原理,特别整理了其中使用到的hooks,后面会持续更新~

一、AST操作

1. 获取import或require依赖

compiler.hooks.normalModuleFactory.tap('demo', (normalModuleFactory) => {
  normalModuleFactory.hooks.parser.for('javascript/auto').tap('demo', (parser) => {
    parser.hooks.import.tap('demo', (statement, source) => {
      // statement: ImportDeclaration节点
      // source 引用的模块
    })
    parser.hooks.call.for('require').tap('demo', (statement) => {
      // statement: CallExpression 调用表达式节点
    })
  })
})

二、模块操作

1. 自定义模块工厂

注意:factorize钩子是webpack5新增的

normalModuleFactory.hooks.factorize.tapAsync('AutoExternalPlugin', (resolveData, callback) => {
  const { request } = resolveData
  // 当请求的模块是jquery  使用ExternalModule 创建模块
  if (request === 'jquery') {
    callback(null, new ExternalModule('$', 'window', 'jquery'))
  } else {
    callback(null)
  }
})

最后生成如下代码

{
"jquery": ((module) => {
    "use strict";
    module.exports = window["$"];
  })
}

2. 获取三方模块的package.json内容

compiler.hooks.compilation.tap(
  "demo",
  (compilation, { normalModuleFactory }) => {
    normalModuleFactory.hooks.module.tap(
      "demo",
      (module, data) => {
        const resolveData = data.resourceResolveData;
        if (
          resolveData &&
          resolveData.descriptionFileData
        ) {
          const pkg = resolveData.descriptionFileData;
          // 获取到package.json内容
        }
        return module;
      }
    );
  }
)

三、操作index.htmk

1. 插入标签

htmlData包含assetTags可自定义最终要生成的脚本或css文件

compiler.hooks.compilation.tap('demo', (compilation) => {
  HtmlWebpackPlugin.getHooks(compilation).alterAssetTags.tap(
    'demo',
    (htmlData) => {
      // assetTags: { scripts: [], styles: [], meta: [] }
      const assetTags = htmlData.assetTags;
      return htmlData;
    }
  );
});

assetTags结构如下

assetTags: {
  scripts: [
    {
      tagName: 'script',
      voidTag: false,
      meta: { plugin: 'html-webpack-plugin' },
      attributes: { defer: true, type: undefined, src: 'main.js' }
    }
  ],
  styles: [],
  meta: []
}

2. 生成资源标签前的回调

compiler.hooks.compilation.tap('PreloadWebpackPlugin', (compilation) => {
  // 在准备生成资源标签之前执行
  HtmlWebpackPlugin.getHooks(compilation).beforeAssetTagGeneration.tapAsync('demo', (htmlData, callback) => {
    // 正常callback就好
    callback()
  })
})