source: trip-planner-front/node_modules/terser-webpack-plugin/dist/index.js@ 6a3a178

Last change on this file since 6a3a178 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 20.3 KB
Line 
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.default = void 0;
7
8var path = _interopRequireWildcard(require("path"));
9
10var os = _interopRequireWildcard(require("os"));
11
12var _sourceMap = require("source-map");
13
14var _schemaUtils = require("schema-utils");
15
16var _serializeJavascript = _interopRequireDefault(require("serialize-javascript"));
17
18var terserPackageJson = _interopRequireWildcard(require("terser/package.json"));
19
20var _pLimit = _interopRequireDefault(require("p-limit"));
21
22var _jestWorker = require("jest-worker");
23
24var schema = _interopRequireWildcard(require("./options.json"));
25
26var _minify = require("./minify");
27
28function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
29
30function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
31
32function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
33
34/** @typedef {import("schema-utils/declarations/validate").Schema} Schema */
35
36/** @typedef {import("webpack").Compiler} Compiler */
37
38/** @typedef {import("webpack").Compilation} Compilation */
39
40/** @typedef {import("webpack").WebpackError} WebpackError */
41
42/** @typedef {import("webpack").Asset} Asset */
43
44/** @typedef {import("terser").ECMA} TerserECMA */
45
46/** @typedef {import("terser").MinifyOptions} TerserMinifyOptions */
47
48/** @typedef {import("jest-worker").Worker} JestWorker */
49
50/** @typedef {import("source-map").RawSourceMap} RawSourceMap */
51
52/** @typedef {import("./minify.js").InternalMinifyOptions} InternalMinifyOptions */
53
54/** @typedef {import("./minify.js").InternalMinifyResult} InternalMinifyResult */
55
56/** @typedef {import("./minify.js").CustomMinifyOptions} CustomMinifyOptions */
57
58/** @typedef {RegExp | string} Rule */
59
60/** @typedef {Rule[] | Rule} Rules */
61
62/** @typedef {JestWorker & { transform: (options: string) => InternalMinifyResult, minify: (options: InternalMinifyOptions) => InternalMinifyResult }} MinifyWorker */
63
64/**
65 * @callback ExtractCommentsFunction
66 * @param {any} astNode
67 * @param {{ value: string, type: 'comment1' | 'comment2' | 'comment3' | 'comment4', pos: number, line: number, col: number }} comment
68 * @returns {boolean}
69 */
70
71/**
72 * @typedef {boolean | string | RegExp | ExtractCommentsFunction} ExtractCommentsCondition
73 */
74
75/**
76 * @typedef {string | ((fileData: any) => string)} ExtractCommentsFilename
77 */
78
79/**
80 * @typedef {boolean | string | ((commentsFile: string) => string)} ExtractCommentsBanner
81 */
82
83/**
84 * @typedef {Object} ExtractCommentsObject
85 * @property {ExtractCommentsCondition} condition
86 * @property {ExtractCommentsFilename} filename
87 * @property {ExtractCommentsBanner} banner
88 */
89
90/**
91 * @callback CustomMinifyFunction
92 * @param {{ [file: string]: string }} fileAndCode
93 * @param {RawSourceMap} [sourceMap]
94 * @param {Object.<any, any>} minifyOptions
95 */
96
97/**
98 * @typedef {ExtractCommentsCondition | ExtractCommentsObject} ExtractCommentsOptions
99 */
100
101/**
102 * @typedef {Object} PluginWithTerserOptions
103 * @property {Rules} [test]
104 * @property {Rules} [include]
105 * @property {Rules} [exclude]
106 * @property {TerserMinifyOptions} [terserOptions]
107 * @property {ExtractCommentsOptions} [extractComments]
108 * @property {boolean} [parallel]
109 * @property {CustomMinifyFunction} [minify]
110 */
111
112/**
113 * @typedef {Object} PluginWithCustomMinifyOptions
114 * @property {Rules} [test]
115 * @property {Rules} [include]
116 * @property {Rules} [exclude]
117 * @property {Object.<any, any>} [terserOptions]
118 * @property {ExtractCommentsOptions} [extractComments]
119 * @property {boolean} [parallel]
120 * @property {CustomMinifyFunction} [minify]
121 */
122
123/**
124 * @typedef {PluginWithTerserOptions | PluginWithCustomMinifyOptions} TerserPluginOptions
125 */
126class TerserPlugin {
127 /**
128 * @param {TerserPluginOptions} options
129 */
130 constructor(options = {}) {
131 (0, _schemaUtils.validate)(
132 /** @type {Schema} */
133 schema, options, {
134 name: "Terser Plugin",
135 baseDataPath: "options"
136 });
137 const {
138 minify,
139 terserOptions = {},
140 test = /\.[cm]?js(\?.*)?$/i,
141 extractComments = true,
142 parallel = true,
143 include,
144 exclude
145 } = options;
146 this.options = {
147 test,
148 extractComments,
149 parallel,
150 include,
151 exclude,
152 minify,
153 terserOptions
154 };
155 }
156 /**
157 * @private
158 * @param {any} input
159 * @returns {boolean}
160 */
161
162
163 static isSourceMap(input) {
164 // All required options for `new SourceMapConsumer(...options)`
165 // https://github.com/mozilla/source-map#new-sourcemapconsumerrawsourcemap
166 return Boolean(input && input.version && input.sources && Array.isArray(input.sources) && typeof input.mappings === "string");
167 }
168 /**
169 * @private
170 * @param {Error & { line: number, col: number}} error
171 * @param {string} file
172 * @param {Compilation["requestShortener"]} [requestShortener]
173 * @param {SourceMapConsumer} [sourceMap]
174 * @returns {Error}
175 */
176
177
178 static buildError(error, file, requestShortener, sourceMap) {
179 if (error.line) {
180 const original = sourceMap && sourceMap.originalPositionFor({
181 line: error.line,
182 column: error.col
183 });
184
185 if (original && original.source && requestShortener) {
186 return new Error(`${file} from Terser\n${error.message} [${requestShortener.shorten(original.source)}:${original.line},${original.column}][${file}:${error.line},${error.col}]${error.stack ? `\n${error.stack.split("\n").slice(1).join("\n")}` : ""}`);
187 }
188
189 return new Error(`${file} from Terser\n${error.message} [${file}:${error.line},${error.col}]${error.stack ? `\n${error.stack.split("\n").slice(1).join("\n")}` : ""}`);
190 }
191
192 if (error.stack) {
193 return new Error(`${file} from Terser\n${error.stack}`);
194 }
195
196 return new Error(`${file} from Terser\n${error.message}`);
197 }
198 /**
199 * @private
200 * @param {boolean} parallel
201 * @returns {number}
202 */
203
204
205 static getAvailableNumberOfCores(parallel) {
206 // In some cases cpus() returns undefined
207 // https://github.com/nodejs/node/issues/19022
208 const cpus = os.cpus() || {
209 length: 1
210 };
211 return parallel === true ? cpus.length - 1 : Math.min(Number(parallel) || 0, cpus.length - 1);
212 }
213 /**
214 * @param {Compiler} compiler
215 * @param {Compilation} compilation
216 * @param {Record<string, import("webpack").sources.Source>} assets
217 * @param {{availableNumberOfCores: number}} optimizeOptions
218 * @returns {Promise<void>}
219 */
220
221
222 async optimize(compiler, compilation, assets, optimizeOptions) {
223 const cache = compilation.getCache("TerserWebpackPlugin");
224 let numberOfAssetsForMinify = 0;
225 const assetsForMinify = await Promise.all(Object.keys(assets).filter(name => {
226 const {
227 info
228 } =
229 /** @type {Asset} */
230 compilation.getAsset(name);
231
232 if ( // Skip double minimize assets from child compilation
233 info.minimized || // Skip minimizing for extracted comments assets
234 info.extractedComments) {
235 return false;
236 }
237
238 if (!compiler.webpack.ModuleFilenameHelpers.matchObject.bind( // eslint-disable-next-line no-undefined
239 undefined, this.options)(name)) {
240 return false;
241 }
242
243 return true;
244 }).map(async name => {
245 const {
246 info,
247 source
248 } =
249 /** @type {Asset} */
250 compilation.getAsset(name);
251 const eTag = cache.getLazyHashedEtag(source);
252 const cacheItem = cache.getItemCache(name, eTag);
253 const output = await cacheItem.getPromise();
254
255 if (!output) {
256 numberOfAssetsForMinify += 1;
257 }
258
259 return {
260 name,
261 info,
262 inputSource: source,
263 output,
264 cacheItem
265 };
266 }));
267 /** @type {undefined | (() => MinifyWorker)} */
268
269 let getWorker;
270 /** @type {undefined | MinifyWorker} */
271
272 let initializedWorker;
273 /** @type {undefined | number} */
274
275 let numberOfWorkers;
276
277 if (optimizeOptions.availableNumberOfCores > 0) {
278 // Do not create unnecessary workers when the number of files is less than the available cores, it saves memory
279 numberOfWorkers = Math.min(numberOfAssetsForMinify, optimizeOptions.availableNumberOfCores); // eslint-disable-next-line consistent-return
280
281 getWorker = () => {
282 if (initializedWorker) {
283 return initializedWorker;
284 }
285
286 initializedWorker =
287 /** @type {MinifyWorker} */
288 new _jestWorker.Worker(require.resolve("./minify"), {
289 numWorkers: numberOfWorkers,
290 enableWorkerThreads: true
291 }); // https://github.com/facebook/jest/issues/8872#issuecomment-524822081
292
293 const workerStdout = initializedWorker.getStdout();
294
295 if (workerStdout) {
296 workerStdout.on("data", chunk => process.stdout.write(chunk));
297 }
298
299 const workerStderr = initializedWorker.getStderr();
300
301 if (workerStderr) {
302 workerStderr.on("data", chunk => process.stderr.write(chunk));
303 }
304
305 return initializedWorker;
306 };
307 }
308
309 const limit = (0, _pLimit.default)(getWorker && numberOfAssetsForMinify > 0 ?
310 /** @type {number} */
311 numberOfWorkers : Infinity);
312 const {
313 SourceMapSource,
314 ConcatSource,
315 RawSource
316 } = compiler.webpack.sources;
317 /** @typedef {{ extractedCommentsSource : import("webpack").sources.RawSource, commentsFilename: string }} ExtractedCommentsInfo */
318
319 /** @type {Map<string, ExtractedCommentsInfo>} */
320
321 const allExtractedComments = new Map();
322 const scheduledTasks = [];
323
324 for (const asset of assetsForMinify) {
325 scheduledTasks.push(limit(async () => {
326 const {
327 name,
328 inputSource,
329 info,
330 cacheItem
331 } = asset;
332 let {
333 output
334 } = asset;
335
336 if (!output) {
337 let input;
338 /** @type {RawSourceMap | undefined} */
339
340 let inputSourceMap;
341 const {
342 source: sourceFromInputSource,
343 map
344 } = inputSource.sourceAndMap();
345 input = sourceFromInputSource;
346
347 if (map) {
348 if (TerserPlugin.isSourceMap(map)) {
349 inputSourceMap =
350 /** @type {RawSourceMap} */
351 map;
352 } else {
353 inputSourceMap =
354 /** @type {RawSourceMap} */
355 map;
356 compilation.warnings.push(
357 /** @type {WebpackError} */
358 new Error(`${name} contains invalid source map`));
359 }
360 }
361
362 if (Buffer.isBuffer(input)) {
363 input = input.toString();
364 }
365 /** @type {InternalMinifyOptions} */
366
367
368 const options = {
369 name,
370 input,
371 inputSourceMap,
372 minify: this.options.minify,
373 minifyOptions: { ...this.options.terserOptions
374 },
375 extractComments: this.options.extractComments
376 };
377
378 if (typeof options.minifyOptions.module === "undefined") {
379 if (typeof info.javascriptModule !== "undefined") {
380 options.minifyOptions.module = info.javascriptModule;
381 } else if (/\.mjs(\?.*)?$/i.test(name)) {
382 options.minifyOptions.module = true;
383 } else if (/\.cjs(\?.*)?$/i.test(name)) {
384 options.minifyOptions.module = false;
385 }
386 }
387
388 try {
389 output = await (getWorker ? getWorker().transform((0, _serializeJavascript.default)(options)) : (0, _minify.minify)(options));
390 } catch (error) {
391 const hasSourceMap = inputSourceMap && TerserPlugin.isSourceMap(inputSourceMap);
392 compilation.errors.push(
393 /** @type {WebpackError} */
394 TerserPlugin.buildError(error, name, // eslint-disable-next-line no-undefined
395 hasSourceMap ? compilation.requestShortener : undefined, hasSourceMap ? new _sourceMap.SourceMapConsumer(
396 /** @type {RawSourceMap} */
397 inputSourceMap) : // eslint-disable-next-line no-undefined
398 undefined));
399 return;
400 }
401
402 let shebang;
403
404 if (
405 /** @type {ExtractCommentsObject} */
406 this.options.extractComments.banner !== false && output.extractedComments && output.extractedComments.length > 0 && output.code.startsWith("#!")) {
407 const firstNewlinePosition = output.code.indexOf("\n");
408 shebang = output.code.substring(0, firstNewlinePosition);
409 output.code = output.code.substring(firstNewlinePosition + 1);
410 }
411
412 if (output.map) {
413 output.source = new SourceMapSource(output.code, name, output.map, input,
414 /** @type {RawSourceMap} */
415 inputSourceMap, true);
416 } else {
417 output.source = new RawSource(output.code);
418 }
419
420 if (output.extractedComments && output.extractedComments.length > 0) {
421 const commentsFilename =
422 /** @type {ExtractCommentsObject} */
423 this.options.extractComments.filename || "[file].LICENSE.txt[query]";
424 let query = "";
425 let filename = name;
426 const querySplit = filename.indexOf("?");
427
428 if (querySplit >= 0) {
429 query = filename.substr(querySplit);
430 filename = filename.substr(0, querySplit);
431 }
432
433 const lastSlashIndex = filename.lastIndexOf("/");
434 const basename = lastSlashIndex === -1 ? filename : filename.substr(lastSlashIndex + 1);
435 const data = {
436 filename,
437 basename,
438 query
439 };
440 output.commentsFilename = compilation.getPath(commentsFilename, data);
441 let banner; // Add a banner to the original file
442
443 if (
444 /** @type {ExtractCommentsObject} */
445 this.options.extractComments.banner !== false) {
446 banner =
447 /** @type {ExtractCommentsObject} */
448 this.options.extractComments.banner || `For license information please see ${path.relative(path.dirname(name), output.commentsFilename).replace(/\\/g, "/")}`;
449
450 if (typeof banner === "function") {
451 banner = banner(output.commentsFilename);
452 }
453
454 if (banner) {
455 output.source = new ConcatSource(shebang ? `${shebang}\n` : "", `/*! ${banner} */\n`, output.source);
456 }
457 }
458
459 const extractedCommentsString = output.extractedComments.sort().join("\n\n");
460 output.extractedCommentsSource = new RawSource(`${extractedCommentsString}\n`);
461 }
462
463 await cacheItem.storePromise({
464 source: output.source,
465 commentsFilename: output.commentsFilename,
466 extractedCommentsSource: output.extractedCommentsSource
467 });
468 }
469 /** @type {Record<string, any>} */
470
471
472 const newInfo = {
473 minimized: true
474 };
475 const {
476 source,
477 extractedCommentsSource
478 } = output; // Write extracted comments to commentsFilename
479
480 if (extractedCommentsSource) {
481 const {
482 commentsFilename
483 } = output;
484 newInfo.related = {
485 license: commentsFilename
486 };
487 allExtractedComments.set(name, {
488 extractedCommentsSource,
489 commentsFilename
490 });
491 }
492
493 compilation.updateAsset(name, source, newInfo);
494 }));
495 }
496
497 await Promise.all(scheduledTasks);
498
499 if (initializedWorker) {
500 await initializedWorker.end();
501 }
502 /** @typedef {{ source: import("webpack").sources.Source, commentsFilename: string, from: string }} ExtractedCommentsInfoWIthFrom */
503
504
505 await Array.from(allExtractedComments).sort().reduce(
506 /**
507 * @param {Promise<unknown>} previousPromise
508 * @param {[string, ExtractedCommentsInfo]} extractedComments
509 * @returns {Promise<ExtractedCommentsInfoWIthFrom>}
510 */
511 async (previousPromise, [from, value]) => {
512 const previous =
513 /** @type {ExtractedCommentsInfoWIthFrom | undefined} **/
514 await previousPromise;
515 const {
516 commentsFilename,
517 extractedCommentsSource
518 } = value;
519
520 if (previous && previous.commentsFilename === commentsFilename) {
521 const {
522 from: previousFrom,
523 source: prevSource
524 } = previous;
525 const mergedName = `${previousFrom}|${from}`;
526 const name = `${commentsFilename}|${mergedName}`;
527 const eTag = [prevSource, extractedCommentsSource].map(item => cache.getLazyHashedEtag(item)).reduce((previousValue, currentValue) => cache.mergeEtags(previousValue, currentValue));
528 let source = await cache.getPromise(name, eTag);
529
530 if (!source) {
531 source = new ConcatSource(Array.from(new Set([...
532 /** @type {string}*/
533 prevSource.source().split("\n\n"), ...
534 /** @type {string}*/
535 extractedCommentsSource.source().split("\n\n")])).join("\n\n"));
536 await cache.storePromise(name, eTag, source);
537 }
538
539 compilation.updateAsset(commentsFilename, source);
540 return {
541 source,
542 commentsFilename,
543 from: mergedName
544 };
545 }
546
547 const existingAsset = compilation.getAsset(commentsFilename);
548
549 if (existingAsset) {
550 return {
551 source: existingAsset.source,
552 commentsFilename,
553 from: commentsFilename
554 };
555 }
556
557 compilation.emitAsset(commentsFilename, extractedCommentsSource, {
558 extractedComments: true
559 });
560 return {
561 source: extractedCommentsSource,
562 commentsFilename,
563 from
564 };
565 },
566 /** @type {Promise<unknown>} */
567 Promise.resolve());
568 }
569 /**
570 * @private
571 * @param {any} environment
572 * @returns {TerserECMA}
573 */
574
575
576 static getEcmaVersion(environment) {
577 // ES 6th
578 if (environment.arrowFunction || environment.const || environment.destructuring || environment.forOf || environment.module) {
579 return 2015;
580 } // ES 11th
581
582
583 if (environment.bigIntLiteral || environment.dynamicImport) {
584 return 2020;
585 }
586
587 return 5;
588 }
589 /**
590 * @param {Compiler} compiler
591 * @returns {void}
592 */
593
594
595 apply(compiler) {
596 const {
597 output
598 } = compiler.options;
599
600 if (typeof this.options.terserOptions.ecma === "undefined") {
601 this.options.terserOptions.ecma = TerserPlugin.getEcmaVersion(output.environment || {});
602 }
603
604 const pluginName = this.constructor.name;
605 const availableNumberOfCores = TerserPlugin.getAvailableNumberOfCores(this.options.parallel);
606 compiler.hooks.compilation.tap(pluginName, compilation => {
607 const hooks = compiler.webpack.javascript.JavascriptModulesPlugin.getCompilationHooks(compilation);
608 const data = (0, _serializeJavascript.default)({
609 terser: terserPackageJson.version,
610 terserOptions: this.options.terserOptions
611 });
612 hooks.chunkHash.tap(pluginName, (chunk, hash) => {
613 hash.update("TerserPlugin");
614 hash.update(data);
615 });
616 compilation.hooks.processAssets.tapPromise({
617 name: pluginName,
618 stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE,
619 additionalAssets: true
620 }, assets => this.optimize(compiler, compilation, assets, {
621 availableNumberOfCores
622 }));
623 compilation.hooks.statsPrinter.tap(pluginName, stats => {
624 stats.hooks.print.for("asset.info.minimized").tap("terser-webpack-plugin", (minimized, {
625 green,
626 formatFlag
627 }) => minimized ?
628 /** @type {Function} */
629 green(
630 /** @type {Function} */
631 formatFlag("minimized")) : "");
632 });
633 });
634 }
635
636}
637
638var _default = TerserPlugin;
639exports.default = _default;
Note: See TracBrowser for help on using the repository browser.