Skip to content

Commit

Permalink
fix: types
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-akait committed Sep 3, 2021
1 parent 91b1869 commit d7ea08f
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 229 deletions.
29 changes: 22 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -676,24 +676,39 @@ module.exports = {
With built-in minify functions:

```ts
import type { SwcMinifyFunction } from "terser-webpack-plugin";
import type { JsMinifyOptions as SwcOptions } from "@swc/core";
import type { MinifyOptions as UglifyJSOptions } from "uglify-js";
import type { TransformOptions as EsbuildOptions } from "esbuild";
import type { MinifyOptions as TerserOptions } from "terser";

module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin<SwcMinimizer>({
new TerserPlugin<SwcOptions>({
minify: TerserPlugin.swcMinify,
terserOptions: {
compress: true,
// `swc` options
},
}),
new TerserPlugin<UglifyJSOptions>({
minify: TerserPlugin.uglifyJsMinify,
terserOptions: {
// `uglif-js` options
},
}),
new TerserPlugin<EsbuildOptions>({
minify: TerserPlugin.esbuildMinify,
terserOptions: {
// `esbuild` options
},
}),

// Alternative:
new TerserPlugin<typeof TerserPlugin.swcMinify>({
minify: TerserPlugin.swcMinify,
// Alternative usage:
new TerserPlugin<TerserOptions>({
minify: TerserPlugin.terserMinify,
terserOptions: {
compress: true,
// `terser` options
},
}),
],
Expand Down
79 changes: 25 additions & 54 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,7 @@ import { minify as minimize } from "./minify";
/** @typedef {import("webpack").Asset} Asset */
/** @typedef {import("./utils.js").TerserECMA} TerserECMA */
/** @typedef {import("./utils.js").TerserOptions} TerserOptions */
/** @typedef {import("./utils.js").UglifyJSOptions} UglifyJSOptions */
/** @typedef {import("./utils.js").SwcOptions} SwcOptions */
/** @typedef {import("./utils.js").EsbuildOptions} EsbuildOptions */
/** @typedef {Object.<any, any>} CustomOptions */
/** @typedef {import("./utils.js").CustomOptions} CustomOptions */
/** @typedef {import("jest-worker").Worker} JestWorker */
/** @typedef {import("source-map").RawSourceMap} RawSourceMap */

Expand Down Expand Up @@ -81,14 +78,14 @@ import { minify as minimize } from "./minify";
/**
* @typedef {Object} PredefinedOptions
* @property {boolean} [module]
* @property {5 | 2015 | 2016 | 2017 | 2018 | 2019 | 2020 | number | string} [ecma]
* @property {any} [ecma]
*/

/**
* @template T
* @typedef {Object} MinimizerImplementationAndOptions
* @property {MinimizerImplementation<ThirdArgument<T>>} implementation
* @property {PredefinedOptions & ThirdArgument<T>} options
* @property {MinimizerImplementation<T>} implementation
* @property {PredefinedOptions & T} options
*/

/**
Expand Down Expand Up @@ -126,26 +123,6 @@ import { minify as minimize } from "./minify";
* @typedef {BasicMinimizerImplementation<T> & MinimizeFunctionHelpers } MinimizerImplementation
*/

/**
* @typedef {MinimizerImplementation<TerserOptions>} TerserMinimizer
*/

/**
* @typedef {MinimizerImplementation<UglifyJSOptions>} UglifyJSMinimizer
*/

/**
* @typedef {MinimizerImplementation<SwcOptions>} SwcMinimizer
*/

/**
* @typedef {MinimizerImplementation<EsbuildOptions>} EsbuildMinimizer
*/

/**
* @typedef {MinimizerImplementation<CustomOptions>} CustomMinimizer
*/

/**
* @typedef {Object} BasePluginOptions
* @property {Rules} [test]
Expand All @@ -157,56 +134,51 @@ import { minify as minimize } from "./minify";

/**
* @template T
* @typedef {T extends (arg1: any, arg2: any, arg3: infer U, ...args: any[]) => any ? U: never} ThirdArgument
* @typedef {T extends infer U ? U : CustomOptions} InferDefaultType
*/

/**
* @template T
* @typedef {Object} DefaultMinimizerImplementationAndOptions
* @property {undefined | MinimizerImplementation<ThirdArgument<T>>} [minify]
* @property {ThirdArgument<T> | undefined} [terserOptions]
* @typedef {InferDefaultType<T> extends TerserOptions ? { minify?: MinimizerImplementation<InferDefaultType<T>> | undefined, terserOptions?: InferDefaultType<T> | undefined } : { minify: MinimizerImplementation<InferDefaultType<T>>, terserOptions?: InferDefaultType<T> | undefined }} DefinedDefaultMinimizerAndOptions
*/

// TODO please add manually `T = TerserOptions`, because typescript is not supported default value for templates yet
/**
* @template T
* @typedef {T extends MinimizerImplementation<TerserOptions> ? DefaultMinimizerImplementationAndOptions<T> : { minify: MinimizerImplementation<ThirdArgument<T>>, terserOptions?: ThirdArgument<T> | undefined}} PickMinimizerImplementationAndOptions
*/

// TODO please add manually `T extends ... = TerserMinimizer`, because typescript is not supported default value for templates yet
/**
* @template {TerserMinimizer | UglifyJSMinimizer | SwcMinimizer | EsbuildMinimizer | CustomMinimizer} T=TerserMinimizer
*/
class TerserPlugin {
/**
* @param {BasePluginOptions & PickMinimizerImplementationAndOptions<T>} [options]
* @param {BasePluginOptions & DefinedDefaultMinimizerAndOptions<T>} [options]
*/
constructor(options) {
validate(/** @type {Schema} */ (schema), options || {}, {
name: "Terser Plugin",
baseDataPath: "options",
});

// TODO make `minimizer` option instead `minify` and `terserOptions` in the next major release, also rename `terserMinify` to `terserMinimize`
const {
minify = terserMinify,
terserOptions = {},
minify = /** @type {MinimizerImplementation<InferDefaultType<T>>} */ (
terserMinify
),
terserOptions = /** @type {InferDefaultType<T>} */ ({}),
test = /\.[cm]?js(\?.*)?$/i,
extractComments = true,
parallel = true,
include,
exclude,
} = options || {};

/**
* @type {BasePluginOptions & { minify: MinimizerImplementation<ThirdArgument<T>>, terserOptions: ThirdArgument<T>}}
*/
this.options = {
test,
extractComments,
parallel,
include,
exclude,
minify,
terserOptions,
minimizer: {
implementation: minify,
options: terserOptions,
},
};
}

Expand Down Expand Up @@ -494,17 +466,14 @@ class TerserPlugin {
input = input.toString();
}

/** @type {InternalOptions<T>} */
const options = {
name,
input,
inputSourceMap,
// TODO make `minimizer` option instead `minify` and `terserOptions` in the next major release, also rename `terserMinify` to `terserMinimize`
minimizer: {
implementation: this.options.minify,
options: {
...this.options.terserOptions,
},
implementation: this.options.minimizer.implementation,
// @ts-ignore https://github.com/Microsoft/TypeScript/issues/10727
options: { ...this.options.minimizer.options },
},
extractComments: this.options.extractComments,
};
Expand Down Expand Up @@ -865,10 +834,12 @@ class TerserPlugin {
);
const data = serialize({
minimizer:
typeof this.options.minify.getMinimizerVersion !== "undefined"
? this.options.minify.getMinimizerVersion() || "0.0.0"
typeof this.options.minimizer.implementation.getMinimizerVersion !==
"undefined"
? this.options.minimizer.implementation.getMinimizerVersion() ||
"0.0.0"
: "0.0.0",
options: this.options.terserOptions,
options: this.options.minimizer.options,
});

hooks.chunkHash.tap(pluginName, (chunk, hash) => {
Expand Down
1 change: 1 addition & 0 deletions src/minify.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/** @typedef {import("./index.js").MinimizedResult} MinimizedResult */
/** @typedef {import("./index.js").CustomOptions} CustomOptions */

/**
* @template T
Expand Down
75 changes: 31 additions & 44 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,6 @@
/** @typedef {import("terser").FormatOptions} TerserFormatOptions */
/** @typedef {import("terser").MinifyOptions} TerserOptions */
/** @typedef {import("terser").ECMA} TerserECMA */
// TODO do not forget to add `// @ts-ignore` on optional peer dependencies to avoid problem with `TS2307: Cannot find module 'module' or its corresponding type declarations.`
/** @typedef {import("uglify-js").OutputOptions} UglifyJSOutputOptions */
/** @typedef {import("uglify-js").MinifyOptions} UglifyJSOptions */
/** @typedef {import("@swc/core").JsMinifyOptions} SwcOptions */
/** @typedef {import("esbuild").TransformOptions} EsbuildOptions */
/** @typedef {import("./index.js").ExtractCommentsOptions} ExtractCommentsOptions */
/** @typedef {import("./index.js").ExtractCommentsFunction} ExtractCommentsFunction */
/** @typedef {import("./index.js").ExtractCommentsCondition} ExtractCommentsCondition */
Expand All @@ -15,15 +10,7 @@
/** @typedef {import("./index.js").PredefinedOptions} PredefinedOptions */

/**
* @typedef {TerserOptions & { sourceMap: undefined } & ({ output: TerserFormatOptions & { beautify: boolean } } | { format: TerserFormatOptions & { beautify: boolean } })} NormalizedTerserOptions
*/

/**
* @typedef {UglifyJSOptions & { sourceMap: undefined } & { output: UglifyJSOutputOptions & { beautify: boolean } }} NormalizedUglifyJSOptions
*/

/**
* @typedef {SwcOptions & { sourceMap: undefined }} NormalizedSwcOptions
* @typedef {{ [key: string]: any }} CustomOptions
*/

/**
Expand All @@ -34,7 +21,7 @@
/**
* @param {Input} input
* @param {RawSourceMap | undefined} sourceMap
* @param {PredefinedOptions & TerserOptions} minimizerOptions
* @param {PredefinedOptions & CustomOptions} minimizerOptions
* @param {ExtractCommentsOptions | undefined} extractComments
* @return {Promise<MinimizedResult>}
*/
Expand All @@ -55,7 +42,7 @@ async function terserMinify(
};

/**
* @param {NormalizedTerserOptions} terserOptions
* @param {TerserOptions & { sourceMap: undefined } & ({ output: TerserFormatOptions & { beautify: boolean } } | { format: TerserFormatOptions & { beautify: boolean } })} terserOptions
* @param {ExtractedComments} extractedComments
* @returns {ExtractCommentsFunction}
*/
Expand Down Expand Up @@ -171,8 +158,8 @@ async function terserMinify(
};

/**
* @param {TerserOptions} [terserOptions={}]
* @returns {NormalizedTerserOptions}
* @param {PredefinedOptions & TerserOptions} [terserOptions={}]
* @returns {TerserOptions & { sourceMap: undefined } & ({ output: TerserFormatOptions & { beautify: boolean } } | { format: TerserFormatOptions & { beautify: boolean } })}
*/
const buildTerserOptions = (terserOptions = {}) => {
// Need deep copy objects to avoid https://github.com/terser/terser/issues/366
Expand Down Expand Up @@ -265,7 +252,7 @@ terserMinify.getMinimizerVersion = () => {
/**
* @param {Input} input
* @param {RawSourceMap | undefined} sourceMap
* @param {PredefinedOptions & UglifyJSOptions} minimizerOptions
* @param {PredefinedOptions & CustomOptions} minimizerOptions
* @param {ExtractCommentsOptions | undefined} extractComments
* @return {Promise<MinimizedResult>}
*/
Expand All @@ -286,7 +273,7 @@ async function uglifyJsMinify(
};

/**
* @param {NormalizedUglifyJSOptions} uglifyJsOptions
* @param {import("uglify-js").MinifyOptions & { sourceMap: undefined } & { output: import("uglify-js").OutputOptions & { beautify: boolean }}} uglifyJsOptions
* @param {ExtractedComments} extractedComments
* @returns {ExtractCommentsFunction}
*/
Expand Down Expand Up @@ -394,10 +381,15 @@ async function uglifyJsMinify(
};

/**
* @param {UglifyJSOptions} [uglifyJsOptions={}]
* @returns {NormalizedUglifyJSOptions}
* @param {PredefinedOptions & import("uglify-js").MinifyOptions} [uglifyJsOptions={}]
* @returns {import("uglify-js").MinifyOptions & { sourceMap: undefined } & { output: import("uglify-js").OutputOptions & { beautify: boolean }}}
*/
const buildUglifyJsOptions = (uglifyJsOptions = {}) => {
// eslint-disable-next-line no-param-reassign
delete minimizerOptions.ecma;
// eslint-disable-next-line no-param-reassign
delete minimizerOptions.module;

// Need deep copy objects to avoid https://github.com/terser/terser/issues/366
return {
...uglifyJsOptions,
Expand Down Expand Up @@ -427,11 +419,6 @@ async function uglifyJsMinify(
// eslint-disable-next-line global-require, import/no-extraneous-dependencies
const { minify } = require("uglify-js");

// eslint-disable-next-line no-param-reassign
delete minimizerOptions.ecma;
// eslint-disable-next-line no-param-reassign
delete minimizerOptions.module;

// Copy `uglify-js` options
const uglifyJsOptions = buildUglifyJsOptions(minimizerOptions);

Expand Down Expand Up @@ -483,13 +470,13 @@ uglifyJsMinify.getMinimizerVersion = () => {
/**
* @param {Input} input
* @param {RawSourceMap | undefined} sourceMap
* @param {PredefinedOptions & SwcOptions} minimizerOptions
* @param {PredefinedOptions & CustomOptions} minimizerOptions
* @return {Promise<MinimizedResult>}
*/
async function swcMinify(input, sourceMap, minimizerOptions) {
/**
* @param {SwcOptions} [swcOptions={}]
* @returns {NormalizedSwcOptions}
* @param {PredefinedOptions & import("@swc/core").JsMinifyOptions} [swcOptions={}]
* @returns {import("@swc/core").JsMinifyOptions & { sourceMap: undefined }}
*/
const buildSwcOptions = (swcOptions = {}) => {
// Need deep copy objects to avoid https://github.com/terser/terser/issues/366
Expand Down Expand Up @@ -567,15 +554,26 @@ swcMinify.getMinimizerVersion = () => {
/**
* @param {Input} input
* @param {RawSourceMap | undefined} sourceMap
* @param {PredefinedOptions & EsbuildOptions} minimizerOptions
* @param {PredefinedOptions & CustomOptions} minimizerOptions
* @return {Promise<MinimizedResult>}
*/
async function esbuildMinify(input, sourceMap, minimizerOptions) {
/**
* @param {EsbuildOptions} [esbuildOptions={}]
* @returns {EsbuildOptions}
* @param {PredefinedOptions & import("esbuild").TransformOptions} [esbuildOptions={}]
* @returns {import("esbuild").TransformOptions}
*/
const buildEsbuildOptions = (esbuildOptions = {}) => {
// eslint-disable-next-line no-param-reassign
delete esbuildOptions.ecma;

if (esbuildOptions.module) {
// eslint-disable-next-line no-param-reassign
esbuildOptions.format = "esm";
}

// eslint-disable-next-line no-param-reassign
delete esbuildOptions.module;

// Need deep copy objects to avoid https://github.com/terser/terser/issues/366
return {
minify: true,
Expand All @@ -588,17 +586,6 @@ async function esbuildMinify(input, sourceMap, minimizerOptions) {
// eslint-disable-next-line import/no-extraneous-dependencies, global-require
const esbuild = require("esbuild");

// eslint-disable-next-line no-param-reassign
delete minimizerOptions.ecma;

if (minimizerOptions.module) {
// eslint-disable-next-line no-param-reassign
minimizerOptions.format = "esm";
}

// eslint-disable-next-line no-param-reassign
delete minimizerOptions.module;

// Copy `swc` options
const esbuildOptions = buildEsbuildOptions(minimizerOptions);

Expand Down
Loading

0 comments on commit d7ea08f

Please sign in to comment.