Skip to content

Commit 8178b00

Browse files
feat: a generator names its file with a function too, and minify is typed as written
The public type said one function where the schema has taken a list or a descriptor since 5.10, and a filename function is what webpack's own getPath takes.
1 parent e9b566d commit 8178b00

6 files changed

Lines changed: 95 additions & 19 deletions

File tree

‎.changeset/generator-compression-options.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
"minimizer-webpack-plugin": minor
33
---
44

5-
Add `threshold`, `minRatio` and `relatedName` to an `asset` generator, let `deleteOriginalAssets` be a function and take the original file alone, and read `minify: []` as nothing to minify rather than `false`.
5+
Add `threshold`, `minRatio` and `relatedName` to an `asset` generator, let `deleteOriginalAssets` be a function and take the original file alone, take a `filename` function, read `minify: []` as nothing to minify rather than `false`, and type what `minify` has long accepted.

‎README.md‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,7 @@ interface minimizer {
340340
}
341341

342342
type minify = minifyFn | (minifyFn | minimizer)[] | minimizer;
343+
// An empty array is nothing to minify.
343344
```
344345

345346
Default: `MinimizerPlugin.terserMinify`
@@ -712,7 +713,7 @@ interface generator {
712713
implementation: generateFn;
713714
options?: Record<string, any>;
714715
type?: "import" | "asset";
715-
filename?: string;
716+
filename?: string | ((pathData: any) => string);
716717
filter?: (name: string) => boolean;
717718
deleteOriginalAssets?: boolean | ((name: string) => boolean);
718719
threshold?: number;
@@ -818,8 +819,9 @@ new MinimizerPlugin({
818819
implementation: MinimizerPlugin.sharpGenerate,
819820
options: { encodeOptions: { webp: {} } },
820821
type: "asset",
821-
// Optional. Without it the generator's own name for the result is used,
822-
// which for `sharpGenerate` is the original with its extension replaced.
822+
// Optional, a template or a function answering with one. Without it the
823+
// generator's own name for the result is used, which for `sharpGenerate`
824+
// is the original with its extension replaced.
823825
filename: "[path][name].webp",
824826
// Optional. Narrows what this generator reads, on top of `test`.
825827
filter: (name) => !name.includes("icons/"),

‎src/index.js‎

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ const {
211211
* @property {MinimizerImplementation<EXPECTED_ANY>} implementation the generator itself
212212
* @property {MinimizerOptions<EXPECTED_ANY>=} options options for this generator, preferred over the deprecated `generatorOptions`
213213
* @property {("import" | "asset")=} type `import` re-encodes a module as it is built, so the import that asked for it is renamed with it; `asset` writes a new file beside one already emitted
214-
* @property {string=} filename name for the generated asset, as a webpack filename template. `asset` generators only
214+
* @property {(string | ((pathData: EXPECTED_ANY) => string))=} filename name for the generated asset, as a webpack filename template or a function answering with one. `asset` generators only
215215
* @property {((name: string) => boolean)=} filter decides per asset whether to generate from it, on top of `test`/`include`/`exclude`
216216
* @property {(boolean | ((name: string) => boolean))=} deleteOriginalAssets removes the asset generated from, its own file alone — whatever its `related` names stays. Written as a function it is asked per asset. `asset` generators only
217217
* @property {number=} threshold generate only from assets larger than this, in bytes. `asset` generators only
@@ -237,8 +237,24 @@ const {
237237
*/
238238

239239
/**
240+
* One minimizer, written as an object stating how to run it.
240241
* @template T
241-
* @typedef {T extends import("terser").MinifyOptions ? { minify?: MinimizerImplementation<T> | undefined, minimizerOptions?: MinimizerOptions<T> | undefined, terserOptions?: MinimizerOptions<T> | undefined } : { minify: MinimizerImplementation<T>, minimizerOptions?: MinimizerOptions<T> | undefined, terserOptions?: MinimizerOptions<T> | undefined }} DefinedDefaultMinimizerAndOptions
242+
* @typedef {object} MinimizerDescriptor
243+
* @property {MinimizerImplementation<T>} implementation the minimizer itself
244+
* @property {MinimizerOptions<T>=} options options for this minimizer, preferred over the deprecated `minimizerOptions`
245+
* @property {((name: string, info: AssetInfo) => boolean | undefined)=} filter which assets this minimizer is offered, overriding a `filter` on the function itself
246+
*/
247+
248+
/**
249+
* What `minify` may be written as: one minimizer, a list of them — empty for
250+
* nothing to minify — or a descriptor.
251+
* @template T
252+
* @typedef {MinimizerImplementation<T> | (MinimizerImplementation<T> | MinimizerDescriptor<T>)[] | MinimizerDescriptor<T>} Minify
253+
*/
254+
255+
/**
256+
* @template T
257+
* @typedef {T extends import("terser").MinifyOptions ? { minify?: Minify<T> | undefined, minimizerOptions?: MinimizerOptions<T> | undefined, terserOptions?: MinimizerOptions<T> | undefined } : { minify: Minify<T>, minimizerOptions?: MinimizerOptions<T> | undefined, terserOptions?: MinimizerOptions<T> | undefined }} DefinedDefaultMinimizerAndOptions
242258
*/
243259

244260
/**
@@ -1355,7 +1371,7 @@ class MinimizerPlugin {
13551371
* @param {string | undefined} name the preset it is written under, where it has one
13561372
* @param {EXPECTED_ANY} entry what was written there
13571373
* @param {EXPECTED_ANY} declared what `generatorOptions` says for it
1358-
* @returns {{ name: string | undefined, implementation: EXPECTED_ANY, options: EXPECTED_ANY, type: string | undefined, filename: string | undefined, filter: ((name: string) => boolean) | undefined, deleteOriginalAssets: boolean | ((name: string) => boolean) | undefined, threshold: number | undefined, minRatio: number | undefined, relatedName: string | false | undefined }} the generator
1374+
* @returns {{ name: string | undefined, implementation: EXPECTED_ANY, options: EXPECTED_ANY, type: string | undefined, filename: string | ((pathData: EXPECTED_ANY) => string) | undefined, filter: ((name: string) => boolean) | undefined, deleteOriginalAssets: boolean | ((name: string) => boolean) | undefined, threshold: number | undefined, minRatio: number | undefined, relatedName: string | false | undefined }} the generator
13591375
*/
13601376
describeGenerator(name, entry, declared) {
13611377
const descriptor = isDescriptor(entry) ? entry : undefined;
@@ -2168,7 +2184,9 @@ class MinimizerPlugin {
21682184
const written = Array.isArray(minify) ? minify : [minify];
21692185

21702186
for (const [index, one] of written.entries()) {
2171-
const own = isDescriptor(one) ? one.options : undefined;
2187+
const own = isDescriptor(one)
2188+
? /** @type {MinimizerDescriptor<EXPECTED_ANY>} */ (one).options
2189+
: undefined;
21722190
const twice = Array.isArray(minify)
21732191
? getMinimizerOptionsAt(declared, index)
21742192
: declared;

‎src/options.json‎

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -276,9 +276,11 @@
276276
"enum": ["import", "asset"]
277277
},
278278
"filename": {
279-
"description": "Name for the generated asset, as a webpack filename template. `asset` generators only; by default the generator's own name for it is used.",
280-
"type": "string",
281-
"minLength": 1
279+
"description": "Name for the generated asset, as a webpack filename template, or a function answering with one. `asset` generators only; by default the generator's own name for it is used.",
280+
"anyOf": [
281+
{ "type": "string", "minLength": 1 },
282+
{ "instanceof": "Function" }
283+
]
282284
},
283285
"filter": {
284286
"description": "Decides per asset whether to generate from it, on top of `test`/`include`/`exclude`.",
@@ -346,9 +348,11 @@
346348
"enum": ["import", "asset"]
347349
},
348350
"filename": {
349-
"description": "Name for the generated asset, as a webpack filename template. `asset` generators only; by default the generator's own name for it is used.",
350-
"type": "string",
351-
"minLength": 1
351+
"description": "Name for the generated asset, as a webpack filename template, or a function answering with one. `asset` generators only; by default the generator's own name for it is used.",
352+
"anyOf": [
353+
{ "type": "string", "minLength": 1 },
354+
{ "instanceof": "Function" }
355+
]
352356
},
353357
"filter": {
354358
"description": "Decides per asset whether to generate from it, on top of `test`/`include`/`exclude`.",

‎test/generate-option.test.js‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2533,6 +2533,31 @@ describe("deleting the asset a file was written beside", () => {
25332533
]);
25342534
});
25352535

2536+
it("should take a `filename` function for the name it writes", async () => {
2537+
const compiler = getCompiler({
2538+
entry: { one: path.resolve(__dirname, "./fixtures/entry.js") },
2539+
});
2540+
2541+
new MinimizerPlugin({
2542+
parallel: false,
2543+
test: /\.js$/i,
2544+
minify: [],
2545+
generate: {
2546+
implementation: (input) => ({ code: Object.values(input)[0] }),
2547+
type: "asset",
2548+
filename: (pathData) => `${pathData.filename}.gz`,
2549+
},
2550+
}).apply(compiler);
2551+
2552+
const stats = await compile(compiler);
2553+
2554+
expect(getErrors(stats)).toEqual([]);
2555+
expect(Object.keys(stats.compilation.assets).sort()).toEqual([
2556+
"one.js",
2557+
"one.js.gz",
2558+
]);
2559+
});
2560+
25362561
it("should not point a file written under the original's name at itself", async () => {
25372562
const compiler = getCompiler({
25382563
entry: { one: path.resolve(__dirname, "./fixtures/entry.js") },

‎types/index.d.ts‎

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ declare class MinimizerPlugin<T = import("terser").MinifyOptions> {
9696
* @param {string | undefined} name the preset it is written under, where it has one
9797
* @param {EXPECTED_ANY} entry what was written there
9898
* @param {EXPECTED_ANY} declared what `generatorOptions` says for it
99-
* @returns {{ name: string | undefined, implementation: EXPECTED_ANY, options: EXPECTED_ANY, type: string | undefined, filename: string | undefined, filter: ((name: string) => boolean) | undefined, deleteOriginalAssets: boolean | ((name: string) => boolean) | undefined, threshold: number | undefined, minRatio: number | undefined, relatedName: string | false | undefined }} the generator
99+
* @returns {{ name: string | undefined, implementation: EXPECTED_ANY, options: EXPECTED_ANY, type: string | undefined, filename: string | ((pathData: EXPECTED_ANY) => string) | undefined, filter: ((name: string) => boolean) | undefined, deleteOriginalAssets: boolean | ((name: string) => boolean) | undefined, threshold: number | undefined, minRatio: number | undefined, relatedName: string | false | undefined }} the generator
100100
*/
101101
private describeGenerator;
102102
/**
@@ -315,6 +315,8 @@ declare namespace MinimizerPlugin {
315315
GeneratorDescriptor,
316316
Generate,
317317
BasePluginOptions,
318+
MinimizerDescriptor,
319+
Minify,
318320
DefinedDefaultMinimizerAndOptions,
319321
InternalPluginOptions,
320322
};
@@ -656,9 +658,9 @@ type GeneratorDescriptor = {
656658
*/
657659
type?: ("import" | "asset") | undefined;
658660
/**
659-
* name for the generated asset, as a webpack filename template. `asset` generators only
661+
* name for the generated asset, as a webpack filename template or a function answering with one. `asset` generators only
660662
*/
661-
filename?: string | undefined;
663+
filename?: (string | ((pathData: EXPECTED_ANY) => string)) | undefined;
662664
/**
663665
* decides per asset whether to generate from it, on top of `test`/`include`/`exclude`
664666
*/
@@ -724,15 +726,40 @@ type BasePluginOptions = {
724726
*/
725727
generatorOptions?: MinimizerOptions<EXPECTED_ANY> | undefined;
726728
};
729+
/**
730+
* One minimizer, written as an object stating how to run it.
731+
*/
732+
type MinimizerDescriptor<T> = {
733+
/**
734+
* the minimizer itself
735+
*/
736+
implementation: MinimizerImplementation<T>;
737+
/**
738+
* options for this minimizer, preferred over the deprecated `minimizerOptions`
739+
*/
740+
options?: MinimizerOptions<T> | undefined;
741+
/**
742+
* which assets this minimizer is offered, overriding a `filter` on the function itself
743+
*/
744+
filter?: ((name: string, info: AssetInfo) => boolean | undefined) | undefined;
745+
};
746+
/**
747+
* What `minify` may be written as: one minimizer, a list of them — empty for
748+
* nothing to minify — or a descriptor.
749+
*/
750+
type Minify<T> =
751+
| MinimizerImplementation<T>
752+
| (MinimizerImplementation<T> | MinimizerDescriptor<T>)[]
753+
| MinimizerDescriptor<T>;
727754
type DefinedDefaultMinimizerAndOptions<T> =
728755
T extends import("terser").MinifyOptions
729756
? {
730-
minify?: MinimizerImplementation<T> | undefined;
757+
minify?: Minify<T> | undefined;
731758
minimizerOptions?: MinimizerOptions<T> | undefined;
732759
terserOptions?: MinimizerOptions<T> | undefined;
733760
}
734761
: {
735-
minify: MinimizerImplementation<T>;
762+
minify: Minify<T>;
736763
minimizerOptions?: MinimizerOptions<T> | undefined;
737764
terserOptions?: MinimizerOptions<T> | undefined;
738765
};

0 commit comments

Comments
 (0)