当前位置: 首页 > 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']}),// 其他插件...]
};
http://www.xdnf.cn/news/399421.html

相关文章:

  • Linux操作系统从入门到实战(六)Linux开发工具(上)详细介绍什么是软件包管理器,Linux下如何进行软件和软件包的安装、升级与卸载
  • 探索边缘计算:赋能物联网的未来
  • 一.Gitee基本操作
  • 2025年阿里云ACP人工智能高级工程师认证模拟试题(附答案解析)
  • Vue:插值表达
  • 如何在 Bash 中使用 =~ 操作符 ?
  • 单词短语0512
  • C++色彩博弈的史诗:红黑树
  • 关于大语言模型的困惑度(PPL)指标优势与劣势
  • 菊厂0510面试手撕题目解答
  • spdlog日志格式化 标志全指南
  • Java详解LeetCode 热题 100(14):LeetCode 56. 合并区间(Merge Intervals)详解
  • 【网络安全】SQL注入
  • pdf 不是扫描件,但却无法搜索关键词【问题尝试解决未果记录】
  • 用短说社区搭建的沉浸式生活方式分享平台
  • Redis+Caffeine构建高性能二级缓存
  • Python邮件处理(使用imaplib和email库实现自动化邮件处理)
  • Kubernetes控制平面组件:Kubelet详解(一):API接口层介绍
  • 自主添加删除开机启动项
  • tinyint(3)数据类型讲解
  • stm32之BKP备份寄存器和RTC时钟
  • 基于Python的高效批量处理Splunk Session ID并写入MySQL的解决方案
  • Hadoop 的代理用户(Proxy User)​ 功能解释
  • 配置hosts
  • 推理加速新范式:火山引擎高性能分布式 KVCache (EIC)核心技术解读
  • 深入理解Embedding Models(嵌入模型):从原理到实战(下)
  • 【机器人】复现 UniGoal 具身导航 | 通用零样本目标导航 CVPR 2025
  • SpringBoot校园失物招领信息平台
  • Shell脚本编程3(函数+正则表达式)
  • [特殊字符] 本地大模型编程实战(29):用大语言模型LLM查询图数据库NEO4J(2)