html-minifier-next 4.11.0 → 4.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -16
- package/cli.js +177 -68
- package/dist/htmlminifier.cjs +206 -35
- package/dist/htmlminifier.esm.bundle.js +206 -35
- package/dist/types/htmlminifier.d.ts.map +1 -1
- package/dist/types/htmlparser.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/htmlminifier.js +195 -28
- package/src/htmlparser.js +11 -7
package/README.md
CHANGED
|
@@ -236,34 +236,34 @@ How does HTML Minifier Next compare to other minifiers? (All with the most aggre
|
|
|
236
236
|
| Site | Original Size (KB) | [HTML Minifier Next](https://github.com/j9t/html-minifier-next)<br>[](https://socket.dev/npm/package/html-minifier-next) | [HTML Minifier Terser](https://github.com/terser/html-minifier-terser)<br>[](https://socket.dev/npm/package/html-minifier-terser) | [htmlnano](https://github.com/posthtml/htmlnano)<br>[](https://socket.dev/npm/package/htmlnano) | [@swc/html](https://github.com/swc-project/swc)<br>[](https://socket.dev/npm/package/@swc/html) | [minify-html](https://github.com/wilsonzlin/minify-html)<br>[](https://socket.dev/npm/package/@minify-html/node) | [minimize](https://github.com/Swaagie/minimize)<br>[](https://socket.dev/npm/package/minimize) | [htmlcompressor.com](https://htmlcompressor.com/) |
|
|
237
237
|
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
|
238
238
|
| [A List Apart](https://alistapart.com/) | 59 | **49** | 50 | 51 | 52 | 51 | 54 | 52 |
|
|
239
|
-
| [Apple](https://www.apple.com/) |
|
|
240
|
-
| [BBC](https://www.bbc.co.uk/) |
|
|
239
|
+
| [Apple](https://www.apple.com/) | 266 | **207** | **207** | 236 | 239 | 240 | 242 | 243 |
|
|
240
|
+
| [BBC](https://www.bbc.co.uk/) | 739 | **675** | 685 | 695 | 695 | 697 | 733 | n/a |
|
|
241
241
|
| [CERN](https://home.cern/) | 156 | **87** | **87** | 95 | 95 | 95 | 97 | 100 |
|
|
242
|
-
| [CSS-Tricks](https://css-tricks.com/) |
|
|
242
|
+
| [CSS-Tricks](https://css-tricks.com/) | 161 | 121 | **119** | 127 | 142 | 142 | 147 | 144 |
|
|
243
243
|
| [ECMAScript](https://tc39.es/ecma262/) | 7238 | **6341** | **6341** | 6561 | 6444 | 6567 | 6614 | n/a |
|
|
244
244
|
| [EDRi](https://edri.org/) | 80 | **59** | 60 | 70 | 70 | 71 | 75 | 73 |
|
|
245
|
-
| [EFF](https://www.eff.org/) |
|
|
245
|
+
| [EFF](https://www.eff.org/) | 55 | **47** | **47** | 50 | 48 | 49 | 50 | 50 |
|
|
246
246
|
| [European Alternatives](https://european-alternatives.eu/) | 48 | **30** | **30** | 32 | 32 | 32 | 32 | 32 |
|
|
247
|
-
| [FAZ](https://www.faz.net/aktuell/) |
|
|
247
|
+
| [FAZ](https://www.faz.net/aktuell/) | 1543 | 1436 | 1441 | **1383** | 1468 | 1479 | 1490 | n/a |
|
|
248
248
|
| [French Tech](https://lafrenchtech.gouv.fr/) | 152 | **121** | 122 | 125 | 125 | 125 | 132 | 126 |
|
|
249
|
-
| [Frontend Dogma](https://frontenddogma.com/) |
|
|
249
|
+
| [Frontend Dogma](https://frontenddogma.com/) | 223 | **213** | 215 | 236 | 221 | 223 | 241 | 222 |
|
|
250
250
|
| [Google](https://www.google.com/) | 18 | **17** | **17** | **17** | **17** | **17** | 18 | 18 |
|
|
251
|
-
| [Ground News](https://ground.news/) |
|
|
251
|
+
| [Ground News](https://ground.news/) | 1437 | **1222** | 1225 | 1320 | 1346 | 1353 | 1424 | n/a |
|
|
252
252
|
| [HTML Living Standard](https://html.spec.whatwg.org/multipage/) | 149 | **147** | **147** | 153 | **147** | 149 | 155 | 149 |
|
|
253
|
-
| [Igalia](https://www.igalia.com/) | 50 | **
|
|
254
|
-
| [Leanpub](https://leanpub.com/) |
|
|
253
|
+
| [Igalia](https://www.igalia.com/) | 50 | **34** | **34** | 36 | 36 | 36 | 37 | 37 |
|
|
254
|
+
| [Leanpub](https://leanpub.com/) | 1288 | **1092** | **1092** | 1099 | 1097 | 1094 | 1283 | n/a |
|
|
255
255
|
| [Mastodon](https://mastodon.social/explore) | 37 | **27** | **27** | 32 | 34 | 35 | 35 | 35 |
|
|
256
256
|
| [MDN](https://developer.mozilla.org/en-US/) | 109 | **62** | **62** | 64 | 65 | 65 | 68 | 68 |
|
|
257
|
-
| [Middle East Eye](https://www.middleeasteye.net/) |
|
|
258
|
-
| [Nielsen Norman Group](https://www.nngroup.com/) |
|
|
257
|
+
| [Middle East Eye](https://www.middleeasteye.net/) | 223 | **196** | **196** | 203 | 201 | 200 | 202 | 203 |
|
|
258
|
+
| [Nielsen Norman Group](https://www.nngroup.com/) | 86 | 74 | 74 | **55** | 74 | 75 | 77 | 76 |
|
|
259
259
|
| [SitePoint](https://www.sitepoint.com/) | 485 | **354** | **354** | 425 | 459 | 464 | 481 | n/a |
|
|
260
260
|
| [TetraLogical](https://tetralogical.com/) | 44 | 38 | 38 | **35** | 38 | 38 | 39 | 39 |
|
|
261
|
-
| [TPGi](https://www.tpgi.com/) | 175 | **
|
|
262
|
-
| [United Nations](https://www.un.org/en/) |
|
|
263
|
-
| [W3C](https://www.w3.org/) | 50 | **
|
|
264
|
-
| **Average processing time** | |
|
|
261
|
+
| [TPGi](https://www.tpgi.com/) | 175 | **160** | 161 | **160** | 164 | 166 | 172 | 172 |
|
|
262
|
+
| [United Nations](https://www.un.org/en/) | 150 | **112** | 113 | 120 | 124 | 124 | 129 | 122 |
|
|
263
|
+
| [W3C](https://www.w3.org/) | 50 | **35** | 36 | 38 | 38 | 38 | 40 | 38 |
|
|
264
|
+
| **Average processing time** | | 306 ms (26/26) | 364 ms (26/26) | 162 ms (26/26) | 55 ms (26/26) | **16 ms (26/26)** | 316 ms (26/26) | 1439 ms (20/26) |
|
|
265
265
|
|
|
266
|
-
(Last updated: Dec
|
|
266
|
+
(Last updated: Dec 17, 2025)
|
|
267
267
|
<!-- End auto-generated -->
|
|
268
268
|
|
|
269
269
|
## Examples
|
package/cli.js
CHANGED
|
@@ -28,10 +28,12 @@
|
|
|
28
28
|
import fs from 'fs';
|
|
29
29
|
import path from 'path';
|
|
30
30
|
import { pathToFileURL } from 'url';
|
|
31
|
+
import os from 'os';
|
|
31
32
|
import { createRequire } from 'module';
|
|
32
33
|
import { camelCase, paramCase } from 'change-case';
|
|
33
34
|
import { Command } from 'commander';
|
|
34
|
-
|
|
35
|
+
// Lazy-load HMN to reduce CLI cold-start overhead
|
|
36
|
+
// import { minify } from './src/htmlminifier.js';
|
|
35
37
|
import { getPreset, getPresetNames } from './src/presets.js';
|
|
36
38
|
|
|
37
39
|
const require = createRequire(import.meta.url);
|
|
@@ -182,6 +184,15 @@ program.option('-o --output <file>', 'Specify output file (reads from file argum
|
|
|
182
184
|
program.option('-v --verbose', 'Show detailed processing information');
|
|
183
185
|
program.option('-d --dry', 'Dry run: process and report statistics without writing output');
|
|
184
186
|
|
|
187
|
+
// Lazy import wrapper for HMN
|
|
188
|
+
let minifyFnPromise;
|
|
189
|
+
async function getMinify() {
|
|
190
|
+
if (!minifyFnPromise) {
|
|
191
|
+
minifyFnPromise = import('./src/htmlminifier.js').then(m => m.minify);
|
|
192
|
+
}
|
|
193
|
+
return minifyFnPromise;
|
|
194
|
+
}
|
|
195
|
+
|
|
185
196
|
function readFile(file) {
|
|
186
197
|
try {
|
|
187
198
|
return fs.readFileSync(file, { encoding: 'utf8' });
|
|
@@ -270,13 +281,30 @@ program.option('--file-ext <extensions>', 'Specify file extension(s) to process
|
|
|
270
281
|
(async () => {
|
|
271
282
|
let content;
|
|
272
283
|
let filesProvided = false;
|
|
284
|
+
let capturedFiles = [];
|
|
273
285
|
await program.arguments('[files...]').action(function (files) {
|
|
274
|
-
|
|
286
|
+
capturedFiles = files;
|
|
275
287
|
filesProvided = files.length > 0;
|
|
288
|
+
// Defer reading files until after we check for consumed filenames
|
|
276
289
|
}).parseAsync(process.argv);
|
|
277
290
|
|
|
278
291
|
const programOptions = program.opts();
|
|
279
292
|
|
|
293
|
+
// Check if any `parseJSON` options consumed a filename as their value
|
|
294
|
+
// If so, treat the option as boolean true and add the filename back to the files list
|
|
295
|
+
const jsonOptionKeys = ['minifyCss', 'minifyJs', 'minifyUrls'];
|
|
296
|
+
for (const key of jsonOptionKeys) {
|
|
297
|
+
const value = programOptions[key];
|
|
298
|
+
if (typeof value === 'string' && /\.(html?|php|xml|svg|xhtml|jsx|tsx|vue|ejs|hbs|mustache|twig)$/i.test(value)) {
|
|
299
|
+
// The option consumed a filename - inject it back
|
|
300
|
+
programOptions[key] = true;
|
|
301
|
+
capturedFiles.push(value);
|
|
302
|
+
filesProvided = true;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Defer reading files—multi-file mode will process per-file later
|
|
307
|
+
|
|
280
308
|
// Load and normalize config if `--config-file` was specified
|
|
281
309
|
if (programOptions.configFile) {
|
|
282
310
|
config = await loadConfigFromPath(programOptions.configFile);
|
|
@@ -344,6 +372,7 @@ program.option('--file-ext <extensions>', 'Specify file extension(s) to process
|
|
|
344
372
|
|
|
345
373
|
let minified;
|
|
346
374
|
try {
|
|
375
|
+
const minify = await getMinify();
|
|
347
376
|
minified = await minify(data, createOptions());
|
|
348
377
|
} catch (err) {
|
|
349
378
|
fatal('Minification error on ' + inputFile + '\n' + err.message);
|
|
@@ -472,6 +501,54 @@ program.option('--file-ext <extensions>', 'Specify file extension(s) to process
|
|
|
472
501
|
process.stderr.write('\r\x1b[K'); // Clear the line
|
|
473
502
|
}
|
|
474
503
|
|
|
504
|
+
// Utility: concurrency runner
|
|
505
|
+
async function runWithConcurrency(items, limit, worker) {
|
|
506
|
+
const results = new Array(items.length);
|
|
507
|
+
let next = 0;
|
|
508
|
+
let active = 0;
|
|
509
|
+
return new Promise((resolve, reject) => {
|
|
510
|
+
const launch = () => {
|
|
511
|
+
while (active < limit && next < items.length) {
|
|
512
|
+
const current = next++;
|
|
513
|
+
active++;
|
|
514
|
+
Promise.resolve(worker(items[current], current))
|
|
515
|
+
.then((res) => {
|
|
516
|
+
results[current] = res;
|
|
517
|
+
active--;
|
|
518
|
+
launch();
|
|
519
|
+
})
|
|
520
|
+
.catch(reject);
|
|
521
|
+
}
|
|
522
|
+
if (next >= items.length && active === 0) {
|
|
523
|
+
resolve(results);
|
|
524
|
+
}
|
|
525
|
+
};
|
|
526
|
+
launch();
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
async function collectFiles(dir, extensions, skipRootAbs, ignorePatterns, baseDir) {
|
|
531
|
+
const out = [];
|
|
532
|
+
const entries = await fs.promises.readdir(dir).catch(() => []);
|
|
533
|
+
for (const name of entries) {
|
|
534
|
+
const filePath = path.join(dir, name);
|
|
535
|
+
if (skipRootAbs) {
|
|
536
|
+
const real = await fs.promises.realpath(filePath).catch(() => undefined);
|
|
537
|
+
if (real && (real === skipRootAbs || real.startsWith(skipRootAbs + path.sep))) continue;
|
|
538
|
+
}
|
|
539
|
+
const lst = await fs.promises.lstat(filePath).catch(() => null);
|
|
540
|
+
if (!lst || lst.isSymbolicLink()) continue;
|
|
541
|
+
if (lst.isDirectory()) {
|
|
542
|
+
if (shouldIgnoreDirectory(filePath, ignorePatterns, baseDir)) continue;
|
|
543
|
+
const sub = await collectFiles(filePath, extensions, skipRootAbs, ignorePatterns, baseDir);
|
|
544
|
+
out.push(...sub);
|
|
545
|
+
} else if (shouldProcessFile(name, extensions)) {
|
|
546
|
+
out.push(filePath);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
return out;
|
|
550
|
+
}
|
|
551
|
+
|
|
475
552
|
async function processDirectory(inputDir, outputDir, extensions, isDryRun = false, isVerbose = false, skipRootAbs, progress = null, ignorePatterns = [], baseDir = null) {
|
|
476
553
|
// If first call provided a string, normalize once; otherwise assume pre-parsed array
|
|
477
554
|
if (typeof extensions === 'string') {
|
|
@@ -483,61 +560,27 @@ program.option('--file-ext <extensions>', 'Specify file extension(s) to process
|
|
|
483
560
|
baseDir = inputDir;
|
|
484
561
|
}
|
|
485
562
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
const
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
const real = await fs.promises.realpath(inputFile).catch(() => undefined);
|
|
499
|
-
if (real && (real === skipRootAbs || real.startsWith(skipRootAbs + path.sep))) {
|
|
500
|
-
continue;
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
const lst = await fs.promises.lstat(inputFile).catch(err => {
|
|
505
|
-
fatal('Cannot read ' + inputFile + '\n' + err.message);
|
|
506
|
-
});
|
|
507
|
-
|
|
508
|
-
if (lst.isSymbolicLink()) {
|
|
509
|
-
continue;
|
|
563
|
+
// Collect all files first for bounded parallel processing
|
|
564
|
+
const list = await collectFiles(inputDir, extensions, skipRootAbs, ignorePatterns, baseDir);
|
|
565
|
+
const allStats = new Array(list.length);
|
|
566
|
+
const concurrency = Math.max(1, Math.min(os.cpus().length || 4, 8));
|
|
567
|
+
await runWithConcurrency(list, concurrency, async (inputFile, idx) => {
|
|
568
|
+
const rel = path.relative(inputDir, inputFile);
|
|
569
|
+
const outFile = path.join(outputDir, rel);
|
|
570
|
+
const outDir = path.dirname(outFile);
|
|
571
|
+
if (!isDryRun) {
|
|
572
|
+
await fs.promises.mkdir(outDir, { recursive: true }).catch(err => {
|
|
573
|
+
fatal('Cannot create directory ' + outDir + '\n' + err.message);
|
|
574
|
+
});
|
|
510
575
|
}
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
}
|
|
517
|
-
const dirStats = await processDirectory(inputFile, outputFile, extensions, isDryRun, isVerbose, skipRootAbs, progress, ignorePatterns, baseDir);
|
|
518
|
-
if (dirStats) {
|
|
519
|
-
allStats.push(...dirStats);
|
|
520
|
-
}
|
|
521
|
-
} else if (shouldProcessFile(file, extensions)) {
|
|
522
|
-
if (!isDryRun) {
|
|
523
|
-
await fs.promises.mkdir(outputDir, { recursive: true }).catch(err => {
|
|
524
|
-
fatal('Cannot create directory ' + outputDir + '\n' + err.message);
|
|
525
|
-
});
|
|
526
|
-
}
|
|
527
|
-
const fileStats = await processFile(inputFile, outputFile, isDryRun, isVerbose);
|
|
528
|
-
if (fileStats) {
|
|
529
|
-
allStats.push(fileStats);
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
// Update progress after processing
|
|
533
|
-
if (progress) {
|
|
534
|
-
progress.current++;
|
|
535
|
-
updateProgress(progress.current, progress.total);
|
|
536
|
-
}
|
|
576
|
+
const stats = await processFile(inputFile, outFile, isDryRun, isVerbose);
|
|
577
|
+
allStats[idx] = stats;
|
|
578
|
+
if (progress) {
|
|
579
|
+
progress.current++;
|
|
580
|
+
updateProgress(progress.current, progress.total);
|
|
537
581
|
}
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
return allStats;
|
|
582
|
+
});
|
|
583
|
+
return allStats.filter(Boolean);
|
|
541
584
|
}
|
|
542
585
|
|
|
543
586
|
const writeMinify = async () => {
|
|
@@ -551,6 +594,7 @@ program.option('--file-ext <extensions>', 'Specify file extension(s) to process
|
|
|
551
594
|
let minified;
|
|
552
595
|
|
|
553
596
|
try {
|
|
597
|
+
const minify = await getMinify();
|
|
554
598
|
minified = await minify(content, minifierOptions);
|
|
555
599
|
} catch (err) {
|
|
556
600
|
fatal('Minification error:\n' + err.message);
|
|
@@ -576,17 +620,12 @@ program.option('--file-ext <extensions>', 'Specify file extension(s) to process
|
|
|
576
620
|
}
|
|
577
621
|
|
|
578
622
|
if (programOptions.output) {
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
.on('finish', resolve);
|
|
586
|
-
fileStream.end(minified);
|
|
587
|
-
}).catch((e) => {
|
|
588
|
-
fatal('Cannot write ' + programOptions.output + '\n' + e.message);
|
|
589
|
-
});
|
|
623
|
+
try {
|
|
624
|
+
await fs.promises.mkdir(path.dirname(programOptions.output), { recursive: true });
|
|
625
|
+
await fs.promises.writeFile(programOptions.output, minified, { encoding: 'utf8' });
|
|
626
|
+
} catch (err) {
|
|
627
|
+
fatal('Cannot write ' + programOptions.output + '\n' + err.message);
|
|
628
|
+
}
|
|
590
629
|
return;
|
|
591
630
|
}
|
|
592
631
|
|
|
@@ -646,6 +685,16 @@ program.option('--file-ext <extensions>', 'Specify file extension(s) to process
|
|
|
646
685
|
// Parse ignore patterns
|
|
647
686
|
const ignorePatterns = parseIgnorePatterns(resolvedIgnoreDir);
|
|
648
687
|
|
|
688
|
+
// Validate that the input directory exists and is readable
|
|
689
|
+
try {
|
|
690
|
+
const stat = await fs.promises.stat(inputDir);
|
|
691
|
+
if (!stat.isDirectory()) {
|
|
692
|
+
fatal(inputDir + ' is not a directory');
|
|
693
|
+
}
|
|
694
|
+
} catch (err) {
|
|
695
|
+
fatal('Cannot read directory ' + inputDir + '\n' + err.message);
|
|
696
|
+
}
|
|
697
|
+
|
|
649
698
|
// Resolve base directory for consistent path comparisons
|
|
650
699
|
const inputDirResolved = await fs.promises.realpath(inputDir).catch(() => inputDir);
|
|
651
700
|
|
|
@@ -688,12 +737,72 @@ program.option('--file-ext <extensions>', 'Specify file extension(s) to process
|
|
|
688
737
|
}
|
|
689
738
|
})();
|
|
690
739
|
} else if (filesProvided) { // Minifying one or more files specified on the CMD line
|
|
691
|
-
|
|
740
|
+
// Process each file independently, then concatenate outputs to preserve current behavior
|
|
741
|
+
const minifierOptions = createOptions();
|
|
742
|
+
// Show config info if verbose/dry
|
|
743
|
+
if (programOptions.verbose || programOptions.dry) {
|
|
744
|
+
getActiveOptionsDisplay(minifierOptions);
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
const concurrency = Math.max(1, Math.min(os.cpus().length || 4, 8));
|
|
748
|
+
const inputs = capturedFiles.slice();
|
|
749
|
+
|
|
750
|
+
// Read originals and minify in parallel with bounded concurrency
|
|
751
|
+
const originals = new Array(inputs.length);
|
|
752
|
+
const outputs = new Array(inputs.length);
|
|
753
|
+
|
|
754
|
+
await runWithConcurrency(inputs, concurrency, async (file, idx) => {
|
|
755
|
+
const data = await fs.promises.readFile(file, 'utf8').catch(err => fatal('Cannot read ' + file + '\n' + err.message));
|
|
756
|
+
const minify = await getMinify();
|
|
757
|
+
let out;
|
|
758
|
+
try {
|
|
759
|
+
out = await minify(data, minifierOptions);
|
|
760
|
+
} catch (err) {
|
|
761
|
+
fatal('Minification error on ' + file + '\n' + err.message);
|
|
762
|
+
}
|
|
763
|
+
originals[idx] = data;
|
|
764
|
+
outputs[idx] = out;
|
|
765
|
+
});
|
|
766
|
+
|
|
767
|
+
const originalCombined = originals.join('');
|
|
768
|
+
const minifiedCombined = outputs.join('');
|
|
769
|
+
|
|
770
|
+
const stats = calculateStats(originalCombined, minifiedCombined);
|
|
771
|
+
|
|
772
|
+
if (programOptions.dry) {
|
|
773
|
+
const inputSource = capturedFiles.join(', ');
|
|
774
|
+
const outputDest = programOptions.output || 'STDOUT';
|
|
775
|
+
console.error(`[DRY RUN] Would minify: ${inputSource} → ${outputDest}`);
|
|
776
|
+
console.error(` Original: ${stats.originalSize.toLocaleString()} bytes`);
|
|
777
|
+
console.error(` Minified: ${stats.minifiedSize.toLocaleString()} bytes`);
|
|
778
|
+
console.error(` Saved: ${stats.sign}${Math.abs(stats.saved).toLocaleString()} bytes (${stats.percentage}%)`);
|
|
779
|
+
process.exit(0);
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
if (programOptions.verbose) {
|
|
783
|
+
const inputSource = capturedFiles.join(', ');
|
|
784
|
+
console.error(` ✓ ${inputSource}: ${stats.originalSize.toLocaleString()} → ${stats.minifiedSize.toLocaleString()} bytes (${stats.sign}${Math.abs(stats.saved).toLocaleString()}, ${stats.percentage}%)`);
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
if (programOptions.output) {
|
|
788
|
+
try {
|
|
789
|
+
await fs.promises.mkdir(path.dirname(programOptions.output), { recursive: true });
|
|
790
|
+
await fs.promises.writeFile(programOptions.output, minifiedCombined, 'utf8');
|
|
791
|
+
} catch (err) {
|
|
792
|
+
fatal('Cannot write ' + programOptions.output + '\n' + err.message);
|
|
793
|
+
}
|
|
794
|
+
} else {
|
|
795
|
+
process.stdout.write(minifiedCombined);
|
|
796
|
+
}
|
|
797
|
+
process.exit(0);
|
|
692
798
|
} else { // Minifying input coming from STDIN
|
|
693
799
|
content = '';
|
|
694
800
|
process.stdin.setEncoding('utf8');
|
|
695
801
|
process.stdin.on('data', function (data) {
|
|
696
802
|
content += data;
|
|
697
|
-
}).on('end',
|
|
803
|
+
}).on('end', async function() {
|
|
804
|
+
await writeMinify();
|
|
805
|
+
process.exit(0);
|
|
806
|
+
});
|
|
698
807
|
}
|
|
699
808
|
})();
|