1+ import HtmlWebpackPlugin from "html-webpack-plugin" ;
2+ import Minimatch from 'minimatch' ;
3+
4+ const PLUGIN_NAME = 'HtmlWebpackExcludeScriptsPlugin' ;
5+
6+ export default class HtmlWebpackExcludeScriptsPlugin {
7+
8+
9+ /** @type {{skipAssets: Array<string|RegExp|Function>, excludeAssets: Array<string|RegExp|Function>} } */
10+ #config;
11+
12+
13+ /**
14+ * @param {{skipAssets: Array<string|RegExp|Function>, excludeAssets: Array<string|RegExp|Function>} } config
15+ */
16+ constructor ( config ) {
17+ this . #config = config ?? [ ] ;
18+ }
19+
20+
21+ apply ( compiler ) {
22+
23+ if ( compiler . hooks ) {
24+ // webpack 4 support
25+ compiler . hooks . compilation . tap ( PLUGIN_NAME , ( compilation ) => {
26+
27+ console . log ( 'WP4' ) ; // TMP
28+ if ( compilation . outputName === 'index.html' ) {
29+ console . log ( compilation ) ; // TMP
30+ // data.plugin.userOptions.chunks.forEach(c => console.log(c));
31+ }
32+
33+ // if (compilation.hooks.htmlWebpackPluginAlterAssetTags) {
34+ if ( compilation . hooks . htmlWebpackPluginAlterAssetTags ) {
35+ // html webpack 3
36+ console . log ( 'html webpack 3' ) ; // TMP
37+ compilation . hooks . beforeAssetTagGeneration . tapAsync ( PLUGIN_NAME , ( data , callback ) => {
38+ /** @type {Array<string|RegExp|Function> } */
39+ const filters = [
40+ ...( this . #config. skipAssets || [ ] ) ,
41+ ...( this . #config. excludeAssets || [ ] ) ,
42+ ...( data . plugin . options . skipAssets || [ ] ) ,
43+ ...( data . plugin . options . excludeAssets || [ ] ) ,
44+ ] ;
45+ data . head = this . #skipAssets( data . head , filters ) ;
46+ data . body = this . #skipAssets( data . body , filters ) ;
47+ return callback ( null , data ) ;
48+ } ) ;
49+ } else if ( HtmlWebpackPlugin && HtmlWebpackPlugin . getHooks ) {
50+ // html-webpack 4
51+ console . log ( 'html-webpack 4' ) ; // TMP
52+ const hooks = HtmlWebpackPlugin . getHooks ( compilation ) ;
53+ // hooks.alterAssetTags.tapAsync(PLUGIN_NAME, (data, callback) => {
54+ hooks . alterAssetTags . tapAsync ( PLUGIN_NAME , ( data , callback ) => {
55+ // console.log(data.outputName);
56+ if ( data . outputName === 'index.html' ) {
57+ console . log ( data ) ; // TMP
58+ // data.plugin.userOptions.chunks.forEach(c => console.log(c));
59+ }
60+ // data.assetTags.scripts.forEach(s => console.log(s));
61+ // /** @type {Array<string|RegExp|Function> } */
62+ // const filters = [
63+ // ...(this.#config.skipAssets || []),
64+ // ...(this.#config.excludeAssets || []),
65+ // ...(data.plugin['options'].skipAssets || []),
66+ // ...(data.plugin['options'].excludeAssets || []),
67+ // ];
68+ // data.assetTags.scripts = this.#skipAssets(data.assetTags.scripts, filters);
69+ // data.assetTags.styles = this.#skipAssets(data.assetTags.styles, filters);
70+ // data.assetTags.meta = this.#skipAssets(data.assetTags.meta, filters);
71+ // return callback(null, data);
72+ } ) ;
73+ } else {
74+ throw new Error ( 'Cannot find appropriate compilation hook' ) ;
75+ }
76+ } ) ;
77+
78+ } else {
79+ console . log ( 'WP5' ) ; // TMP
80+ // Hook into the html-webpack-plugin processing
81+ compiler . plugin ( 'compilation' , ( compilation ) => {
82+ compilation . plugin ( 'html-webpack-plugin-alter-asset-tags' , ( htmlPluginData , callback ) => {
83+ /** @type {Array<string|RegExp|Function> } */
84+ const filters = [
85+ ...( this . #config. skipAssets || [ ] ) ,
86+ ...( this . #config. excludeAssets || [ ] ) ,
87+ ...( htmlPluginData . plugin . options . skipAssets || [ ] ) ,
88+ ...( htmlPluginData . plugin . options . excludeAssets || [ ] ) ,
89+ ] ;
90+ htmlPluginData . head = this . #skipAssets( htmlPluginData . head , filters ) ;
91+ htmlPluginData . body = this . #skipAssets( htmlPluginData . body , filters ) ;
92+ return callback ( null , htmlPluginData ) ;
93+ } ) ;
94+ } ) ;
95+ }
96+
97+
98+ }
99+
100+ /**
101+ * @param {HtmlWebpackPlugin.HtmlTagObject[] } assets
102+ * @param {Array<string|RegExp|Function> } matchers
103+ * @returns {HtmlWebpackPlugin.HtmlTagObject[] }
104+ */
105+ #skipAssets( assets , matchers ) {
106+ return assets . filter ( ( asset ) => {
107+ const assetUrl = `${ ( asset . attributes . src ?? asset . attributes . href ?? '' ) } ` ;
108+ console . log ( 'assetUrl' , assetUrl ) ;
109+ const skipped = matchers . some ( ( matcher ) => {
110+ // if (!matcher) {
111+ // return false;
112+ // }
113+ // const assetUrl = `${(asset.attributes.src ?? asset.attributes.href ?? '')}`;
114+ // if (typeof matcher === 'string') {
115+ // return minimatch(assetUrl, matcher);
116+ // }
117+ // if (matcher.constructor && matcher.constructor.name === 'RegExp') {
118+ // /** @type {RegExp } */
119+ // const regexMatcher = matcher;
120+ // return !!(assetUrl.match(regexMatcher));
121+ // }
122+ // if (typeof matcher === 'function') {
123+ // const matchesCallback = matcher(asset);
124+ // return !!(matchesCallback);
125+ // }
126+ return false ;
127+ } ) ;
128+ return ! skipped ;
129+ } ) ;
130+ }
131+
132+ }
133+
134+ /**
135+ * @typedef {object } HtmlWebpackExcludeScriptsPluginFilters
136+ */
0 commit comments