html-minifier-next 4.14.0 → 4.14.1

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
@@ -295,33 +295,35 @@ How does HTML Minifier Next compare to other minifiers? (All with the most aggre
295
295
  <!-- Auto-generated benchmarks, don’t edit -->
296
296
  | Site | Original Size (KB) | [HTML Minifier Next](https://github.com/j9t/html-minifier-next) ([config](https://github.com/j9t/html-minifier-next/blob/main/benchmarks/html-minifier.json))<br>[![npm last update](https://img.shields.io/npm/last-update/html-minifier-next)](https://socket.dev/npm/package/html-minifier-next) | [HTML Minifier Terser](https://github.com/terser/html-minifier-terser)<br>[![npm last update](https://img.shields.io/npm/last-update/html-minifier-terser)](https://socket.dev/npm/package/html-minifier-terser) | [htmlnano](https://github.com/posthtml/htmlnano)<br>[![npm last update](https://img.shields.io/npm/last-update/htmlnano)](https://socket.dev/npm/package/htmlnano) | [@swc/html](https://github.com/swc-project/swc)<br>[![npm last update](https://img.shields.io/npm/last-update/@swc/html)](https://socket.dev/npm/package/@swc/html) | [minify-html](https://github.com/wilsonzlin/minify-html)<br>[![npm last update](https://img.shields.io/npm/last-update/@minify-html/node)](https://socket.dev/npm/package/@minify-html/node) | [minimize](https://github.com/Swaagie/minimize)<br>[![npm last update](https://img.shields.io/npm/last-update/minimize)](https://socket.dev/npm/package/minimize) | [html­com­pressor.­com](https://htmlcompressor.com/) |
297
297
  | --- | --- | --- | --- | --- | --- | --- | --- | --- |
298
- | [A List Apart](https://alistapart.com/) | 59 | **50** | **50** | 51 | 52 | 51 | 54 | 52 |
298
+ | [A List Apart](https://alistapart.com/) | 59 | **49** | 50 | 51 | 52 | 51 | 54 | 52 |
299
299
  | [Apple](https://www.apple.com/) | 266 | **207** | **207** | 236 | 239 | 240 | 242 | 243 |
300
- | [BBC](https://www.bbc.co.uk/) | 701 | **636** | 646 | 658 | 659 | 660 | 695 | n/a |
301
- | [CERN](https://home.cern/) | 152 | 85 | **84** | 91 | 91 | 91 | 93 | 96 |
300
+ | [BBC](https://www.bbc.co.uk/) | 730 | **663** | 673 | 685 | 686 | 687 | 724 | n/a |
301
+ | [CERN](https://home.cern/) | 152 | **83** | 84 | 91 | 91 | 91 | 93 | 96 |
302
302
  | [CSS-Tricks](https://css-tricks.com/) | 162 | 121 | **120** | 127 | 143 | 143 | 148 | 145 |
303
303
  | [ECMAScript](https://tc39.es/ecma262/) | 7250 | **6352** | **6352** | 6573 | 6455 | 6578 | 6626 | n/a |
304
304
  | [EDRi](https://edri.org/) | 80 | **59** | 60 | 70 | 70 | 71 | 75 | 73 |
305
305
  | [EFF](https://www.eff.org/) | 55 | **45** | 46 | 49 | 48 | 48 | 50 | 50 |
306
306
  | [European Alternatives](https://european-alternatives.eu/) | 48 | **30** | **30** | 32 | 32 | 32 | 32 | 32 |
307
- | [FAZ](https://www.faz.net/aktuell/) | 1603 | 1494 | 1499 | **1437** | 1526 | 1538 | 1549 | n/a |
307
+ | [FAZ](https://www.faz.net/aktuell/) | 1562 | 1455 | 1460 | **1401** | 1487 | 1498 | 1509 | n/a |
308
308
  | [French Tech](https://lafrenchtech.gouv.fr/) | 152 | **122** | **122** | 126 | 125 | 125 | 132 | 127 |
309
- | [Frontend Dogma](https://frontenddogma.com/) | 224 | **214** | 216 | 237 | 222 | 224 | 243 | 223 |
309
+ | [Frontend Dogma](https://frontenddogma.com/) | 224 | **214** | 216 | 237 | 222 | 224 | 243 | 224 |
310
310
  | [Google](https://www.google.com/) | 18 | **16** | 17 | 17 | 17 | 17 | 18 | 18 |
311
- | [Ground News](https://ground.news/) | 1713 | **1476** | 1477 | 1577 | 1602 | 1607 | 1699 | n/a |
311
+ | [Ground News](https://ground.news/) | 2344 | **2062** | 2064 | 2159 | 2184 | 2188 | 2331 | n/a |
312
312
  | [HTML Living Standard](https://html.spec.whatwg.org/multipage/) | 149 | **147** | **147** | 153 | **147** | 149 | 155 | 149 |
313
313
  | [Igalia](https://www.igalia.com/) | 50 | **34** | **34** | 36 | 36 | 36 | 37 | 37 |
314
+ | [Leanpub](https://leanpub.com/) | 222 | 192 | **190** | 207 | 207 | 207 | 217 | 219 |
314
315
  | [Mastodon](https://mastodon.social/explore) | 37 | **28** | **28** | 32 | 35 | 35 | 36 | 36 |
315
316
  | [MDN](https://developer.mozilla.org/en-US/) | 109 | **62** | **62** | 64 | 65 | 65 | 68 | 68 |
316
- | [Middle East Eye](https://www.middleeasteye.net/) | 222 | **195** | **195** | 202 | 200 | 200 | 202 | 203 |
317
+ | [Middle East Eye](https://www.middleeasteye.net/) | 222 | **195** | **195** | 202 | 200 | 200 | 202 | 202 |
317
318
  | [Nielsen Norman Group](https://www.nngroup.com/) | 86 | 74 | 74 | **55** | 74 | 75 | 77 | 76 |
318
319
  | [SitePoint](https://www.sitepoint.com/) | 501 | **370** | **370** | 442 | 475 | 480 | 498 | n/a |
319
320
  | [TetraLogical](https://tetralogical.com/) | 44 | 38 | 38 | **35** | 38 | 39 | 39 | 39 |
320
321
  | [TPGi](https://www.tpgi.com/) | 175 | **159** | 161 | 160 | 164 | 166 | 172 | 172 |
322
+ | [United Nations](https://www.un.org/en/) | 152 | **113** | 114 | 121 | 125 | 125 | 131 | 124 |
321
323
  | [W3C](https://www.w3.org/) | 50 | **36** | **36** | 39 | 38 | 38 | 41 | 39 |
322
- | **Average processing time** | | 256 ms (24/24) | 352 ms (24/24) | 167 ms (24/24) | 54 ms (24/24) | **15 ms (24/24)** | 339 ms (24/24) | 3288 ms (19/24) |
324
+ | **Average processing time** | | 264 ms (26/26) | 365 ms (26/26) | 162 ms (26/26) | 56 ms (26/26) | **16 ms (26/26)** | 323 ms (26/26) | 1373 ms (21/26) |
323
325
 
324
- (Last updated: Dec 20, 2025)
326
+ (Last updated: Dec 21, 2025)
325
327
  <!-- End auto-generated -->
326
328
 
327
329
  ## Examples
@@ -928,10 +928,13 @@ const tagDefaults = {
928
928
  colorspace: 'limited-srgb',
929
929
  type: 'text'
930
930
  },
931
+ link: { media: 'all' },
931
932
  marquee: {
932
933
  behavior: 'scroll',
933
934
  direction: 'left'
934
935
  },
936
+ meta: { media: 'all' },
937
+ source: { media: 'all' },
935
938
  style: { media: 'all' },
936
939
  textarea: { wrap: 'soft' },
937
940
  track: { kind: 'subtitles' }
@@ -1782,6 +1785,11 @@ async function cleanAttributeValue(tag, attrName, attrValue, options, attrs, min
1782
1785
  }
1783
1786
  try {
1784
1787
  attrValue = await options.minifyCSS(attrValue, 'inline');
1788
+ // After minification, check if CSS consists entirely of invalid properties (no values)
1789
+ // E.g., `color:` or `margin:;padding:` should be treated as empty
1790
+ if (attrValue && /^(?:[a-z-]+:\s*;?\s*)+$/i.test(attrValue)) {
1791
+ attrValue = '';
1792
+ }
1785
1793
  } catch (err) {
1786
1794
  if (!options.continueOnMinifyError) {
1787
1795
  throw err;
@@ -1830,6 +1838,11 @@ async function cleanAttributeValue(tag, attrName, attrValue, options, attrs, min
1830
1838
  attrValue = trimWhitespace(attrValue.replace(/\s*;\s*/g, ';'));
1831
1839
  } else if (isMediaQuery(tag, attrs, attrName)) {
1832
1840
  attrValue = trimWhitespace(attrValue);
1841
+ // Only minify actual media queries (those with features in parentheses)
1842
+ // Skip simple media types like `all`, `screen`, `print` which are already minimal
1843
+ if (!/[()]/.test(attrValue)) {
1844
+ return attrValue;
1845
+ }
1833
1846
  try {
1834
1847
  return await options.minifyCSS(attrValue, 'media');
1835
1848
  } catch (err) {
@@ -3540,10 +3540,13 @@ const tagDefaults = {
3540
3540
  colorspace: 'limited-srgb',
3541
3541
  type: 'text'
3542
3542
  },
3543
+ link: { media: 'all' },
3543
3544
  marquee: {
3544
3545
  behavior: 'scroll',
3545
3546
  direction: 'left'
3546
3547
  },
3548
+ meta: { media: 'all' },
3549
+ source: { media: 'all' },
3547
3550
  style: { media: 'all' },
3548
3551
  textarea: { wrap: 'soft' },
3549
3552
  track: { kind: 'subtitles' }
@@ -6924,6 +6927,11 @@ async function cleanAttributeValue(tag, attrName, attrValue, options, attrs, min
6924
6927
  }
6925
6928
  try {
6926
6929
  attrValue = await options.minifyCSS(attrValue, 'inline');
6930
+ // After minification, check if CSS consists entirely of invalid properties (no values)
6931
+ // E.g., `color:` or `margin:;padding:` should be treated as empty
6932
+ if (attrValue && /^(?:[a-z-]+:\s*;?\s*)+$/i.test(attrValue)) {
6933
+ attrValue = '';
6934
+ }
6927
6935
  } catch (err) {
6928
6936
  if (!options.continueOnMinifyError) {
6929
6937
  throw err;
@@ -6972,6 +6980,11 @@ async function cleanAttributeValue(tag, attrName, attrValue, options, attrs, min
6972
6980
  attrValue = trimWhitespace(attrValue.replace(/\s*;\s*/g, ';'));
6973
6981
  } else if (isMediaQuery(tag, attrs, attrName)) {
6974
6982
  attrValue = trimWhitespace(attrValue);
6983
+ // Only minify actual media queries (those with features in parentheses)
6984
+ // Skip simple media types like `all`, `screen`, `print` which are already minimal
6985
+ if (!/[()]/.test(attrValue)) {
6986
+ return attrValue;
6987
+ }
6975
6988
  try {
6976
6989
  return await options.minifyCSS(attrValue, 'media');
6977
6990
  } catch (err) {
@@ -1 +1 @@
1
- {"version":3,"file":"attributes.d.ts","sourceRoot":"","sources":["../../../src/lib/attributes.js"],"names":[],"mappings":"AAsBA,yDAEC;AAED,mEAOC;AAED,uEAWC;AAED,8DAGC;AAED,4EAOC;AAED,mGAqBC;AAED,mEAGC;AAED,qEAGC;AAED,kEAWC;AAED,sEAGC;AAED,4DAWC;AAED,2EAEC;AAED,qEAaC;AAED,wEAUC;AAED,sEAUC;AAED,2EAEC;AAED,2DAEC;AAED,8DAUC;AAED,uEAUC;AAED,oGASC;AAED,4DAOC;AAID,0IAqHC;AAsBD;;;;GAsCC;AAED,6GA4EC"}
1
+ {"version":3,"file":"attributes.d.ts","sourceRoot":"","sources":["../../../src/lib/attributes.js"],"names":[],"mappings":"AAsBA,yDAEC;AAED,mEAOC;AAED,uEAWC;AAED,8DAGC;AAED,4EAOC;AAED,mGAqBC;AAED,mEAGC;AAED,qEAGC;AAED,kEAWC;AAED,sEAGC;AAED,4DAWC;AAED,2EAEC;AAED,qEAaC;AAED,wEAUC;AAED,sEAUC;AAED,2EAEC;AAED,2DAEC;AAED,8DAUC;AAED,uEAUC;AAED,oGASC;AAED,4DAOC;AAID,0IA+HC;AAsBD;;;;GAsCC;AAED,6GA4EC"}
@@ -41,12 +41,24 @@ export namespace tagDefaults {
41
41
  let type_1: string;
42
42
  export { type_1 as type };
43
43
  }
44
+ namespace link {
45
+ let media: string;
46
+ }
44
47
  namespace marquee {
45
48
  let behavior: string;
46
49
  let direction: string;
47
50
  }
51
+ namespace meta {
52
+ let media_1: string;
53
+ export { media_1 as media };
54
+ }
55
+ namespace source {
56
+ let media_2: string;
57
+ export { media_2 as media };
58
+ }
48
59
  namespace style {
49
- let media: string;
60
+ let media_3: string;
61
+ export { media_3 as media };
50
62
  }
51
63
  namespace textarea {
52
64
  let wrap: string;
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/lib/constants.js"],"names":[],"mappings":"AAEA,iCAAoC;AACpC,+BAAkC;AAClC,oCAA2C;AAC3C,2CAAmD;AACnD,wCAA8C;AAC9C,4CAAkD;AAClD,4CAA2C;AAC3C,4CAA0D;AAC1D,2CAA8C;AAC9C,+CAA0D;AAC1D,2CAAmC;AACnC,mCAA4C;AAK5C,+DAAgb;AAGhb,+DAA6O;AAG7O,yDAAmF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCnF,qDAQG;AAEH,+CAEG;AAcH,0CAUG;AApBH,0CAAwhB;AAExhB,yCAAkD;AAIlD,qCAA8C;AAuB9C,4CAAiF;AAEjF,0CAAoM;AAEpM,qCAAwF;AAExF,0CAA8C;AAE9C,qCAA6S;AAE7S,sCAAsF;AAEtF,6CAA8D;AAE9D,gDAAqD;AAErD,oCAAkD;AAElD,2CAAqD;AAErD,2CAA8D;AAE9D,mCAAuC;AAEvC,uCAAuD;AAEvD,sCAA8C;AAE9C,oCAA2D;AAE3D,uCAA8C;AAE9C,mCAA+wC;AAI/wC,sCAEsD;AAItD,6CAAwD"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/lib/constants.js"],"names":[],"mappings":"AAEA,iCAAoC;AACpC,+BAAkC;AAClC,oCAA2C;AAC3C,2CAAmD;AACnD,wCAA8C;AAC9C,4CAAkD;AAClD,4CAA2C;AAC3C,4CAA0D;AAC1D,2CAA8C;AAC9C,+CAA0D;AAC1D,2CAAmC;AACnC,mCAA4C;AAK5C,+DAAgb;AAGhb,+DAA6O;AAG7O,yDAAmF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0CnF,qDAQG;AAEH,+CAEG;AAcH,0CAUG;AApBH,0CAAwhB;AAExhB,yCAAkD;AAIlD,qCAA8C;AAuB9C,4CAAiF;AAEjF,0CAAoM;AAEpM,qCAAwF;AAExF,0CAA8C;AAE9C,qCAA6S;AAE7S,sCAAsF;AAEtF,6CAA8D;AAE9D,gDAAqD;AAErD,oCAAkD;AAElD,2CAAqD;AAErD,2CAA8D;AAE9D,mCAAuC;AAEvC,uCAAuD;AAEvD,sCAA8C;AAE9C,oCAA2D;AAE3D,uCAA8C;AAE9C,mCAA+wC;AAI/wC,sCAEsD;AAItD,6CAAwD"}
package/package.json CHANGED
@@ -93,5 +93,5 @@
93
93
  "test:watch": "node --test --watch tests/*.spec.js"
94
94
  },
95
95
  "type": "module",
96
- "version": "4.14.0"
96
+ "version": "4.14.1"
97
97
  }
@@ -272,6 +272,11 @@ async function cleanAttributeValue(tag, attrName, attrValue, options, attrs, min
272
272
  }
273
273
  try {
274
274
  attrValue = await options.minifyCSS(attrValue, 'inline');
275
+ // After minification, check if CSS consists entirely of invalid properties (no values)
276
+ // E.g., `color:` or `margin:;padding:` should be treated as empty
277
+ if (attrValue && /^(?:[a-z-]+:\s*;?\s*)+$/i.test(attrValue)) {
278
+ attrValue = '';
279
+ }
275
280
  } catch (err) {
276
281
  if (!options.continueOnMinifyError) {
277
282
  throw err;
@@ -320,6 +325,11 @@ async function cleanAttributeValue(tag, attrName, attrValue, options, attrs, min
320
325
  attrValue = trimWhitespace(attrValue.replace(/\s*;\s*/g, ';'));
321
326
  } else if (isMediaQuery(tag, attrs, attrName)) {
322
327
  attrValue = trimWhitespace(attrValue);
328
+ // Only minify actual media queries (those with features in parentheses)
329
+ // Skip simple media types like `all`, `screen`, `print` which are already minimal
330
+ if (!/[()]/.test(attrValue)) {
331
+ return attrValue;
332
+ }
323
333
  try {
324
334
  return await options.minifyCSS(attrValue, 'media');
325
335
  } catch (err) {
@@ -48,10 +48,13 @@ const tagDefaults = {
48
48
  colorspace: 'limited-srgb',
49
49
  type: 'text'
50
50
  },
51
+ link: { media: 'all' },
51
52
  marquee: {
52
53
  behavior: 'scroll',
53
54
  direction: 'left'
54
55
  },
56
+ meta: { media: 'all' },
57
+ source: { media: 'all' },
55
58
  style: { media: 'all' },
56
59
  textarea: { wrap: 'soft' },
57
60
  track: { kind: 'subtitles' }