@@ -11,9 +11,83 @@ import serialize from "serialize-javascript";
1111
1212import schema from "./options.json" ;
1313
14+ /** @typedef {import("schema-utils/declarations/validate").Schema } Schema */
15+ /** @typedef {import("webpack").Compiler } Compiler */
16+ /** @typedef {import("webpack").Compilation } Compilation */
17+ /** @typedef {import("webpack").sources.Source } Source */
18+ /** @typedef {import("webpack").Asset } Asset */
19+ /** @typedef {import("webpack").WebpackError } WebpackError */
20+
21+ /** @typedef {RegExp | string } Rule */
22+
23+ /** @typedef {Rule[] | Rule } Rules */
24+
25+ /**
26+ * @typedef {{ [key: string]: any } } CustomOptions
27+ */
28+
29+ /**
30+ * @template T
31+ * @typedef {T extends infer U ? U : CustomOptions } InferDefaultType
32+ */
33+
34+ /**
35+ * @template T
36+ * @typedef {InferDefaultType<T> } CompressionOptions
37+ */
38+
39+ /**
40+ * @template T
41+ * @callback AlgorithmFunction
42+ * @param {Buffer } input
43+ * @param {CompressionOptions<T> } options
44+ * @param {(error: Error, result: string | Buffer) => void } callback
45+ */
46+
47+ /**
48+ * @typedef {{[key: string]: any} } PathData
49+ */
50+
51+ /**
52+ * @typedef {string | ((fileData: PathData) => string) } Filename
53+ */
54+
55+ /**
56+ * @typedef {boolean | "keep-source-map" } DeleteOriginalAssets
57+ */
58+
59+ /**
60+ * @template T
61+ * @typedef {Object } BasePluginOptions
62+ * @property {Rules } [test]
63+ * @property {Rules } [include]
64+ * @property {Rules } [exclude]
65+ * @property {string | AlgorithmFunction<T> } [algorithm]
66+ * @property {CompressionOptions<T> } [compressionOptions]
67+ * @property {number } [threshold]
68+ * @property {number } [minRatio]
69+ * @property {DeleteOriginalAssets } [deleteOriginalAssets]
70+ * @property {Filename } [filename]
71+ */
72+
73+ /**
74+ * @template T
75+ * @typedef {BasePluginOptions<T> & { compressionOptions: CompressionOptions<T>, threshold: number, minRatio: number, deleteOriginalAssets: DeleteOriginalAssets, filename: Filename } } InternalPluginOptions
76+ */
77+
78+ /**
79+ * @typedef {import("zlib").ZlibOptions } ZlibOptions
80+ */
81+
82+ /**
83+ * @template [T=ZlibOptions]
84+ */
1485class CompressionPlugin {
86+ /**
87+ * @param {BasePluginOptions<T> } [options]
88+ */
1589 constructor ( options = { } ) {
16- validate ( schema , options , {
90+ validate ( /** @type { Schema } */ ( schema ) , options , {
1791 name : "Compression Plugin" ,
1892 baseDataPath : "options" ,
1993 } ) ;
@@ -23,13 +97,17 @@ class CompressionPlugin {
2397 include,
2498 exclude,
2599 algorithm = "gzip" ,
26- compressionOptions = { } ,
100+ compressionOptions = /** @type { CompressionOptions<T> } */ ( { } ) ,
27101 filename = "[path][base].gz" ,
28102 threshold = 0 ,
29103 minRatio = 0.8 ,
30104 deleteOriginalAssets = false ,
31105 } = options ;
32106
107+ /**
108+ * @private
109+ * @type {InternalPluginOptions<T> }
110+ */
33111 this . options = {
34112 test,
35113 include,
@@ -42,12 +120,25 @@ class CompressionPlugin {
42120 deleteOriginalAssets,
43121 } ;
44122
45- this . algorithm = this . options . algorithm ;
123+ /**
124+ * @private
125+ * @type {AlgorithmFunction<T> }
126+ */
127+ this . algorithm =
128+ /** @type {AlgorithmFunction<T> } */
129+ ( this . options . algorithm ) ;
46130
47131 if ( typeof this . algorithm === "string" ) {
132+ /**
133+ * @type {typeof import("zlib") }
134+ */
48135 // eslint-disable-next-line global-require
49136 const zlib = require ( "zlib" ) ;
50137
138+ /**
139+ * @private
140+ * @type {AlgorithmFunction<T> }
141+ */
51142 this . algorithm = zlib [ this . algorithm ] ;
52143
53144 if ( ! this . algorithm ) {
@@ -73,42 +164,62 @@ class CompressionPlugin {
73164 zlib . constants . BROTLI_MAX_QUALITY ,
74165 } ,
75166 } ,
76- } [ algorithm ] || { } ;
77-
78- this . options . compressionOptions = {
79- ...defaultCompressionOptions ,
80- ...this . options . compressionOptions ,
81- } ;
167+ } [ /** @type {string } */ ( algorithm ) ] || { } ;
168+
169+ this . options . compressionOptions =
170+ /**
171+ * @type {CompressionOptions<T> }
172+ */
173+ ( {
174+ .../** @type {object } */ ( defaultCompressionOptions ) ,
175+ .../** @type {object } */ ( this . options . compressionOptions ) ,
176+ } ) ;
82177 }
83178 }
84179
180+ /**
181+ * @private
182+ * @param {Buffer } input
183+ * @returns {Promise<Buffer> }
184+ */
85185 runCompressionAlgorithm ( input ) {
86186 return new Promise ( ( resolve , reject ) => {
87187 this . algorithm (
88188 input ,
89189 this . options . compressionOptions ,
90190 ( error , result ) => {
91191 if ( error ) {
92- return reject ( error ) ;
192+ reject ( error ) ;
193+
194+ return ;
93195 }
94196
95197 if ( ! Buffer . isBuffer ( result ) ) {
96198 // eslint-disable-next-line no-param-reassign
97199 result = Buffer . from ( result ) ;
98200 }
99201
100- return resolve ( result ) ;
202+ resolve ( result ) ;
101203 }
102204 ) ;
103205 } ) ;
104206 }
105207
208+ /**
209+ * @private
210+ * @param {Compiler } compiler
211+ * @param {Compilation } compilation
212+ * @param {Record<string, Source> } assets
213+ * @returns {Promise<void> }
214+ */
106215 async compress ( compiler , compilation , assets ) {
107216 const cache = compilation . getCache ( "CompressionWebpackPlugin" ) ;
108217 const assetsForMinify = (
109218 await Promise . all (
110219 Object . keys ( assets ) . map ( async ( name ) => {
111- const { info, source } = compilation . getAsset ( name ) ;
220+ const { info, source } = /** @type {Asset } */ (
221+ compilation . getAsset ( name )
222+ ) ;
112223
113224 if ( info . compressed ) {
114225 return false ;
@@ -124,6 +235,9 @@ class CompressionPlugin {
124235 return false ;
125236 }
126237
238+ /**
239+ * @type {string | undefined }
240+ */
127241 let relatedName ;
128242
129243 if ( typeof this . options . algorithm === "function" ) {
@@ -133,6 +247,9 @@ class CompressionPlugin {
133247 . update ( serialize ( this . options . filename ) )
134248 . digest ( "hex" ) } `;
135249 } else {
250+ /**
251+ * @type {string }
252+ */
136253 let filenameForRelatedName = this . options . filename ;
137254
138255 const index = filenameForRelatedName . indexOf ( "?" ) ;
@@ -202,6 +319,7 @@ class CompressionPlugin {
202319 for ( const asset of assetsForMinify ) {
203320 scheduledTasks . push (
204321 ( async ( ) => {
322+ // @ts -ignore
205323 const { name, source, buffer, output, cacheItem, info, relatedName } =
206324 asset ;
207325
@@ -210,7 +328,7 @@ class CompressionPlugin {
210328 try {
211329 output . compressed = await this . runCompressionAlgorithm ( buffer ) ;
212330 } catch ( error ) {
213- compilation . errors . push ( error ) ;
331+ compilation . errors . push ( /** @type { WebpackError } */ ( error ) ) ;
214332
215333 return ;
216334 }
@@ -235,16 +353,21 @@ class CompressionPlugin {
235353 } ) ;
236354 const newInfo = { compressed : true } ;
237355
356+ // TODO: possible problem when developer uses custom function, ideally we need to get parts of filname (i.e. name/base/ext/etc) in info
357+ // otherwise we can't detect an asset as immutable
238358 if (
239359 info . immutable &&
360+ typeof this . options . filename === "string" &&
240361 / ( \[ n a m e ] | \[ b a s e ] | \[ f i l e ] ) / . test ( this . options . filename )
241362 ) {
363+ // @ts -ignore
242364 newInfo . immutable = true ;
243365 }
244366
245367 if ( this . options . deleteOriginalAssets ) {
246368 if ( this . options . deleteOriginalAssets === "keep-source-map" ) {
247369 compilation . updateAsset ( name , source , {
370+ // @ts -ignore
248371 related : { sourceMap : null } ,
249372 } ) ;
250373 }
@@ -261,9 +384,13 @@ class CompressionPlugin {
261384 ) ;
262385 }
263386
264- return Promise . all ( scheduledTasks ) ;
387+ await Promise . all ( scheduledTasks ) ;
265388 }
266389
390+ /**
391+ * @param {Compiler } compiler
392+ * @returns {void }
393+ */
267394 apply ( compiler ) {
268395 const pluginName = this . constructor . name ;
269396
@@ -284,8 +411,11 @@ class CompressionPlugin {
284411 . tap (
285412 "compression-webpack-plugin" ,
286413 ( compressed , { green, formatFlag } ) =>
287- // eslint-disable-next-line no-undefined
288- compressed ? green ( formatFlag ( "compressed" ) ) : undefined
414+ compressed
415+ ? /** @type {Function } */ ( green ) (
416+ /** @type {Function } */ ( formatFlag ) ( "compressed" )
417+ )
418+ : ""
289419 ) ;
290420 } ) ;
291421 } ) ;
0 commit comments