| | |
| | | const schema = require("./options.json"); |
| | | const { |
| | | esbuildMinify, |
| | | jsonMinify, |
| | | memoize, |
| | | swcMinify, |
| | | terserMinify, |
| | |
| | | /** @typedef {import("webpack").Configuration} Configuration */ |
| | | /** @typedef {import("webpack").Asset} Asset */ |
| | | /** @typedef {import("webpack").AssetInfo} AssetInfo */ |
| | | /** @typedef {import("webpack").TemplatePath} TemplatePath */ |
| | | /** @typedef {import("jest-worker").Worker} JestWorker */ |
| | | /** @typedef {import("@jridgewell/trace-mapping").EncodedSourceMap & { sources: string[], sourcesContent?: string[], file: string }} RawSourceMap */ |
| | | /** @typedef {import("@jridgewell/trace-mapping").TraceMap} TraceMap */ |
| | |
| | | /** @typedef {RegExp | string} Rule */ |
| | | /** @typedef {Rule[] | Rule} Rules */ |
| | | |
| | | // eslint-disable-next-line jsdoc/no-restricted-syntax |
| | | // eslint-disable-next-line jsdoc/reject-any-type |
| | | /** @typedef {any} EXPECTED_ANY */ |
| | | |
| | | /** |
| | | * @callback ExtractCommentsFunction |
| | | * @param {any} astNode ast Node |
| | | * @param {{ value: string, type: 'comment1' | 'comment2' | 'comment3' | 'comment4', pos: number, line: number, col: number }} comment comment node |
| | | * @param {EXPECTED_ANY} astNode ast Node |
| | | * @param {{ value: string, type: "comment1" | "comment2" | "comment3" | "comment4", pos: number, line: number, col: number }} comment comment node |
| | | * @returns {boolean} true when need to extract comment, otherwise false |
| | | */ |
| | | |
| | | /** |
| | | * @typedef {boolean | 'all' | 'some' | RegExp | ExtractCommentsFunction} ExtractCommentsCondition |
| | | * @typedef {boolean | "all" | "some" | RegExp | ExtractCommentsFunction} ExtractCommentsCondition |
| | | */ |
| | | |
| | | // eslint-disable-next-line jsdoc/no-restricted-syntax |
| | | /** |
| | | * @typedef {string | ((fileData: any) => string)} ExtractCommentsFilename |
| | | * @typedef {TemplatePath} ExtractCommentsFilename |
| | | */ |
| | | |
| | | /** |
| | |
| | | * @typedef {object} MinimizedResult |
| | | * @property {string=} code code |
| | | * @property {RawSourceMap=} map source map |
| | | * @property {Array<Error | string>=} errors errors |
| | | * @property {Array<Error | string>=} warnings warnings |
| | | * @property {Array<string>=} extractedComments extracted comments |
| | | * @property {(Error | string)[]=} errors errors |
| | | * @property {(Error | string)[]=} warnings warnings |
| | | * @property {string[]=} extractedComments extracted comments |
| | | */ |
| | | |
| | | /** |
| | | * @typedef {{ [file: string]: string }} Input |
| | | */ |
| | | |
| | | // eslint-disable-next-line jsdoc/no-restricted-syntax |
| | | /** |
| | | * @typedef {{ [key: string]: any }} CustomOptions |
| | | * @typedef {{ [key: string]: EXPECTED_ANY }} CustomOptions |
| | | */ |
| | | |
| | | /** |
| | |
| | | * @typedef {object} MinimizeFunctionHelpers |
| | | * @property {() => string | undefined=} getMinimizerVersion function that returns version of minimizer |
| | | * @property {() => boolean | undefined=} supportsWorkerThreads true when minimizer support worker threads, otherwise false |
| | | * @property {() => boolean | undefined=} supportsWorker true when minimizer support worker, otherwise false |
| | | */ |
| | | |
| | | /** |
| | |
| | | */ |
| | | |
| | | const getTraceMapping = memoize(() => require("@jridgewell/trace-mapping")); |
| | | const getSerializeJavascript = memoize(() => require("serialize-javascript")); |
| | | const getSerializeJavascript = memoize(() => require("./serialize-javascript")); |
| | | |
| | | /** |
| | | * @template [T=import("terser").MinifyOptions] |
| | |
| | | * @param {BasePluginOptions & DefinedDefaultMinimizerAndOptions<T>=} options options |
| | | */ |
| | | constructor(options) { |
| | | validate( /** @type {Schema} */schema, options || {}, { |
| | | validate(/** @type {Schema} */schema, options || {}, { |
| | | name: "Terser Plugin", |
| | | baseDataPath: "options" |
| | | }); |
| | | |
| | | // TODO handle json and etc in the next major release |
| | | // TODO make `minimizer` option instead `minify` and `terserOptions` in the next major release, also rename `terserMinify` to `terserMinimize` |
| | | const { |
| | | minify = ( /** @type {MinimizerImplementation<T>} */terserMinify), |
| | | terserOptions = ( /** @type {MinimizerOptions<T>} */{}), |
| | | minify = (/** @type {MinimizerImplementation<T>} */terserMinify), |
| | | terserOptions = (/** @type {MinimizerOptions<T>} */{}), |
| | | test = /\.[cm]?js(\?.*)?$/i, |
| | | extractComments = true, |
| | | parallel = true, |
| | |
| | | builtError.file = file; |
| | | return builtError; |
| | | } |
| | | if ( /** @type {ErrorObject} */error.line) { |
| | | if (/** @type {ErrorObject} */error.line) { |
| | | const { |
| | | line, |
| | | column |
| | |
| | | let initializedWorker; |
| | | /** @type {undefined | number} */ |
| | | let numberOfWorkers; |
| | | if (optimizeOptions.availableNumberOfCores > 0) { |
| | | const needCreateWorker = optimizeOptions.availableNumberOfCores > 0 && (typeof this.options.minimizer.implementation.supportsWorker === "undefined" || typeof this.options.minimizer.implementation.supportsWorker === "function" && this.options.minimizer.implementation.supportsWorker()); |
| | | if (needCreateWorker) { |
| | | // Do not create unnecessary workers when the number of files is less than the available cores, it saves memory |
| | | numberOfWorkers = Math.min(numberOfAssets, optimizeOptions.availableNumberOfCores); |
| | | getWorker = () => { |
| | |
| | | RawSource |
| | | } = compiler.webpack.sources; |
| | | |
| | | /** @typedef {{ extractedCommentsSource : import("webpack").sources.RawSource, commentsFilename: string }} ExtractedCommentsInfo */ |
| | | /** @typedef {{ extractedCommentsSource: import("webpack").sources.RawSource, commentsFilename: string }} ExtractedCommentsInfo */ |
| | | /** @type {Map<string, ExtractedCommentsInfo>} */ |
| | | const allExtractedComments = new Map(); |
| | | const scheduledTasks = []; |
| | |
| | | output = await (getWorker ? getWorker().transform(getSerializeJavascript()(options)) : minify(options)); |
| | | } catch (error) { |
| | | const hasSourceMap = inputSourceMap && TerserPlugin.isSourceMap(inputSourceMap); |
| | | compilation.errors.push(TerserPlugin.buildError( /** @type {Error | ErrorObject | string} */ |
| | | error, name, hasSourceMap ? new (getTraceMapping().TraceMap)( /** @type {RawSourceMap} */ |
| | | compilation.errors.push(TerserPlugin.buildError(/** @type {Error | ErrorObject | string} */ |
| | | error, name, hasSourceMap ? new (getTraceMapping().TraceMap)(/** @type {RawSourceMap} */ |
| | | inputSourceMap) : undefined, hasSourceMap ? compilation.requestShortener : undefined)); |
| | | return; |
| | | } |
| | |
| | | * @param {Error | string} item an error |
| | | * @returns {Error} built error with extra info |
| | | */ |
| | | item => TerserPlugin.buildError(item, name, hasSourceMap ? new (getTraceMapping().TraceMap)( /** @type {RawSourceMap} */ |
| | | item => TerserPlugin.buildError(item, name, hasSourceMap ? new (getTraceMapping().TraceMap)(/** @type {RawSourceMap} */ |
| | | inputSourceMap) : undefined, hasSourceMap ? compilation.requestShortener : undefined)); |
| | | } |
| | | |
| | | // Custom functions can return `undefined` or `null` |
| | | if (typeof output.code !== "undefined" && output.code !== null) { |
| | | let shebang; |
| | | if ( /** @type {ExtractCommentsObject} */ |
| | | if (/** @type {ExtractCommentsObject} */ |
| | | this.options.extractComments.banner !== false && output.extractedComments && output.extractedComments.length > 0 && output.code.startsWith("#!")) { |
| | | const firstNewlinePosition = output.code.indexOf("\n"); |
| | | shebang = output.code.slice(0, Math.max(0, firstNewlinePosition)); |
| | |
| | | let banner; |
| | | |
| | | // Add a banner to the original file |
| | | if ( /** @type {ExtractCommentsObject} */ |
| | | if (/** @type {ExtractCommentsObject} */ |
| | | this.options.extractComments.banner !== false) { |
| | | banner = /** @type {ExtractCommentsObject} */ |
| | | this.options.extractComments.banner || `For license information please see ${path.relative(path.dirname(name), output.commentsFilename).replace(/\\/g, "/")}`; |
| | |
| | | compilation.updateAsset(name, source, newInfo); |
| | | }); |
| | | } |
| | | const limit = getWorker && numberOfAssets > 0 ? ( /** @type {number} */numberOfWorkers) : scheduledTasks.length; |
| | | const limit = getWorker && numberOfAssets > 0 ? (/** @type {number} */numberOfWorkers) : scheduledTasks.length; |
| | | await throttleAll(limit, scheduledTasks); |
| | | if (initializedWorker) { |
| | | await initializedWorker.end(); |
| | |
| | | stats.hooks.print.for("asset.info.minimized").tap("terser-webpack-plugin", (minimized, { |
| | | green, |
| | | formatFlag |
| | | }) => minimized ? /** @type {(text: string) => string} */green( /** @type {(flag: string) => string} */formatFlag("minimized")) : ""); |
| | | }) => minimized ? /** @type {(text: string) => string} */green(/** @type {(flag: string) => string} */formatFlag("minimized")) : ""); |
| | | }); |
| | | }); |
| | | } |
| | |
| | | TerserPlugin.uglifyJsMinify = uglifyJsMinify; |
| | | TerserPlugin.swcMinify = swcMinify; |
| | | TerserPlugin.esbuildMinify = esbuildMinify; |
| | | TerserPlugin.jsonMinify = jsonMinify; |
| | | module.exports = TerserPlugin; |