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 +11 -9
- package/dist/htmlminifier.cjs +13 -0
- package/dist/htmlminifier.esm.bundle.js +13 -0
- package/dist/types/lib/attributes.d.ts.map +1 -1
- package/dist/types/lib/constants.d.ts +13 -1
- package/dist/types/lib/constants.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/lib/attributes.js +10 -0
- package/src/lib/constants.js +3 -0
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>[](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/) |
|
|
297
297
|
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
|
298
|
-
| [A List Apart](https://alistapart.com/) | 59 | **
|
|
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/) |
|
|
301
|
-
| [CERN](https://home.cern/) | 152 |
|
|
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/) |
|
|
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 |
|
|
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/) |
|
|
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 |
|
|
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** | |
|
|
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
|
|
326
|
+
(Last updated: Dec 21, 2025)
|
|
325
327
|
<!-- End auto-generated -->
|
|
326
328
|
|
|
327
329
|
## Examples
|
package/dist/htmlminifier.cjs
CHANGED
|
@@ -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,
|
|
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
|
|
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
|
|
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
package/src/lib/attributes.js
CHANGED
|
@@ -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) {
|
package/src/lib/constants.js
CHANGED
|
@@ -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' }
|