当前位置: 首页 > news >正文

首屏优化,webpack插件用于给html中js自动添加异步加载属性

因为要使用cheerio库,需要安装

npm安装
npm install cheerio --save-dev或使用 yarn安装
yarn add cheerio --dev

创建async-script-webpack-plugin.js

const cheerio = require('cheerio');class AsyncScriptWebpackPlugin {constructor(options = {}) {this.options = {// 默认添加 async 属性async: true,defer: false,// 可选:指定需要添加异步属性的脚本文件名或正则表达式include: [],exclude: [],...options};}apply(compiler) {// 监听 HTML 生成后的钩子compiler.hooks.compilation.tap('AsyncScriptWebpackPlugin', (compilation) => {// 检查是否存在 html-webpack-pluginconst HtmlWebpackPlugin = compiler.options.plugins.find((plugin) => plugin.constructor.name === 'HtmlWebpackPlugin');if (!HtmlWebpackPlugin) {console.warn('[AsyncScriptWebpackPlugin] 未检测到 HtmlWebpackPlugin,插件将不会生效');return;}// 注册钩子到 html-webpack-plugin 处理 HTML 之后if (compilation.hooks.htmlWebpackPluginAfterHtmlProcessing) {// 兼容旧版本 html-webpack-plugincompilation.hooks.htmlWebpackPluginAfterHtmlProcessing.tapAsync('AsyncScriptWebpackPlugin',(data, cb) => {data.html = this.processHtml(data.html);cb(null, data);});} else if (compilation.hooks.htmlWebpackPluginAlterAssetTags) {// 兼容新版本 html-webpack-plugincompilation.hooks.htmlWebpackPluginAlterAssetTags.tapAsync('AsyncScriptWebpackPlugin',(data, cb) => {data.body = this.processScripts(data.body);data.head = this.processScripts(data.head);cb(null, data);});}});}// 处理 HTML 字符串中的 script 标签processHtml(html) {const $ = cheerio.load(html);$('script').each((i, script) => {this.modifyScriptTag($, script);});return $.html();}// 处理 html-webpack-plugin 提供的 script 标签数组processScripts(scripts) {return scripts.map((script) => {if (script.tagName === 'script' && script.attributes && script.attributes.src) {const src = script.attributes.src;// 检查是否匹配包含/排除规则if (this.shouldProcessScript(src)) {if (this.options.async) script.attributes.async = true;if (this.options.defer) script.attributes.defer = true;}}return script;});}// 判断是否应该处理某个脚本shouldProcessScript(src) {const { include, exclude } = this.options;// 如果有排除规则且匹配,则不处理if (exclude.length > 0 && this.matchesAny(src, exclude)) {return false;}// 如果有包含规则且不匹配,则不处理if (include.length > 0 && !this.matchesAny(src, include)) {return false;}// 默认处理return true;}// 检查字符串是否匹配任何规则(字符串或正则)matchesAny(str, rules) {return rules.some((rule) => {if (typeof rule === 'string') {return str.includes(rule);}if (rule instanceof RegExp) {return rule.test(str);}return false;});}// 修改 script 标签modifyScriptTag($, script) {const $script = $(script);const src = $script.attr('src');// 如果没有 src 属性,可能是内联脚本,跳过if (!src) return;// 检查是否应该处理这个脚本if (!this.shouldProcessScript(src)) return;// 添加异步加载属性if (this.options.async) $script.attr('async', 'async');if (this.options.defer) $script.attr('defer', 'defer');}
}module.exports = AsyncScriptWebpackPlugin;    

使用方法

const AsyncScriptWebpackPlugin = require('./async-script-webpack-plugin');module.exports = {// 其他 Webpack 配置...plugins: [new AsyncScriptWebpackPlugin({// 可选配置:async: true,   // 添加 async 属性(默认)defer: false,  // 不添加 defer 属性include: [     // 只处理匹配的脚本/vendor\.js$/,'analytics.js'],exclude: [     // 排除匹配的脚本'critical.js']}),// 其他插件...]
};

相关文章:

  • .net 公共变量 线程安全
  • flutter 的 json序列化和反序列化
  • 【PostgreSQL数据分析实战:从数据清洗到可视化全流程】金融风控分析案例-10.1 风险数据清洗与特征工程
  • 【技巧】离线安装docker镜像的方法
  • Python中操作Neo4j图数据库
  • LeetCode热题100——链表
  • IBM BAW(原BPM升级版)使用教程第十二讲
  • HTML17:表单初级验证
  • js应用opencv
  • Scala和Spark的介绍
  • 深入浅出 iOS 对象模型:isa 指针 与 Swift Metadata
  • Spring Boot 使用Itext绘制并导出PDF
  • 创建三个网络,分别使用RIP、OSPF、静态,并每个网络10个电脑。使用DHCP分配IP
  • C++ 中介者模式详解
  • SAM论文学习
  • Windows系统安装VirtualBox-7及其以上的版本修改默认安装路径后提示
  • python标准库--heapq - 堆队列算法(优先队列)在算法比赛的应用
  • 【AI News | 20250512】每日AI进展
  • 使用Daemonset部署日志收集守护进程
  • 探索边缘计算:赋能物联网的未来
  • 周启鸣加盟同济大学,曾任香港浸会大学深圳研究院院长
  • 从这些电影与影像,看到包容开放的上海
  • 夜读丨取稿费的乐趣
  • 言短意长|西湖大学首次“走出西湖”
  • 中国目的地·入境游简报006|外国网红游中国启示录
  • 中美会谈前都发生了什么?美方为何坐不住了?