html-minifier-next 4.14.1 → 4.14.3
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 +35 -21
- package/dist/htmlminifier.cjs +14 -0
- package/dist/htmlminifier.esm.bundle.js +14 -0
- package/dist/types/lib/whitespace.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/lib/whitespace.js +16 -1
package/README.md
CHANGED
|
@@ -14,6 +14,12 @@ From npm for use as a command line app:
|
|
|
14
14
|
npm i -g html-minifier-next
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
+
Or use directly with npx (no installation required):
|
|
18
|
+
|
|
19
|
+
```shell
|
|
20
|
+
npx html-minifier-next --help
|
|
21
|
+
```
|
|
22
|
+
|
|
17
23
|
From npm for programmatic use:
|
|
18
24
|
|
|
19
25
|
```shell
|
|
@@ -67,7 +73,7 @@ module.exports = {
|
|
|
67
73
|
|
|
68
74
|
**Using a configuration file:**
|
|
69
75
|
|
|
70
|
-
```
|
|
76
|
+
```shell
|
|
71
77
|
# Specify config file
|
|
72
78
|
html-minifier-next --config-file=html-minifier.json --input-dir=src --output-dir=dist
|
|
73
79
|
|
|
@@ -116,7 +122,7 @@ To review the specific options set, [presets.js](https://github.com/j9t/html-min
|
|
|
116
122
|
|
|
117
123
|
**Using presets:**
|
|
118
124
|
|
|
119
|
-
```
|
|
125
|
+
```shell
|
|
120
126
|
# Via CLI flag
|
|
121
127
|
html-minifier-next --preset conservative input.html
|
|
122
128
|
|
|
@@ -237,7 +243,7 @@ You can choose between different JS minifiers using the `engine` field:
|
|
|
237
243
|
```js
|
|
238
244
|
const result = await minify(html, {
|
|
239
245
|
minifyJS: {
|
|
240
|
-
engine: 'swc', // Use
|
|
246
|
+
engine: 'swc', // Use SWC for faster minification
|
|
241
247
|
// SWC-specific options here
|
|
242
248
|
}
|
|
243
249
|
});
|
|
@@ -248,12 +254,14 @@ const result = await minify(html, {
|
|
|
248
254
|
* `terser` (default): The standard JavaScript minifier with excellent compression
|
|
249
255
|
* [`swc`](https://swc.rs/): Rust-based minifier that’s significantly faster than Terser (requires separate installation)
|
|
250
256
|
|
|
251
|
-
**To use
|
|
257
|
+
**To use SWC**, install it as a dependency:
|
|
252
258
|
|
|
253
|
-
```
|
|
259
|
+
```shell
|
|
254
260
|
npm i @swc/core
|
|
255
261
|
```
|
|
256
262
|
|
|
263
|
+
(Build-only users may want to install it as a dev dependency: `npm i -D @swc/core`.)
|
|
264
|
+
|
|
257
265
|
**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
266
|
|
|
259
267
|
You can pass engine-specific configuration options:
|
|
@@ -295,33 +303,33 @@ How does HTML Minifier Next compare to other minifiers? (All with the most aggre
|
|
|
295
303
|
<!-- Auto-generated benchmarks, don’t edit -->
|
|
296
304
|
| 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
305
|
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
|
298
|
-
| [A List Apart](https://alistapart.com/) | 59 | **
|
|
306
|
+
| [A List Apart](https://alistapart.com/) | 59 | **50** | **50** | 51 | 52 | 51 | 54 | 52 |
|
|
299
307
|
| [Apple](https://www.apple.com/) | 266 | **207** | **207** | 236 | 239 | 240 | 242 | 243 |
|
|
300
|
-
| [BBC](https://www.bbc.co.uk/) |
|
|
308
|
+
| [BBC](https://www.bbc.co.uk/) | 727 | **661** | 671 | 683 | 683 | 685 | 721 | n/a |
|
|
301
309
|
| [CERN](https://home.cern/) | 152 | **83** | 84 | 91 | 91 | 91 | 93 | 96 |
|
|
302
|
-
| [CSS-Tricks](https://css-tricks.com/) | 162 |
|
|
303
|
-
| [ECMAScript](https://tc39.es/ecma262/) | 7250 | **
|
|
310
|
+
| [CSS-Tricks](https://css-tricks.com/) | 162 | 122 | **120** | 127 | 143 | 143 | 148 | 145 |
|
|
311
|
+
| [ECMAScript](https://tc39.es/ecma262/) | 7250 | **6354** | **6354** | 6573 | 6455 | 6578 | 6626 | n/a |
|
|
304
312
|
| [EDRi](https://edri.org/) | 80 | **59** | 60 | 70 | 70 | 71 | 75 | 73 |
|
|
305
|
-
| [EFF](https://www.eff.org/) | 55 | **45** |
|
|
313
|
+
| [EFF](https://www.eff.org/) | 55 | **45** | 47 | 49 | 48 | 48 | 50 | 50 |
|
|
306
314
|
| [European Alternatives](https://european-alternatives.eu/) | 48 | **30** | **30** | 32 | 32 | 32 | 32 | 32 |
|
|
307
|
-
| [FAZ](https://www.faz.net/aktuell/) |
|
|
315
|
+
| [FAZ](https://www.faz.net/aktuell/) | 1591 | 1486 | 1491 | **1427** | 1515 | 1526 | 1538 | n/a |
|
|
308
316
|
| [French Tech](https://lafrenchtech.gouv.fr/) | 152 | **122** | **122** | 126 | 125 | 125 | 132 | 127 |
|
|
309
317
|
| [Frontend Dogma](https://frontenddogma.com/) | 224 | **214** | 216 | 237 | 222 | 224 | 243 | 224 |
|
|
310
318
|
| [Google](https://www.google.com/) | 18 | **16** | 17 | 17 | 17 | 17 | 18 | 18 |
|
|
311
|
-
| [Ground News](https://ground.news/) |
|
|
319
|
+
| [Ground News](https://ground.news/) | 2358 | **2076** | 2077 | 2173 | 2198 | 2202 | 2345 | n/a |
|
|
312
320
|
| [HTML Living Standard](https://html.spec.whatwg.org/multipage/) | 149 | **147** | **147** | 153 | **147** | 149 | 155 | 149 |
|
|
313
321
|
| [Igalia](https://www.igalia.com/) | 50 | **34** | **34** | 36 | 36 | 36 | 37 | 37 |
|
|
314
|
-
| [Leanpub](https://leanpub.com/) | 222 | 192 | **
|
|
322
|
+
| [Leanpub](https://leanpub.com/) | 222 | 192 | **191** | 207 | 207 | 207 | 217 | 219 |
|
|
315
323
|
| [Mastodon](https://mastodon.social/explore) | 37 | **28** | **28** | 32 | 35 | 35 | 36 | 36 |
|
|
316
324
|
| [MDN](https://developer.mozilla.org/en-US/) | 109 | **62** | **62** | 64 | 65 | 65 | 68 | 68 |
|
|
317
|
-
| [Middle East Eye](https://www.middleeasteye.net/) | 222 | **
|
|
325
|
+
| [Middle East Eye](https://www.middleeasteye.net/) | 222 | **196** | **196** | 202 | 200 | 200 | 202 | 203 |
|
|
318
326
|
| [Nielsen Norman Group](https://www.nngroup.com/) | 86 | 74 | 74 | **55** | 74 | 75 | 77 | 76 |
|
|
319
|
-
| [SitePoint](https://www.sitepoint.com/) |
|
|
327
|
+
| [SitePoint](https://www.sitepoint.com/) | 491 | **360** | **360** | 431 | 465 | 470 | 488 | n/a |
|
|
320
328
|
| [TetraLogical](https://tetralogical.com/) | 44 | 38 | 38 | **35** | 38 | 39 | 39 | 39 |
|
|
321
329
|
| [TPGi](https://www.tpgi.com/) | 175 | **159** | 161 | 160 | 164 | 166 | 172 | 172 |
|
|
322
330
|
| [United Nations](https://www.un.org/en/) | 152 | **113** | 114 | 121 | 125 | 125 | 131 | 124 |
|
|
323
331
|
| [W3C](https://www.w3.org/) | 50 | **36** | **36** | 39 | 38 | 38 | 41 | 39 |
|
|
324
|
-
| **Average processing time** | |
|
|
332
|
+
| **Average processing time** | | 259 ms (26/26) | 375 ms (26/26) | 164 ms (26/26) | 54 ms (26/26) | **16 ms (26/26)** | 327 ms (26/26) | 1497 ms (21/26) |
|
|
325
333
|
|
|
326
334
|
(Last updated: Dec 21, 2025)
|
|
327
335
|
<!-- End auto-generated -->
|
|
@@ -332,13 +340,19 @@ How does HTML Minifier Next compare to other minifiers? (All with the most aggre
|
|
|
332
340
|
|
|
333
341
|
**Sample command line:**
|
|
334
342
|
|
|
335
|
-
```
|
|
343
|
+
```shell
|
|
336
344
|
html-minifier-next --collapse-whitespace --remove-comments --minify-js --input-dir=. --output-dir=example
|
|
337
345
|
```
|
|
338
346
|
|
|
347
|
+
Another example, using npx:
|
|
348
|
+
|
|
349
|
+
```shell
|
|
350
|
+
npx html-minifier-next --input-dir=test --file-ext html --preset comprehensive --output-dir example
|
|
351
|
+
```
|
|
352
|
+
|
|
339
353
|
**Process specific files and directories:**
|
|
340
354
|
|
|
341
|
-
```
|
|
355
|
+
```shell
|
|
342
356
|
# Process only HTML files
|
|
343
357
|
html-minifier-next --collapse-whitespace --input-dir=src --output-dir=dist --file-ext=html
|
|
344
358
|
|
|
@@ -356,7 +370,7 @@ html-minifier-next --collapse-whitespace --input-dir=src --output-dir=dist
|
|
|
356
370
|
|
|
357
371
|
**Exclude directories from processing:**
|
|
358
372
|
|
|
359
|
-
```
|
|
373
|
+
```shell
|
|
360
374
|
# Ignore a single directory
|
|
361
375
|
html-minifier-next --collapse-whitespace --input-dir=src --output-dir=dist --ignore-dir=libs
|
|
362
376
|
|
|
@@ -369,7 +383,7 @@ html-minifier-next --collapse-whitespace --input-dir=src --output-dir=dist --ign
|
|
|
369
383
|
|
|
370
384
|
**Dry run mode (preview outcome without writing files):**
|
|
371
385
|
|
|
372
|
-
```
|
|
386
|
+
```shell
|
|
373
387
|
# Preview with output file
|
|
374
388
|
html-minifier-next input.html -o output.html --dry --collapse-whitespace
|
|
375
389
|
|
|
@@ -384,7 +398,7 @@ html-minifier-next --input-dir=src --output-dir=dist --dry --collapse-whitespace
|
|
|
384
398
|
|
|
385
399
|
**Verbose mode (show detailed processing information):**
|
|
386
400
|
|
|
387
|
-
```
|
|
401
|
+
```shell
|
|
388
402
|
# Show processing details while minifying
|
|
389
403
|
html-minifier-next --input-dir=src --output-dir=dist --verbose --collapse-whitespace
|
|
390
404
|
# Output: Options: collapseWhitespace, html5, includeAutoGeneratedTags
|
package/dist/htmlminifier.cjs
CHANGED
|
@@ -1135,10 +1135,24 @@ function collapseWhitespaceSmart(str, prevTag, nextTag, options, inlineElements,
|
|
|
1135
1135
|
if (trimLeft && !options.collapseInlineTagWhitespace) {
|
|
1136
1136
|
trimLeft = prevTag.charAt(0) === '/' ? !inlineElements.has(prevTag.slice(1)) : !inlineTextSet.has(prevTag);
|
|
1137
1137
|
}
|
|
1138
|
+
// When `collapseInlineTagWhitespace` is enabled, still preserve whitespace around inline text elements
|
|
1139
|
+
if (trimLeft && options.collapseInlineTagWhitespace) {
|
|
1140
|
+
const tagName = prevTag.charAt(0) === '/' ? prevTag.slice(1) : prevTag;
|
|
1141
|
+
if (inlineElementsToKeepWhitespaceWithin.has(tagName)) {
|
|
1142
|
+
trimLeft = false;
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1138
1145
|
let trimRight = nextTag && !inlineElementsToKeepWhitespace.has(nextTag);
|
|
1139
1146
|
if (trimRight && !options.collapseInlineTagWhitespace) {
|
|
1140
1147
|
trimRight = nextTag.charAt(0) === '/' ? !inlineTextSet.has(nextTag.slice(1)) : !inlineElements.has(nextTag);
|
|
1141
1148
|
}
|
|
1149
|
+
// When `collapseInlineTagWhitespace` is enabled, still preserve whitespace around inline text elements
|
|
1150
|
+
if (trimRight && options.collapseInlineTagWhitespace) {
|
|
1151
|
+
const tagName = nextTag.charAt(0) === '/' ? nextTag.slice(1) : nextTag;
|
|
1152
|
+
if (inlineElementsToKeepWhitespaceWithin.has(tagName)) {
|
|
1153
|
+
trimRight = false;
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1142
1156
|
return collapseWhitespace(str, options, trimLeft, trimRight, prevTag && nextTag);
|
|
1143
1157
|
}
|
|
1144
1158
|
|
|
@@ -3747,10 +3747,24 @@ function collapseWhitespaceSmart(str, prevTag, nextTag, options, inlineElements,
|
|
|
3747
3747
|
if (trimLeft && !options.collapseInlineTagWhitespace) {
|
|
3748
3748
|
trimLeft = prevTag.charAt(0) === '/' ? !inlineElements.has(prevTag.slice(1)) : !inlineTextSet.has(prevTag);
|
|
3749
3749
|
}
|
|
3750
|
+
// When `collapseInlineTagWhitespace` is enabled, still preserve whitespace around inline text elements
|
|
3751
|
+
if (trimLeft && options.collapseInlineTagWhitespace) {
|
|
3752
|
+
const tagName = prevTag.charAt(0) === '/' ? prevTag.slice(1) : prevTag;
|
|
3753
|
+
if (inlineElementsToKeepWhitespaceWithin.has(tagName)) {
|
|
3754
|
+
trimLeft = false;
|
|
3755
|
+
}
|
|
3756
|
+
}
|
|
3750
3757
|
let trimRight = nextTag && !inlineElementsToKeepWhitespace.has(nextTag);
|
|
3751
3758
|
if (trimRight && !options.collapseInlineTagWhitespace) {
|
|
3752
3759
|
trimRight = nextTag.charAt(0) === '/' ? !inlineTextSet.has(nextTag.slice(1)) : !inlineElements.has(nextTag);
|
|
3753
3760
|
}
|
|
3761
|
+
// When `collapseInlineTagWhitespace` is enabled, still preserve whitespace around inline text elements
|
|
3762
|
+
if (trimRight && options.collapseInlineTagWhitespace) {
|
|
3763
|
+
const tagName = nextTag.charAt(0) === '/' ? nextTag.slice(1) : nextTag;
|
|
3764
|
+
if (inlineElementsToKeepWhitespaceWithin.has(tagName)) {
|
|
3765
|
+
trimRight = false;
|
|
3766
|
+
}
|
|
3767
|
+
}
|
|
3754
3768
|
return collapseWhitespace(str, options, trimLeft, trimRight, prevTag && nextTag);
|
|
3755
3769
|
}
|
|
3756
3770
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"whitespace.d.ts","sourceRoot":"","sources":["../../../src/lib/whitespace.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"whitespace.d.ts","sourceRoot":"","sources":["../../../src/lib/whitespace.js"],"names":[],"mappings":"AAgBA,8CAOC;AAID,qDAgBC;AAID,iHAyDC;AAID,0IAwBC;AAID,yDAEC;AAED,qDAEC"}
|
package/package.json
CHANGED
package/src/lib/whitespace.js
CHANGED
|
@@ -8,7 +8,8 @@ import {
|
|
|
8
8
|
RE_NBSP_LEAD_GROUP,
|
|
9
9
|
RE_NBSP_TRAILING_GROUP,
|
|
10
10
|
RE_NBSP_TRAILING_STRIP,
|
|
11
|
-
inlineElementsToKeepWhitespace
|
|
11
|
+
inlineElementsToKeepWhitespace,
|
|
12
|
+
inlineElementsToKeepWhitespaceWithin
|
|
12
13
|
} from './constants.js';
|
|
13
14
|
|
|
14
15
|
// Trim whitespace
|
|
@@ -110,10 +111,24 @@ function collapseWhitespaceSmart(str, prevTag, nextTag, options, inlineElements,
|
|
|
110
111
|
if (trimLeft && !options.collapseInlineTagWhitespace) {
|
|
111
112
|
trimLeft = prevTag.charAt(0) === '/' ? !inlineElements.has(prevTag.slice(1)) : !inlineTextSet.has(prevTag);
|
|
112
113
|
}
|
|
114
|
+
// When `collapseInlineTagWhitespace` is enabled, still preserve whitespace around inline text elements
|
|
115
|
+
if (trimLeft && options.collapseInlineTagWhitespace) {
|
|
116
|
+
const tagName = prevTag.charAt(0) === '/' ? prevTag.slice(1) : prevTag;
|
|
117
|
+
if (inlineElementsToKeepWhitespaceWithin.has(tagName)) {
|
|
118
|
+
trimLeft = false;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
113
121
|
let trimRight = nextTag && !inlineElementsToKeepWhitespace.has(nextTag);
|
|
114
122
|
if (trimRight && !options.collapseInlineTagWhitespace) {
|
|
115
123
|
trimRight = nextTag.charAt(0) === '/' ? !inlineTextSet.has(nextTag.slice(1)) : !inlineElements.has(nextTag);
|
|
116
124
|
}
|
|
125
|
+
// When `collapseInlineTagWhitespace` is enabled, still preserve whitespace around inline text elements
|
|
126
|
+
if (trimRight && options.collapseInlineTagWhitespace) {
|
|
127
|
+
const tagName = nextTag.charAt(0) === '/' ? nextTag.slice(1) : nextTag;
|
|
128
|
+
if (inlineElementsToKeepWhitespaceWithin.has(tagName)) {
|
|
129
|
+
trimRight = false;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
117
132
|
return collapseWhitespace(str, options, trimLeft, trimRight, prevTag && nextTag);
|
|
118
133
|
}
|
|
119
134
|
|