因为要使用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: true,defer: false,include: [],exclude: [],...options};}apply(compiler) {compiler.hooks.compilation.tap('AsyncScriptWebpackPlugin', (compilation) => {const HtmlWebpackPlugin = compiler.options.plugins.find((plugin) => plugin.constructor.name === 'HtmlWebpackPlugin');if (!HtmlWebpackPlugin) {console.warn('[AsyncScriptWebpackPlugin] 未检测到 HtmlWebpackPlugin,插件将不会生效');return;}if (compilation.hooks.htmlWebpackPluginAfterHtmlProcessing) {compilation.hooks.htmlWebpackPluginAfterHtmlProcessing.tapAsync('AsyncScriptWebpackPlugin',(data, cb) => {data.html = this.processHtml(data.html);cb(null, data);});} else if (compilation.hooks.htmlWebpackPluginAlterAssetTags) {compilation.hooks.htmlWebpackPluginAlterAssetTags.tapAsync('AsyncScriptWebpackPlugin',(data, cb) => {data.body = this.processScripts(data.body);data.head = this.processScripts(data.head);cb(null, data);});}});}processHtml(html) {const $ = cheerio.load(html);$('script').each((i, script) => {this.modifyScriptTag($, script);});return $.html();}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;});}modifyScriptTag($, script) {const $script = $(script);const src = $script.attr('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 = {plugins: [new AsyncScriptWebpackPlugin({async: true, defer: false, include: [ /vendor\.js$/,'analytics.js'],exclude: [ 'critical.js']}),]
};