html-minifier-next 4.12.2 → 4.14.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.
Files changed (37) hide show
  1. package/README.md +84 -26
  2. package/cli.js +1 -1
  3. package/dist/htmlminifier.cjs +1552 -1320
  4. package/dist/htmlminifier.esm.bundle.js +4204 -3972
  5. package/dist/types/htmlminifier.d.ts +10 -3
  6. package/dist/types/htmlminifier.d.ts.map +1 -1
  7. package/dist/types/htmlparser.d.ts.map +1 -1
  8. package/dist/types/lib/attributes.d.ts +29 -0
  9. package/dist/types/lib/attributes.d.ts.map +1 -0
  10. package/dist/types/lib/constants.d.ts +83 -0
  11. package/dist/types/lib/constants.d.ts.map +1 -0
  12. package/dist/types/lib/content.d.ts +7 -0
  13. package/dist/types/lib/content.d.ts.map +1 -0
  14. package/dist/types/lib/elements.d.ts +39 -0
  15. package/dist/types/lib/elements.d.ts.map +1 -0
  16. package/dist/types/lib/options.d.ts +17 -0
  17. package/dist/types/lib/options.d.ts.map +1 -0
  18. package/dist/types/lib/utils.d.ts +21 -0
  19. package/dist/types/lib/utils.d.ts.map +1 -0
  20. package/dist/types/lib/whitespace.d.ts +7 -0
  21. package/dist/types/lib/whitespace.d.ts.map +1 -0
  22. package/dist/types/presets.d.ts.map +1 -1
  23. package/package.json +10 -1
  24. package/src/htmlminifier.js +114 -1229
  25. package/src/htmlparser.js +11 -11
  26. package/src/lib/attributes.js +511 -0
  27. package/src/lib/constants.js +213 -0
  28. package/src/lib/content.js +105 -0
  29. package/src/lib/elements.js +242 -0
  30. package/src/lib/index.js +20 -0
  31. package/src/lib/options.js +300 -0
  32. package/src/lib/utils.js +90 -0
  33. package/src/lib/whitespace.js +139 -0
  34. package/src/presets.js +0 -1
  35. package/src/tokenchain.js +1 -1
  36. package/dist/types/utils.d.ts +0 -2
  37. package/dist/types/utils.d.ts.map +0 -1
package/README.md CHANGED
@@ -161,7 +161,7 @@ Options can be used in config files (camelCase) or via CLI flags (kebab-case wit
161
161
  | `maxInputLength`<br>`--max-input-length` | Maximum input length to prevent ReDoS attacks (disabled by default) | `undefined` |
162
162
  | `maxLineLength`<br>`--max-line-length` | Specify a maximum line length; compressed output will be split by newlines at valid HTML split-points | |
163
163
  | `minifyCSS`<br>`--minify-css` | Minify CSS in `style` elements and `style` attributes (uses [Lightning CSS](https://lightningcss.dev/)) | `false` (could be `true`, `Object`, `Function(text, type)`) |
164
- | `minifyJS`<br>`--minify-js` | Minify JavaScript in `script` elements and event attributes (uses [Terser](https://github.com/terser/terser)) | `false` (could be `true`, `Object`, `Function(text, inline)`) |
164
+ | `minifyJS`<br>`--minify-js` | Minify JavaScript in `script` elements and event attributes (uses [Terser](https://github.com/terser/terser) or [SWC](https://swc.rs/)) | `false` (could be `true`, `Object`, `Function(text, inline)`) |
165
165
  | `minifyURLs`<br>`--minify-urls` | Minify URLs in various attributes (uses [relateurl](https://github.com/stevenvachon/relateurl)) | `false` (could be `String`, `Object`, `Function(text)`, `async Function(text)`) |
166
166
  | `noNewlinesBeforeTagClose`<br>`--no-newlines-before-tag-close` | Never add a newline before a tag that closes an element | `false` |
167
167
  | `partialMarkup`<br>`--partial-markup` | Treat input as a partial HTML fragment, preserving stray end tags (closing tags without opening tags) and preventing auto-closing of unclosed tags at end of input | `false` |
@@ -189,7 +189,7 @@ Options can be used in config files (camelCase) or via CLI flags (kebab-case wit
189
189
 
190
190
  Minifier options like `sortAttributes` and `sortClassName` won’t impact the plain‑text size of the output. However, using these options for more consistent ordering improves the compression ratio for gzip and Brotli used over HTTP.
191
191
 
192
- ### CSS minification with Lightning CSS
192
+ ### CSS minification
193
193
 
194
194
  When `minifyCSS` is set to `true`, HTML Minifier Next uses [Lightning CSS](https://lightningcss.dev/) to minify CSS in `<style>` elements and `style` attributes. Lightning CSS provides excellent minification by default.
195
195
 
@@ -228,42 +228,100 @@ const result = await minify(html, {
228
228
  });
229
229
  ```
230
230
 
231
+ ### JavaScript minification
232
+
233
+ When `minifyJS` is set to `true`, HTML Minifier Next uses [Terser](https://github.com/terser/terser) by default to minify JavaScript in `<script>` elements and event attributes.
234
+
235
+ You can choose between different JS minifiers using the `engine` field:
236
+
237
+ ```js
238
+ const result = await minify(html, {
239
+ minifyJS: {
240
+ engine: 'swc', // Use swc for faster minification
241
+ // SWC-specific options here
242
+ }
243
+ });
244
+ ```
245
+
246
+ **Available engines:**
247
+
248
+ * `terser` (default): The standard JavaScript minifier with excellent compression
249
+ * [`swc`](https://swc.rs/): Rust-based minifier that’s significantly faster than Terser (requires separate installation)
250
+
251
+ **To use swc**, install it as a dependency:
252
+
253
+ ```bash
254
+ npm i @swc/core
255
+ ```
256
+
257
+ **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
+
259
+ You can pass engine-specific configuration options:
260
+
261
+ ```js
262
+ // Using Terser with custom options
263
+ const result = await minify(html, {
264
+ minifyJS: {
265
+ compress: {
266
+ drop_console: true // Remove console.log statements
267
+ }
268
+ }
269
+ });
270
+
271
+ // Using SWC for faster minification
272
+ const result = await minify(html, {
273
+ minifyJS: {
274
+ engine: 'swc'
275
+ }
276
+ });
277
+ ```
278
+
279
+ For advanced usage, you can also pass a function:
280
+
281
+ ```js
282
+ const result = await minify(html, {
283
+ minifyJS: function(text, inline) {
284
+ // `text`: JavaScript string to minify
285
+ // `inline`: `true` for event handlers (e.g., `onclick`), `false` for `<script>` elements
286
+ return yourCustomMinifier(text);
287
+ }
288
+ });
289
+ ```
290
+
231
291
  ## Minification comparison
232
292
 
233
- How does HTML Minifier Next compare to other minifiers? (All with the most aggressive settings, though without [hyper-optimization](https://meiert.com/blog/the-ways-of-writing-html/#toc-hyper-optimized). Minimize does not minify CSS or JS.)
293
+ How does HTML Minifier Next compare to other minifiers? (All with the most aggressive settingsthough without [hyper-optimization](https://meiert.com/blog/the-ways-of-writing-html/#toc-hyper-optimized)—and against some large documents.—Minimize does not minify CSS or JS.)
234
294
 
235
295
  <!-- Auto-generated benchmarks, don’t edit -->
236
- | Site | Original Size (KB) | [HTML Minifier Next](https://github.com/j9t/html-minifier-next)<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/) |
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/) |
237
297
  | --- | --- | --- | --- | --- | --- | --- | --- | --- |
238
- | [A List Apart](https://alistapart.com/) | 59 | **49** | 50 | 51 | 52 | 51 | 54 | 52 |
298
+ | [A List Apart](https://alistapart.com/) | 59 | **50** | **50** | 51 | 52 | 51 | 54 | 52 |
239
299
  | [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
- | [CERN](https://home.cern/) | 156 | **87** | **87** | 95 | 95 | 95 | 97 | 100 |
242
- | [CSS-Tricks](https://css-tricks.com/) | 161 | 121 | **119** | 127 | 142 | 142 | 147 | 144 |
243
- | [ECMAScript](https://tc39.es/ecma262/) | 7238 | **6341** | **6341** | 6561 | 6444 | 6567 | 6614 | n/a |
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 |
302
+ | [CSS-Tricks](https://css-tricks.com/) | 162 | 121 | **120** | 127 | 143 | 143 | 148 | 145 |
303
+ | [ECMAScript](https://tc39.es/ecma262/) | 7250 | **6352** | **6352** | 6573 | 6455 | 6578 | 6626 | n/a |
244
304
  | [EDRi](https://edri.org/) | 80 | **59** | 60 | 70 | 70 | 71 | 75 | 73 |
245
- | [EFF](https://www.eff.org/) | 55 | **47** | **47** | 50 | 48 | 49 | 50 | 50 |
305
+ | [EFF](https://www.eff.org/) | 55 | **45** | 46 | 49 | 48 | 48 | 50 | 50 |
246
306
  | [European Alternatives](https://european-alternatives.eu/) | 48 | **30** | **30** | 32 | 32 | 32 | 32 | 32 |
247
- | [FAZ](https://www.faz.net/aktuell/) | 1543 | 1436 | 1441 | **1383** | 1468 | 1479 | 1490 | n/a |
248
- | [French Tech](https://lafrenchtech.gouv.fr/) | 152 | **121** | 122 | 125 | 125 | 125 | 132 | 126 |
249
- | [Frontend Dogma](https://frontenddogma.com/) | 223 | **213** | 215 | 236 | 221 | 223 | 241 | 222 |
250
- | [Google](https://www.google.com/) | 18 | **17** | **17** | **17** | **17** | **17** | 18 | 18 |
251
- | [Ground News](https://ground.news/) | 1437 | **1222** | 1225 | 1320 | 1346 | 1353 | 1424 | n/a |
307
+ | [FAZ](https://www.faz.net/aktuell/) | 1603 | 1494 | 1499 | **1437** | 1526 | 1538 | 1549 | n/a |
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 |
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 |
252
312
  | [HTML Living Standard](https://html.spec.whatwg.org/multipage/) | 149 | **147** | **147** | 153 | **147** | 149 | 155 | 149 |
253
313
  | [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
- | [Mastodon](https://mastodon.social/explore) | 37 | **27** | **27** | 32 | 34 | 35 | 35 | 35 |
314
+ | [Mastodon](https://mastodon.social/explore) | 37 | **28** | **28** | 32 | 35 | 35 | 36 | 36 |
256
315
  | [MDN](https://developer.mozilla.org/en-US/) | 109 | **62** | **62** | 64 | 65 | 65 | 68 | 68 |
257
- | [Middle East Eye](https://www.middleeasteye.net/) | 223 | **196** | **196** | 203 | 201 | 200 | 202 | 203 |
316
+ | [Middle East Eye](https://www.middleeasteye.net/) | 222 | **195** | **195** | 202 | 200 | 200 | 202 | 203 |
258
317
  | [Nielsen Norman Group](https://www.nngroup.com/) | 86 | 74 | 74 | **55** | 74 | 75 | 77 | 76 |
259
- | [SitePoint](https://www.sitepoint.com/) | 485 | **354** | **354** | 425 | 459 | 464 | 481 | n/a |
260
- | [TetraLogical](https://tetralogical.com/) | 44 | 38 | 38 | **35** | 38 | 38 | 39 | 39 |
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
-
266
- (Last updated: Dec 17, 2025)
318
+ | [SitePoint](https://www.sitepoint.com/) | 501 | **370** | **370** | 442 | 475 | 480 | 498 | n/a |
319
+ | [TetraLogical](https://tetralogical.com/) | 44 | 38 | 38 | **35** | 38 | 39 | 39 | 39 |
320
+ | [TPGi](https://www.tpgi.com/) | 175 | **159** | 161 | 160 | 164 | 166 | 172 | 172 |
321
+ | [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) |
323
+
324
+ (Last updated: Dec 20, 2025)
267
325
  <!-- End auto-generated -->
268
326
 
269
327
  ## Examples
package/cli.js CHANGED
@@ -141,7 +141,7 @@ const mainOptions = {
141
141
  maxInputLength: ['Maximum input length to prevent ReDoS attacks', parseValidInt('maxInputLength')],
142
142
  maxLineLength: ['Specify a maximum line length; compressed output will be split by newlines at valid HTML split-points', parseValidInt('maxLineLength')],
143
143
  minifyCSS: ['Minify CSS in “style” elements and “style” attributes (uses Lightning CSS)', parseJSON],
144
- minifyJS: ['Minify JavaScript in “script” elements and event attributes (uses Terser)', parseJSON],
144
+ minifyJS: ['Minify JavaScript in “script” elements and event attributes (uses Terser or SWC; pass “{"engine": "swc"}” for SWC)', parseJSON],
145
145
  minifyURLs: ['Minify URLs in various attributes (uses relateurl)', parseJSON],
146
146
  noNewlinesBeforeTagClose: 'Never add a newline before a tag that closes an element',
147
147
  partialMarkup: 'Treat input as a partial HTML fragment, preserving stray end tags and unclosed tags',