Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 02d9b2a

Browse files
feat: added types (#269)
1 parent 671337d commit 02d9b2a

File tree

8 files changed

+322
-28
lines changed

8 files changed

+322
-28
lines changed

package-lock.json

+14
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+8-2
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,14 @@
1919
"start": "npm run build -- -w",
2020
"clean": "del-cli dist",
2121
"prebuild": "npm run clean",
22-
"build": "cross-env NODE_ENV=production babel src -d dist --copy-files",
22+
"build:types": "tsc --declaration --emitDeclarationOnly --outDir types && prettier \"types/**/*.ts\" --write && prettier types --write",
23+
"build:code": "cross-env NODE_ENV=production babel src -d dist --copy-files",
24+
"build": "npm-run-all -p \"build:**\"",
2325
"commitlint": "commitlint --from=master",
2426
"security": "npm audit --production",
2527
"lint:prettier": "prettier --list-different .",
2628
"lint:js": "eslint --cache .",
29+
"lint:types": "tsc --pretty --noEmit",
2730
"lint": "npm-run-all -l -p \"lint:**\"",
2831
"test:only": "cross-env NODE_ENV=test jest",
2932
"test:watch": "npm run test:only -- --watch",
@@ -34,7 +37,8 @@
3437
"release": "standard-version"
3538
},
3639
"files": [
37-
"dist"
40+
"dist",
41+
"types"
3842
],
3943
"peerDependencies": {
4044
"webpack": "^5.1.0"
@@ -50,6 +54,7 @@
5054
"@commitlint/cli": "^15.0.0",
5155
"@commitlint/config-conventional": "^15.0.0",
5256
"@gfx/zopfli": "^1.0.15",
57+
"@types/serialize-javascript": "^5.0.1",
5358
"@webpack-contrib/eslint-config-webpack": "^3.0.0",
5459
"babel-jest": "^27.0.6",
5560
"cross-env": "^7.0.3",
@@ -66,6 +71,7 @@
6671
"npm-run-all": "^4.1.5",
6772
"prettier": "^2.3.2",
6873
"standard-version": "^9.3.0",
74+
"typescript": "^4.5.2",
6975
"webpack": "^5.51.0",
7076
"webpack-stats-plugin": "^1.0.3",
7177
"workbox-webpack-plugin": "^6.2.4"

src/index.js

+146-16
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,83 @@ import serialize from "serialize-javascript";
1111

1212
import 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+
*/
1485
class 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
/(\[name]|\[base]|\[file])/.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
});

src/options.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{
2+
"type": "object",
23
"additionalProperties": false,
34
"definitions": {
45
"Rule": {
@@ -114,6 +115,5 @@
114115
}
115116
]
116117
}
117-
},
118-
"type": "object"
118+
}
119119
}

0 commit comments

Comments
 (0)