html-minifier-next 6.2.7 → 6.2.8

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 CHANGED
@@ -4,17 +4,11 @@
4
4
 
5
5
  Your web page optimization precision tool: HTML Minifier Next (HMN) is a **super-configurable, well-tested, JavaScript-based HTML minifier** able to also handle in-document CSS, JavaScript, and SVG minification.
6
6
 
7
- The project was based on [HTML Minifier Terser (HMT)](https://github.com/terser/html-minifier-terser), which in turn had been based on [Juriy “kangax” Zaytsev’s HTML Minifier (HM)](https://github.com/kangax/html-minifier); as of 2025, both HTML Minifier Terser and HTML Minifier had been unmaintained for several years. HMN offers additional features and has been optimized for speed. While an independent project, it is still backwards-compatible with HMT and HM.
7
+ The project was based on [HTML Minifier Terser (HMT)](https://github.com/terser/html-minifier-terser), which in turn had been based on [Juriy “kangax” Zaytsev’s HTML Minifier (HM)](https://github.com/kangax/html-minifier). It is now **the official successor to HTML Minifier**. HMN is maintained, easier to use, offers new features, and has been optimized for speed.
8
8
 
9
9
  ## Installation
10
10
 
11
- From npm for use as a command-line app:
12
-
13
- ```shell
14
- npm i -g html-minifier-next
15
- ```
16
-
17
- Directly with npx:
11
+ For use as a command-line app, use npx:
18
12
 
19
13
  ```shell
20
14
  npx html-minifier-next --help
@@ -22,30 +16,30 @@ npx html-minifier-next --help
22
16
 
23
17
  (For immediate, zero-config use in the current folder: `npx html-minifier-next --zero`)
24
18
 
25
- From npm for programmatic use:
19
+ For programmatic use, install as a development dependency:
26
20
 
27
21
  ```shell
28
- npm i html-minifier-next
22
+ npm i -D html-minifier-next
29
23
  ```
30
24
 
31
25
  ## General usage
32
26
 
33
27
  ### CLI
34
28
 
35
- Use `html-minifier-next --help` to check all available options:
29
+ Use `npx html-minifier-next --help` to check all available options:
36
30
 
37
31
  | Option | Description | Example |
38
32
  | --- | --- | --- |
39
- | `--zero`, `-z` | Minify all HTML files in the current folder and its subfolders in place (except node_modules), using comprehensive settings (standalone—flag is ignored when combined with other options) | `html-minifier-next --zero` |
33
+ | `--zero`, `-z` | Minify all HTML files in the current folder and its subfolders in place (except node_modules), using comprehensive settings (standalone—flag is ignored when combined with other options) | `npx html-minifier-next --zero` |
40
34
  | `--input-dir <dir>`, `-I <dir>` | Specify an input directory | `--input-dir=src` |
41
35
  | `--ignore-dir <patterns>`, `-X <patterns>` | Exclude directories—relative to input directory—from processing (comma-separated, overrides config file setting) | `--ignore-dir=libs`, `--ignore-dir=libs,vendor,node_modules` |
42
36
  | `--output-dir <dir>`, `-O <dir>` | Specify an output directory | `--output-dir=dist` |
43
- | `--output <file>`, `-o <file>` | Specify output file (reads from file arguments or STDIN) | File to file: `html-minifier-next input.html -o output.html`<br>Pipe to file: `cat input.html \| html-minifier-next -o output.html`<br>File to STDOUT: `html-minifier-next input.html` |
37
+ | `--output <file>`, `-o <file>` | Specify output file (reads from file arguments or STDIN) | File to file: `npx html-minifier-next input.html -o output.html`<br>Pipe to file: `cat input.html \| npx html-minifier-next -o output.html`<br>File to STDOUT: `npx html-minifier-next input.html` |
44
38
  | `--file-ext <extensions>`, `-f <extensions>` | Specify file extension(s) to process (comma-separated, overrides config file setting); defaults to `html,htm,shtml,shtm`; use `*` for all files | `--file-ext=html,php`, `--file-ext='*'` |
45
39
  | `--preset <name>`, `-p <name>` | Use a preset configuration (conservative or comprehensive) | `--preset=conservative` |
46
40
  | `--config-file <file>`, `-c <file>` | Use a configuration file | `--config-file=html-minifier.json` |
47
- | `--verbose`, `-v` | Show detailed processing information (active options, file statistics) | `html-minifier-next --input-dir=src --output-dir=dist --verbose --collapse-whitespace` |
48
- | `--dry`, `-d` | Dry run: Process and report statistics without writing output | `html-minifier-next input.html --dry --collapse-whitespace` |
41
+ | `--verbose`, `-v` | Show detailed processing information (active options, file statistics) | `npx html-minifier-next --input-dir=src --output-dir=dist --verbose --collapse-whitespace` |
42
+ | `--dry`, `-d` | Dry run: Process and report statistics without writing output | `npx html-minifier-next input.html --dry --collapse-whitespace` |
49
43
 
50
44
  ### Configuration file
51
45
 
@@ -113,14 +107,14 @@ To review the specific options set, [presets.js](https://github.com/j9t/html-min
113
107
 
114
108
  ```shell
115
109
  # Via CLI flag
116
- html-minifier-next --preset conservative input.html
110
+ npx html-minifier-next --preset conservative input.html
117
111
 
118
112
  # Via config file
119
- html-minifier-next --config-file=html-minifier.json input.html
113
+ npx html-minifier-next --config-file=html-minifier.json input.html
120
114
  # where html-minifier.json contains: { "preset": "conservative" }
121
115
 
122
116
  # Override preset options
123
- html-minifier-next --preset conservative --remove-empty-attributes input.html
117
+ npx html-minifier-next --preset conservative --remove-empty-attributes input.html
124
118
  ```
125
119
 
126
120
  **Priority order:** Presets are applied first, then config file options, then CLI flags. This allows you to start with a preset and customize as needed.
@@ -246,14 +240,12 @@ const result = await minify(html, {
246
240
  * `terser` (default): The standard JavaScript minifier with excellent compression
247
241
  * [`swc`](https://swc.rs/): Rust-based minifier that’s significantly faster than Terser (requires separate installation)
248
242
 
249
- **To use SWC**, install it as a dependency:
243
+ **To use SWC**, install it as a development dependency:
250
244
 
251
245
  ```shell
252
- npm i @swc/core
246
+ npm i -D @swc/core
253
247
  ```
254
248
 
255
- (Build-only users may want to install it as a dev dependency: `npm i -D @swc/core`.)
256
-
257
249
  **Important:** Inline event handlers (e.g., `onclick="return false"`) always use Terser regardless of the `engine` setting, as SWC doesn’t support bare return statements. This is handled automatically—you don’t need to do anything special.
258
250
 
259
251
  You can pass engine-specific configuration options:
@@ -340,7 +332,7 @@ const result = await minify(html, {
340
332
  **Via CLI flags:**
341
333
 
342
334
  ```shell
343
- html-minifier-next --minify-css --cache-css 750 --minify-js --cache-js 250 --minify-svg --cache-svg 100 input.html
335
+ npx html-minifier-next --minify-css --cache-css 750 --minify-js --cache-js 250 --minify-svg --cache-svg 100 input.html
344
336
  ```
345
337
 
346
338
  **Via environment variables:**
@@ -349,7 +341,7 @@ html-minifier-next --minify-css --cache-css 750 --minify-js --cache-js 250 --min
349
341
  export HMN_CACHE_CSS=750
350
342
  export HMN_CACHE_JS=250
351
343
  export HMN_CACHE_SVG=100
352
- html-minifier-next --minify-css --minify-js --minify-svg input.html
344
+ npx html-minifier-next --minify-css --minify-js --minify-svg input.html
353
345
  ```
354
346
 
355
347
  **Configuration file:**
@@ -390,12 +382,8 @@ Please see [**the Minifier Benchmarks project**](https://github.com/j9t/minifier
390
382
  **Sample command line:**
391
383
 
392
384
  ```shell
393
- html-minifier-next --collapse-whitespace --remove-comments --minify-js --input-dir=. --output-dir=example
394
- ```
385
+ npx html-minifier-next --collapse-whitespace --remove-comments --minify-js --input-dir=. --output-dir=example
395
386
 
396
- Example using npx:
397
-
398
- ```shell
399
387
  npx html-minifier-next --input-dir=test --preset comprehensive --output-dir example
400
388
  ```
401
389
 
@@ -403,39 +391,39 @@ npx html-minifier-next --input-dir=test --preset comprehensive --output-dir exam
403
391
 
404
392
  ```shell
405
393
  # Process default extensions (html, htm, shtml, shtm)
406
- html-minifier-next --collapse-whitespace --input-dir=src --output-dir=dist
394
+ npx html-minifier-next --collapse-whitespace --input-dir=src --output-dir=dist
407
395
 
408
396
  # Process only specific extensions
409
- html-minifier-next --collapse-whitespace --input-dir=src --output-dir=dist --file-ext=html,php
397
+ npx html-minifier-next --collapse-whitespace --input-dir=src --output-dir=dist --file-ext=html,php
410
398
 
411
399
  # Using configuration file that sets `fileExt` (e.g., `"fileExt": "html,php"`)
412
- html-minifier-next --config-file=html-minifier.json --input-dir=src --output-dir=dist
400
+ npx html-minifier-next --config-file=html-minifier.json --input-dir=src --output-dir=dist
413
401
 
414
402
  # Process all files (explicit wildcard)
415
- html-minifier-next --collapse-whitespace --input-dir=src --output-dir=dist --file-ext='*'
403
+ npx html-minifier-next --collapse-whitespace --input-dir=src --output-dir=dist --file-ext='*'
416
404
  ```
417
405
 
418
406
  **Exclude directories from processing:**
419
407
 
420
408
  ```shell
421
409
  # Ignore a single directory
422
- html-minifier-next --collapse-whitespace --input-dir=src --output-dir=dist --ignore-dir=libs
410
+ npx html-minifier-next --collapse-whitespace --input-dir=src --output-dir=dist --ignore-dir=libs
423
411
 
424
412
  # Ignore multiple directories
425
- html-minifier-next --collapse-whitespace --input-dir=src --output-dir=dist --ignore-dir=libs,vendor,node_modules
413
+ npx html-minifier-next --collapse-whitespace --input-dir=src --output-dir=dist --ignore-dir=libs,vendor,node_modules
426
414
 
427
415
  # Ignore by relative path (only ignores src/static/libs, not other “libs” directories)
428
- html-minifier-next --collapse-whitespace --input-dir=src --output-dir=dist --ignore-dir=static/libs
416
+ npx html-minifier-next --collapse-whitespace --input-dir=src --output-dir=dist --ignore-dir=static/libs
429
417
  ```
430
418
 
431
419
  **Dry run mode (preview outcome without writing files):**
432
420
 
433
421
  ```shell
434
422
  # Preview with output file
435
- html-minifier-next input.html -o output.html --dry --collapse-whitespace
423
+ npx html-minifier-next input.html -o output.html --dry --collapse-whitespace
436
424
 
437
425
  # Preview directory processing with statistics per file and total
438
- html-minifier-next --input-dir=src --output-dir=dist --dry --collapse-whitespace
426
+ npx html-minifier-next --input-dir=src --output-dir=dist --dry --collapse-whitespace
439
427
  # Output: [DRY RUN] Would process directory: src → dist
440
428
  # index.html: 1,234 → 892 bytes (-342, 27.7%)
441
429
  # about.html: 2,100 → 1,654 bytes (-446, 21.2%)
@@ -447,7 +435,7 @@ html-minifier-next --input-dir=src --output-dir=dist --dry --collapse-whitespace
447
435
 
448
436
  ```shell
449
437
  # Show processing details while minifying
450
- html-minifier-next --input-dir=src --output-dir=dist --verbose --collapse-whitespace
438
+ npx html-minifier-next --input-dir=src --output-dir=dist --verbose --collapse-whitespace
451
439
  # Output: CLI options: collapseWhitespace
452
440
  # ✓ src/index.html: 1,234 → 892 bytes (-342, 27.7%)
453
441
  # ✓ src/about.html: 2,100 → 1,654 bytes (-446, 21.2%)
@@ -455,7 +443,7 @@ html-minifier-next --input-dir=src --output-dir=dist --verbose --collapse-whites
455
443
  # Total: 3,334 → 2,546 bytes (-788, 23.6%)
456
444
 
457
445
  # `--dry` automatically enables verbose output
458
- html-minifier-next --input-dir=src --output-dir=dist --dry --collapse-whitespace
446
+ npx html-minifier-next --input-dir=src --output-dir=dist --dry --collapse-whitespace
459
447
  ```
460
448
 
461
449
  ## Special cases
@@ -560,13 +548,13 @@ ignoreCustomFragments: [/\{%[\s\S]{0,1000}?%\}/, /\{\{[\s\S]{0,500}?\}\}/]
560
548
  **CLI (via config file—recommended):**
561
549
 
562
550
  ```shell
563
- html-minifier-next --config-file=config.json input.html
551
+ npx html-minifier-next --config-file=config.json input.html
564
552
  ```
565
553
 
566
554
  **CLI (inline—not recommended due to complex escaping):**
567
555
 
568
556
  ```shell
569
- html-minifier-next --ignore-custom-fragments '[\\\"\\\\{%[\\\\s\\\\S]{0,1000}?%\\\\}\\\"]' input.html
557
+ npx html-minifier-next --ignore-custom-fragments '[\\\"\\\\{%[\\\\s\\\\S]{0,1000}?%\\\\}\\\"]' input.html
570
558
  ```
571
559
 
572
560
  For CLI usage, using a config file is strongly recommended to avoid complex shell and JSON escaping.
@@ -577,7 +565,7 @@ For CLI usage, using a config file is strongly recommended to avoid complex shel
577
565
  \{%[\s\S]{0,1000}?%\} \{\{[\s\S]{0,500}?\}\}
578
566
  ```
579
567
 
580
- ## Running HTML Minifier Next locally
568
+ ## Working on HTML Minifier Next
581
569
 
582
570
  ### Local server
583
571
 
@@ -609,6 +597,6 @@ With many thanks to the previous authors of and contributors to HTML Minifier, e
609
597
 
610
598
  You might like some of my other work:
611
599
 
612
- * Optimization tools: HTML Minifier Next · [ObsoHTML](https://github.com/j9t/obsohtml) · [Image Guard](https://github.com/j9t/image-guard) · [Compressor.js Next](https://github.com/j9t/compressorjs-next) · [.htaccess Punk](https://github.com/j9t/htaccess-punk)
600
+ * Optimization tools: [hihtml](https://github.com/j9t/hihtml) · HTML Minifier Next · [ObsoHTML](https://github.com/j9t/obsohtml) · [Image Guard](https://github.com/j9t/image-guard) · [Compressor.js Next](https://github.com/j9t/compressorjs-next) · [.htaccess Punk](https://github.com/j9t/htaccess-punk)
613
601
  * Defense tools: [IA Defensa](https://iadefensa.com/solutions/)
614
602
  * Resources for quality web development: [Articles](https://meiert.com/topics/development/) · [Books](https://meiert.com/topics/books/) (including [_On Web Development_](https://meiert.com/blog/on-web-development-2/)) · [News](https://frontenddogma.com/) · [Terminology](https://webglossary.info/)
@@ -3973,47 +3973,55 @@ async function minifyHTML(value, options, partialMarkup) {
3973
3973
  const maxQuantifier = options.customFragmentQuantifierLimit || 200;
3974
3974
  const whitespacePattern = `\\s{0,${maxQuantifier}}`;
3975
3975
 
3976
- // Use bounded quantifiers to prevent ReDoS—this approach prevents exponential backtracking
3977
- const reCustomIgnore = new RegExp(
3978
- whitespacePattern + '(?:' + customFragments.join('|') + '){1,' + maxQuantifier + '}' + whitespacePattern,
3979
- 'g'
3980
- );
3981
- // Temporarily replace custom ignored fragments with unique attributes
3982
- value = value.replace(reCustomIgnore, function (match) {
3983
- if (!uidAttr) {
3984
- uidAttr = uniqueId(value);
3985
- uidPattern = new RegExp('(\\s*)' + uidAttr + '([0-9]+)' + uidAttr + '(\\s*)', 'g');
3986
- uidAttrLeadingPattern = new RegExp('^\\s*' + uidAttr + '(\\d+)' + uidAttr);
3987
-
3988
- if (options.minifyCSS) {
3989
- options.minifyCSS = (function (fn) {
3990
- return function (text, type) {
3991
- text = text.replace(uidPattern, function (match, prefix, index) {
3992
- const chunks = ignoredCustomMarkupChunks[+index];
3993
- return chunks[1] + uidAttr + index + uidAttr + chunks[2];
3994
- });
3995
-
3996
- return fn(text, type);
3997
- };
3998
- })(options.minifyCSS);
3999
- }
3976
+ // Fast path: The padded replace below is costly on large inputs because the
3977
+ // `\s{0,N}` padding makes the regex engine consume and backtrack at every
3978
+ // whitespace run; since the padding is optional and the fragment group requires
3979
+ // at least one match, a single unpadded probe that finds nothing proves the
3980
+ // replace would be a no-op—so skip it entirely
3981
+ const reFragmentProbe = new RegExp('(?:' + customFragments.join('|') + ')');
3982
+ if (reFragmentProbe.test(value)) {
3983
+ // Use bounded quantifiers to prevent ReDoS—this approach prevents exponential backtracking
3984
+ const reCustomIgnore = new RegExp(
3985
+ whitespacePattern + '(?:' + customFragments.join('|') + '){1,' + maxQuantifier + '}' + whitespacePattern,
3986
+ 'g'
3987
+ );
3988
+ // Temporarily replace custom ignored fragments with unique attributes
3989
+ value = value.replace(reCustomIgnore, function (match) {
3990
+ if (!uidAttr) {
3991
+ uidAttr = uniqueId(value);
3992
+ uidPattern = new RegExp('(\\s*)' + uidAttr + '([0-9]+)' + uidAttr + '(\\s*)', 'g');
3993
+ uidAttrLeadingPattern = new RegExp('^\\s*' + uidAttr + '(\\d+)' + uidAttr);
3994
+
3995
+ if (options.minifyCSS) {
3996
+ options.minifyCSS = (function (fn) {
3997
+ return function (text, type) {
3998
+ text = text.replace(uidPattern, function (match, prefix, index) {
3999
+ const chunks = ignoredCustomMarkupChunks[+index];
4000
+ return chunks[1] + uidAttr + index + uidAttr + chunks[2];
4001
+ });
4002
+
4003
+ return fn(text, type);
4004
+ };
4005
+ })(options.minifyCSS);
4006
+ }
4000
4007
 
4001
- if (options.minifyJS) {
4002
- options.minifyJS = (function (fn) {
4003
- return function (text, inline, isModule) {
4004
- return fn(text.replace(uidPattern, function (match, prefix, index) {
4005
- const chunks = ignoredCustomMarkupChunks[+index];
4006
- return chunks[1] + uidAttr + index + uidAttr + chunks[2];
4007
- }), inline, isModule);
4008
- };
4009
- })(options.minifyJS);
4008
+ if (options.minifyJS) {
4009
+ options.minifyJS = (function (fn) {
4010
+ return function (text, inline, isModule) {
4011
+ return fn(text.replace(uidPattern, function (match, prefix, index) {
4012
+ const chunks = ignoredCustomMarkupChunks[+index];
4013
+ return chunks[1] + uidAttr + index + uidAttr + chunks[2];
4014
+ }), inline, isModule);
4015
+ };
4016
+ })(options.minifyJS);
4017
+ }
4010
4018
  }
4011
- }
4012
4019
 
4013
- const token = uidAttr + ignoredCustomMarkupChunks.length + uidAttr;
4014
- ignoredCustomMarkupChunks.push(/^(\s*)[\s\S]*?(\s*)$/.exec(match));
4015
- return '\t' + token + '\t';
4016
- });
4020
+ const token = uidAttr + ignoredCustomMarkupChunks.length + uidAttr;
4021
+ ignoredCustomMarkupChunks.push(/^(\s*)[\s\S]*?(\s*)$/.exec(match));
4022
+ return '\t' + token + '\t';
4023
+ });
4024
+ }
4017
4025
  }
4018
4026
 
4019
4027
  function canCollapseWhitespace$1(tag, attrs) {
@@ -1 +1 @@
1
- {"version":3,"file":"htmlminifier.d.ts","sourceRoot":"","sources":["../../src/htmlminifier.js"],"names":[],"mappings":"AA4yDO,8BAJI,MAAM,YACN,eAAe,GACb,OAAO,CAAC,MAAM,CAAC,CAwB3B;;;;;;;;;;;;UA5hDS,MAAM;;;;;;;;;;;;;;;;;;mCAaA,MAAM,SAAS,aAAa,EAAE,yBAAyB,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,KAAK,OAAO;;;;;;;+BAM3F,MAAM,GAAG,IAAI,SAAS,aAAa,EAAE,GAAG,SAAS,qBAAqB,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,KAAK,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA6JtG,OAAO,KAAK,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2HA2BiF,MAAM,SAAS,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM;;;;;;;;;;;;;;;;iBASxG,QAAQ,GAAG,KAAK;gBAAgC,MAAM,WAAW,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM;;;;;;;;;;;eAa/H,MAAM;gBAAY,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM;;;;;;;;;;;;;;;;;mBAiBzE,MAAM,KAAK,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kDA+DF,MAAM,OAAO,MAAM,KAAK,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sCA2EpC,MAAM,SAAS,aAAa,EAAE,KAAK,IAAI;;;;;;;;;wCAQrC,MAAM,KAAK,MAAM;;;;;;;;;;;;;;;;;wBAtqBK,cAAc;0BAAd,cAAc;+BAAd,cAAc"}
1
+ {"version":3,"file":"htmlminifier.d.ts","sourceRoot":"","sources":["../../src/htmlminifier.js"],"names":[],"mappings":"AAozDO,8BAJI,MAAM,YACN,eAAe,GACb,OAAO,CAAC,MAAM,CAAC,CAwB3B;;;;;;;;;;;;UApiDS,MAAM;;;;;;;;;;;;;;;;;;mCAaA,MAAM,SAAS,aAAa,EAAE,yBAAyB,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,KAAK,OAAO;;;;;;;+BAM3F,MAAM,GAAG,IAAI,SAAS,aAAa,EAAE,GAAG,SAAS,qBAAqB,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,KAAK,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA6JtG,OAAO,KAAK,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2HA2BiF,MAAM,SAAS,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM;;;;;;;;;;;;;;;;iBASxG,QAAQ,GAAG,KAAK;gBAAgC,MAAM,WAAW,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM;;;;;;;;;;;eAa/H,MAAM;gBAAY,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM;;;;;;;;;;;;;;;;;mBAiBzE,MAAM,KAAK,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kDA+DF,MAAM,OAAO,MAAM,KAAK,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sCA2EpC,MAAM,SAAS,aAAa,EAAE,KAAK,IAAI;;;;;;;;;wCAQrC,MAAM,KAAK,MAAM;;;;;;;;;;;;;;;;;wBAtqBK,cAAc;0BAAd,cAAc;+BAAd,cAAc"}
package/package.json CHANGED
@@ -10,21 +10,21 @@
10
10
  "entities": "^8.0.0",
11
11
  "lightningcss": "^1.32.0",
12
12
  "svgo": "^4.0.1",
13
- "terser": "^5.46.2"
13
+ "terser": "^5.47.1"
14
14
  },
15
15
  "description": "Super-configurable and well-tested web page minifier (enhanced successor of HTML Minifier)",
16
16
  "devDependencies": {
17
- "@commitlint/cli": "^20.5.3",
17
+ "@commitlint/cli": "^21.0.1",
18
18
  "@eslint/js": "^10.0.1",
19
19
  "@rollup/plugin-commonjs": "^29.0.2",
20
20
  "@rollup/plugin-json": "^6.1.0",
21
21
  "@rollup/plugin-node-resolve": "^16.0.3",
22
- "@swc/core": "^1.15.33",
23
- "eslint": "^10.3.0",
24
- "rollup": "^4.60.2",
22
+ "@swc/core": "^1.15.40",
23
+ "eslint": "^10.4.0",
24
+ "rollup": "^4.60.4",
25
25
  "rollup-plugin-polyfill-node": "^0.13.0",
26
26
  "typescript": "^6.0.3",
27
- "vite": "^8.0.10"
27
+ "vite": "^8.0.14"
28
28
  },
29
29
  "exports": {
30
30
  ".": {
@@ -97,5 +97,5 @@
97
97
  },
98
98
  "type": "module",
99
99
  "types": "./dist/types/htmlminifier.d.ts",
100
- "version": "6.2.7"
100
+ "version": "6.2.8"
101
101
  }
@@ -1031,47 +1031,55 @@ async function minifyHTML(value, options, partialMarkup) {
1031
1031
  const maxQuantifier = options.customFragmentQuantifierLimit || 200;
1032
1032
  const whitespacePattern = `\\s{0,${maxQuantifier}}`;
1033
1033
 
1034
- // Use bounded quantifiers to prevent ReDoS—this approach prevents exponential backtracking
1035
- const reCustomIgnore = new RegExp(
1036
- whitespacePattern + '(?:' + customFragments.join('|') + '){1,' + maxQuantifier + '}' + whitespacePattern,
1037
- 'g'
1038
- );
1039
- // Temporarily replace custom ignored fragments with unique attributes
1040
- value = value.replace(reCustomIgnore, function (match) {
1041
- if (!uidAttr) {
1042
- uidAttr = uniqueId(value);
1043
- uidPattern = new RegExp('(\\s*)' + uidAttr + '([0-9]+)' + uidAttr + '(\\s*)', 'g');
1044
- uidAttrLeadingPattern = new RegExp('^\\s*' + uidAttr + '(\\d+)' + uidAttr);
1045
-
1046
- if (options.minifyCSS) {
1047
- options.minifyCSS = (function (fn) {
1048
- return function (text, type) {
1049
- text = text.replace(uidPattern, function (match, prefix, index) {
1050
- const chunks = ignoredCustomMarkupChunks[+index];
1051
- return chunks[1] + uidAttr + index + uidAttr + chunks[2];
1052
- });
1053
-
1054
- return fn(text, type);
1055
- };
1056
- })(options.minifyCSS);
1057
- }
1034
+ // Fast path: The padded replace below is costly on large inputs because the
1035
+ // `\s{0,N}` padding makes the regex engine consume and backtrack at every
1036
+ // whitespace run; since the padding is optional and the fragment group requires
1037
+ // at least one match, a single unpadded probe that finds nothing proves the
1038
+ // replace would be a no-op—so skip it entirely
1039
+ const reFragmentProbe = new RegExp('(?:' + customFragments.join('|') + ')');
1040
+ if (reFragmentProbe.test(value)) {
1041
+ // Use bounded quantifiers to prevent ReDoS—this approach prevents exponential backtracking
1042
+ const reCustomIgnore = new RegExp(
1043
+ whitespacePattern + '(?:' + customFragments.join('|') + '){1,' + maxQuantifier + '}' + whitespacePattern,
1044
+ 'g'
1045
+ );
1046
+ // Temporarily replace custom ignored fragments with unique attributes
1047
+ value = value.replace(reCustomIgnore, function (match) {
1048
+ if (!uidAttr) {
1049
+ uidAttr = uniqueId(value);
1050
+ uidPattern = new RegExp('(\\s*)' + uidAttr + '([0-9]+)' + uidAttr + '(\\s*)', 'g');
1051
+ uidAttrLeadingPattern = new RegExp('^\\s*' + uidAttr + '(\\d+)' + uidAttr);
1052
+
1053
+ if (options.minifyCSS) {
1054
+ options.minifyCSS = (function (fn) {
1055
+ return function (text, type) {
1056
+ text = text.replace(uidPattern, function (match, prefix, index) {
1057
+ const chunks = ignoredCustomMarkupChunks[+index];
1058
+ return chunks[1] + uidAttr + index + uidAttr + chunks[2];
1059
+ });
1060
+
1061
+ return fn(text, type);
1062
+ };
1063
+ })(options.minifyCSS);
1064
+ }
1058
1065
 
1059
- if (options.minifyJS) {
1060
- options.minifyJS = (function (fn) {
1061
- return function (text, inline, isModule) {
1062
- return fn(text.replace(uidPattern, function (match, prefix, index) {
1063
- const chunks = ignoredCustomMarkupChunks[+index];
1064
- return chunks[1] + uidAttr + index + uidAttr + chunks[2];
1065
- }), inline, isModule);
1066
- };
1067
- })(options.minifyJS);
1066
+ if (options.minifyJS) {
1067
+ options.minifyJS = (function (fn) {
1068
+ return function (text, inline, isModule) {
1069
+ return fn(text.replace(uidPattern, function (match, prefix, index) {
1070
+ const chunks = ignoredCustomMarkupChunks[+index];
1071
+ return chunks[1] + uidAttr + index + uidAttr + chunks[2];
1072
+ }), inline, isModule);
1073
+ };
1074
+ })(options.minifyJS);
1075
+ }
1068
1076
  }
1069
- }
1070
1077
 
1071
- const token = uidAttr + ignoredCustomMarkupChunks.length + uidAttr;
1072
- ignoredCustomMarkupChunks.push(/^(\s*)[\s\S]*?(\s*)$/.exec(match));
1073
- return '\t' + token + '\t';
1074
- });
1078
+ const token = uidAttr + ignoredCustomMarkupChunks.length + uidAttr;
1079
+ ignoredCustomMarkupChunks.push(/^(\s*)[\s\S]*?(\s*)$/.exec(match));
1080
+ return '\t' + token + '\t';
1081
+ });
1082
+ }
1075
1083
  }
1076
1084
 
1077
1085
  function canCollapseWhitespace(tag, attrs) {