html-minifier-next 4.5.0 → 4.6.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.
- package/README.md +23 -23
- package/dist/htmlminifier.cjs +48 -5
- package/dist/htmlminifier.esm.bundle.js +48 -5
- package/dist/types/htmlminifier.d.ts.map +1 -1
- package/dist/types/presets.d.ts +0 -2
- package/dist/types/presets.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/htmlminifier.js +48 -4
- package/src/presets.js +1 -2
package/README.md
CHANGED
|
@@ -72,29 +72,6 @@ html-minifier-next --config-file=html-minifier.json --input-dir=src --output-dir
|
|
|
72
72
|
html-minifier-next --config-file=html-minifier.json --file-ext=xml --input-dir=src --output-dir=dist
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
-
### Presets
|
|
76
|
-
|
|
77
|
-
HTML Minifier Next provides presets for common use cases. Presets are pre-configured option sets that can be used as a starting point:
|
|
78
|
-
|
|
79
|
-
* `conservative`: Safe minification suitable for most projects. Includes whitespace collapsing, comment removal, and doctype normalization.
|
|
80
|
-
* `comprehensive`: Aggressive minification for maximum file size reduction. Includes all conservative options plus attribute quote removal, optional tag removal, and more.
|
|
81
|
-
|
|
82
|
-
**Using presets:**
|
|
83
|
-
|
|
84
|
-
```bash
|
|
85
|
-
# Via CLI flag
|
|
86
|
-
html-minifier-next --preset conservative input.html
|
|
87
|
-
|
|
88
|
-
# Via config file
|
|
89
|
-
html-minifier-next --config-file=config.json input.html
|
|
90
|
-
# where config.json contains: { "preset": "conservative" }
|
|
91
|
-
|
|
92
|
-
# Override preset options
|
|
93
|
-
html-minifier-next --preset conservative --remove-empty-attributes input.html
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
**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.
|
|
97
|
-
|
|
98
75
|
### Node.js
|
|
99
76
|
|
|
100
77
|
ESM with Node.js ≥16.14:
|
|
@@ -125,6 +102,29 @@ See [the original blog post](https://perfectionkills.com/experimenting-with-html
|
|
|
125
102
|
|
|
126
103
|
For lint-like capabilities, take a look at [HTMLLint](https://github.com/kangax/html-lint).
|
|
127
104
|
|
|
105
|
+
## Presets
|
|
106
|
+
|
|
107
|
+
HTML Minifier Next provides presets for common use cases. Presets are pre-configured option sets that can be used as a starting point:
|
|
108
|
+
|
|
109
|
+
* `conservative`: Safe minification suitable for most projects. Includes whitespace collapsing, comment removal, and doctype normalization.
|
|
110
|
+
* `comprehensive`: Aggressive minification for maximum file size reduction. Includes relevant conservative options plus attribute quote removal, optional tag removal, and more.
|
|
111
|
+
|
|
112
|
+
**Using presets:**
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
# Via CLI flag
|
|
116
|
+
html-minifier-next --preset conservative input.html
|
|
117
|
+
|
|
118
|
+
# Via config file
|
|
119
|
+
html-minifier-next --config-file=html-minifier.json input.html
|
|
120
|
+
# where html-minifier.json contains: { "preset": "conservative" }
|
|
121
|
+
|
|
122
|
+
# Override preset options
|
|
123
|
+
html-minifier-next --preset conservative --remove-empty-attributes input.html
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**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.
|
|
127
|
+
|
|
128
128
|
## Options quick reference
|
|
129
129
|
|
|
130
130
|
Most of the options are disabled by default. Experiment and find what works best for you and your project.
|
package/dist/htmlminifier.cjs
CHANGED
|
@@ -569,7 +569,6 @@ const presets = {
|
|
|
569
569
|
collapseBooleanAttributes: true,
|
|
570
570
|
collapseInlineTagWhitespace: true,
|
|
571
571
|
collapseWhitespace: true,
|
|
572
|
-
conservativeCollapse: true,
|
|
573
572
|
continueOnParseError: true,
|
|
574
573
|
decodeEntities: true,
|
|
575
574
|
minifyCSS: true,
|
|
@@ -1033,11 +1032,55 @@ async function cleanConditionalComment(comment, options) {
|
|
|
1033
1032
|
: comment;
|
|
1034
1033
|
}
|
|
1035
1034
|
|
|
1035
|
+
const jsonScriptTypes = new Set([
|
|
1036
|
+
'application/json',
|
|
1037
|
+
'application/ld+json',
|
|
1038
|
+
'application/manifest+json',
|
|
1039
|
+
'application/vnd.geo+json',
|
|
1040
|
+
'importmap',
|
|
1041
|
+
'speculationrules',
|
|
1042
|
+
]);
|
|
1043
|
+
|
|
1044
|
+
function minifyJson(text, options) {
|
|
1045
|
+
try {
|
|
1046
|
+
return JSON.stringify(JSON.parse(text));
|
|
1047
|
+
}
|
|
1048
|
+
catch (err) {
|
|
1049
|
+
if (!options.continueOnMinifyError) {
|
|
1050
|
+
throw err;
|
|
1051
|
+
}
|
|
1052
|
+
options.log && options.log(err);
|
|
1053
|
+
return text;
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
function hasJsonScriptType(attrs) {
|
|
1058
|
+
for (let i = 0, len = attrs.length; i < len; i++) {
|
|
1059
|
+
const attrName = attrs[i].name.toLowerCase();
|
|
1060
|
+
if (attrName === 'type') {
|
|
1061
|
+
const attrValue = trimWhitespace((attrs[i].value || '').split(/;/, 2)[0]).toLowerCase();
|
|
1062
|
+
if (jsonScriptTypes.has(attrValue)) {
|
|
1063
|
+
return true;
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
return false;
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1036
1070
|
async function processScript(text, options, currentAttrs) {
|
|
1037
1071
|
for (let i = 0, len = currentAttrs.length; i < len; i++) {
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1072
|
+
const attrName = currentAttrs[i].name.toLowerCase();
|
|
1073
|
+
if (attrName === 'type') {
|
|
1074
|
+
const rawValue = currentAttrs[i].value;
|
|
1075
|
+
const normalizedValue = trimWhitespace((rawValue || '').split(/;/, 2)[0]).toLowerCase();
|
|
1076
|
+
// Minify JSON script types automatically
|
|
1077
|
+
if (jsonScriptTypes.has(normalizedValue)) {
|
|
1078
|
+
return minifyJson(text, options);
|
|
1079
|
+
}
|
|
1080
|
+
// Process custom script types if specified
|
|
1081
|
+
if (options.processScripts && options.processScripts.indexOf(rawValue) > -1) {
|
|
1082
|
+
return await minifyHTML(text, options);
|
|
1083
|
+
}
|
|
1041
1084
|
}
|
|
1042
1085
|
}
|
|
1043
1086
|
return text;
|
|
@@ -1917,7 +1960,7 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1917
1960
|
text = collapseWhitespace(text, options, false, false, true);
|
|
1918
1961
|
}
|
|
1919
1962
|
}
|
|
1920
|
-
if (options.processScripts
|
|
1963
|
+
if (specialContentTags.has(currentTag) && (options.processScripts || hasJsonScriptType(currentAttrs))) {
|
|
1921
1964
|
text = await processScript(text, options, currentAttrs);
|
|
1922
1965
|
}
|
|
1923
1966
|
if (isExecutableScript(currentTag, currentAttrs)) {
|
|
@@ -39622,7 +39622,6 @@ const presets = {
|
|
|
39622
39622
|
collapseBooleanAttributes: true,
|
|
39623
39623
|
collapseInlineTagWhitespace: true,
|
|
39624
39624
|
collapseWhitespace: true,
|
|
39625
|
-
conservativeCollapse: true,
|
|
39626
39625
|
continueOnParseError: true,
|
|
39627
39626
|
decodeEntities: true,
|
|
39628
39627
|
minifyCSS: true,
|
|
@@ -40086,11 +40085,55 @@ async function cleanConditionalComment(comment, options) {
|
|
|
40086
40085
|
: comment;
|
|
40087
40086
|
}
|
|
40088
40087
|
|
|
40088
|
+
const jsonScriptTypes = new Set([
|
|
40089
|
+
'application/json',
|
|
40090
|
+
'application/ld+json',
|
|
40091
|
+
'application/manifest+json',
|
|
40092
|
+
'application/vnd.geo+json',
|
|
40093
|
+
'importmap',
|
|
40094
|
+
'speculationrules',
|
|
40095
|
+
]);
|
|
40096
|
+
|
|
40097
|
+
function minifyJson(text, options) {
|
|
40098
|
+
try {
|
|
40099
|
+
return JSON.stringify(JSON.parse(text));
|
|
40100
|
+
}
|
|
40101
|
+
catch (err) {
|
|
40102
|
+
if (!options.continueOnMinifyError) {
|
|
40103
|
+
throw err;
|
|
40104
|
+
}
|
|
40105
|
+
options.log && options.log(err);
|
|
40106
|
+
return text;
|
|
40107
|
+
}
|
|
40108
|
+
}
|
|
40109
|
+
|
|
40110
|
+
function hasJsonScriptType(attrs) {
|
|
40111
|
+
for (let i = 0, len = attrs.length; i < len; i++) {
|
|
40112
|
+
const attrName = attrs[i].name.toLowerCase();
|
|
40113
|
+
if (attrName === 'type') {
|
|
40114
|
+
const attrValue = trimWhitespace((attrs[i].value || '').split(/;/, 2)[0]).toLowerCase();
|
|
40115
|
+
if (jsonScriptTypes.has(attrValue)) {
|
|
40116
|
+
return true;
|
|
40117
|
+
}
|
|
40118
|
+
}
|
|
40119
|
+
}
|
|
40120
|
+
return false;
|
|
40121
|
+
}
|
|
40122
|
+
|
|
40089
40123
|
async function processScript(text, options, currentAttrs) {
|
|
40090
40124
|
for (let i = 0, len = currentAttrs.length; i < len; i++) {
|
|
40091
|
-
|
|
40092
|
-
|
|
40093
|
-
|
|
40125
|
+
const attrName = currentAttrs[i].name.toLowerCase();
|
|
40126
|
+
if (attrName === 'type') {
|
|
40127
|
+
const rawValue = currentAttrs[i].value;
|
|
40128
|
+
const normalizedValue = trimWhitespace((rawValue || '').split(/;/, 2)[0]).toLowerCase();
|
|
40129
|
+
// Minify JSON script types automatically
|
|
40130
|
+
if (jsonScriptTypes.has(normalizedValue)) {
|
|
40131
|
+
return minifyJson(text, options);
|
|
40132
|
+
}
|
|
40133
|
+
// Process custom script types if specified
|
|
40134
|
+
if (options.processScripts && options.processScripts.indexOf(rawValue) > -1) {
|
|
40135
|
+
return await minifyHTML(text, options);
|
|
40136
|
+
}
|
|
40094
40137
|
}
|
|
40095
40138
|
}
|
|
40096
40139
|
return text;
|
|
@@ -40970,7 +41013,7 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
40970
41013
|
text = collapseWhitespace(text, options, false, false, true);
|
|
40971
41014
|
}
|
|
40972
41015
|
}
|
|
40973
|
-
if (options.processScripts
|
|
41016
|
+
if (specialContentTags.has(currentTag) && (options.processScripts || hasJsonScriptType(currentAttrs))) {
|
|
40974
41017
|
text = await processScript(text, options, currentAttrs);
|
|
40975
41018
|
}
|
|
40976
41019
|
if (isExecutableScript(currentTag, currentAttrs)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"htmlminifier.d.ts","sourceRoot":"","sources":["../../src/htmlminifier.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"htmlminifier.d.ts","sourceRoot":"","sources":["../../src/htmlminifier.js"],"names":[],"mappings":"AAm/CO,8BAJI,MAAM,YACN,eAAe,GACb,OAAO,CAAC,MAAM,CAAC,CAQ3B;;;;;;;;;;;;UAUS,MAAM;YACN,MAAM;YACN,MAAM;mBACN,MAAM;iBACN,MAAM;kBACN,MAAM;;;;;;;;;;;;;4BAQN,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,EAAE,qBAAqB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,KAAK,OAAO;;;;;;;wBAMjG,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,GAAG,SAAS,EAAE,iBAAiB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,KAAK,OAAO;;;;;;;;oBAMhH,OAAO;;;;;;;;gCAOP,OAAO;;;;;;;;kCAOP,OAAO;;;;;;;;yBAOP,OAAO;;;;;;;;2BAOP,OAAO;;;;;;;;4BAOP,OAAO;;;;;;;2BAOP,OAAO;;;;;;;;uBAMP,MAAM,EAAE;;;;;;yBAOR,MAAM;;;;;;yBAKN,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE;;;;;;;4BAKlB,MAAM,EAAE;;;;;;;oCAMR,MAAM;;;;;;;qBAMN,OAAO;;;;;;;YAMP,OAAO;;;;;;;;2BAMP,MAAM,EAAE;;;;;;;;;4BAOR,MAAM,EAAE;;;;;;;+BAQR,OAAO;;;;;;;2BAMP,SAAS,CAAC,MAAM,CAAC;;;;;;uBAMjB,OAAO;;;;;;;;UAKP,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI;;;;;;;;qBAO1B,MAAM;;;;;;;oBAON,MAAM;;;;;;;;;;gBAMN,OAAO,GAAG,OAAO,CAAC,OAAO,cAAc,EAAE,gBAAgB,CAAC,OAAO,cAAc,EAAE,aAAa,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;;;;;;;;;;eAS9J,OAAO,GAAG,OAAO,QAAQ,EAAE,aAAa,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;;;;;;;;;;iBASzG,OAAO,GAAG,MAAM,GAAG,OAAO,WAAW,EAAE,OAAO,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;;;;;;;;WAS7F,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM;;;;;;;+BAOxB,OAAO;;;;;;;;;;oBAMP,OAAO;;;;;;;;yBASP,OAAO;;;;;;;gCAOP,OAAO;;;;;;;;iCAMP,OAAO;;;;;;;;;;qBAOP,MAAM,EAAE;;;;;;;qBASR,IAAI,GAAG,GAAG;;;;;;;4BAMV,OAAO;;;;;;;;qBAMP,OAAO;;;;;;;;;4BAOP,OAAO,GAAG,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;;;;;;;;0BAQtD,OAAO;;;;;;;;yBAOP,OAAO;;;;;;;;gCAOP,OAAO;;;;;;;iCAOP,OAAO;;;;;;;oCAMP,OAAO;;;;;;;;;;0BAMP,OAAO;;;;;;;;;qBASP,OAAO,GAAG,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,IAAI,CAAC;;;;;;;;;oBAQzD,OAAO,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;;;;;;;;0BAQrC,OAAO;;;;;;;sBAOP,OAAO;;wBA50DkC,cAAc;0BAAd,cAAc;+BAAd,cAAc"}
|
package/dist/types/presets.d.ts
CHANGED
|
@@ -31,8 +31,6 @@ export namespace presets {
|
|
|
31
31
|
export let collapseInlineTagWhitespace: boolean;
|
|
32
32
|
let collapseWhitespace_1: boolean;
|
|
33
33
|
export { collapseWhitespace_1 as collapseWhitespace };
|
|
34
|
-
let conservativeCollapse_1: boolean;
|
|
35
|
-
export { conservativeCollapse_1 as conservativeCollapse };
|
|
36
34
|
let continueOnParseError_1: boolean;
|
|
37
35
|
export { continueOnParseError_1 as continueOnParseError };
|
|
38
36
|
let decodeEntities_1: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../../src/presets.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../../src/presets.js"],"names":[],"mappings":"AAgDA;;;;GAIG;AACH,gCAHW,MAAM,GACJ,MAAM,GAAC,IAAI,CAMvB;AAED;;;GAGG;AACH,kCAFa,MAAM,EAAE,CAIpB"}
|
package/package.json
CHANGED
package/src/htmlminifier.js
CHANGED
|
@@ -431,11 +431,55 @@ async function cleanConditionalComment(comment, options) {
|
|
|
431
431
|
: comment;
|
|
432
432
|
}
|
|
433
433
|
|
|
434
|
+
const jsonScriptTypes = new Set([
|
|
435
|
+
'application/json',
|
|
436
|
+
'application/ld+json',
|
|
437
|
+
'application/manifest+json',
|
|
438
|
+
'application/vnd.geo+json',
|
|
439
|
+
'importmap',
|
|
440
|
+
'speculationrules',
|
|
441
|
+
]);
|
|
442
|
+
|
|
443
|
+
function minifyJson(text, options) {
|
|
444
|
+
try {
|
|
445
|
+
return JSON.stringify(JSON.parse(text));
|
|
446
|
+
}
|
|
447
|
+
catch (err) {
|
|
448
|
+
if (!options.continueOnMinifyError) {
|
|
449
|
+
throw err;
|
|
450
|
+
}
|
|
451
|
+
options.log && options.log(err);
|
|
452
|
+
return text;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
function hasJsonScriptType(attrs) {
|
|
457
|
+
for (let i = 0, len = attrs.length; i < len; i++) {
|
|
458
|
+
const attrName = attrs[i].name.toLowerCase();
|
|
459
|
+
if (attrName === 'type') {
|
|
460
|
+
const attrValue = trimWhitespace((attrs[i].value || '').split(/;/, 2)[0]).toLowerCase();
|
|
461
|
+
if (jsonScriptTypes.has(attrValue)) {
|
|
462
|
+
return true;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
return false;
|
|
467
|
+
}
|
|
468
|
+
|
|
434
469
|
async function processScript(text, options, currentAttrs) {
|
|
435
470
|
for (let i = 0, len = currentAttrs.length; i < len; i++) {
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
471
|
+
const attrName = currentAttrs[i].name.toLowerCase();
|
|
472
|
+
if (attrName === 'type') {
|
|
473
|
+
const rawValue = currentAttrs[i].value;
|
|
474
|
+
const normalizedValue = trimWhitespace((rawValue || '').split(/;/, 2)[0]).toLowerCase();
|
|
475
|
+
// Minify JSON script types automatically
|
|
476
|
+
if (jsonScriptTypes.has(normalizedValue)) {
|
|
477
|
+
return minifyJson(text, options);
|
|
478
|
+
}
|
|
479
|
+
// Process custom script types if specified
|
|
480
|
+
if (options.processScripts && options.processScripts.indexOf(rawValue) > -1) {
|
|
481
|
+
return await minifyHTML(text, options);
|
|
482
|
+
}
|
|
439
483
|
}
|
|
440
484
|
}
|
|
441
485
|
return text;
|
|
@@ -1315,7 +1359,7 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1315
1359
|
text = collapseWhitespace(text, options, false, false, true);
|
|
1316
1360
|
}
|
|
1317
1361
|
}
|
|
1318
|
-
if (options.processScripts
|
|
1362
|
+
if (specialContentTags.has(currentTag) && (options.processScripts || hasJsonScriptType(currentAttrs))) {
|
|
1319
1363
|
text = await processScript(text, options, currentAttrs);
|
|
1320
1364
|
}
|
|
1321
1365
|
if (isExecutableScript(currentTag, currentAttrs)) {
|
package/src/presets.js
CHANGED
|
@@ -26,7 +26,6 @@ export const presets = {
|
|
|
26
26
|
collapseBooleanAttributes: true,
|
|
27
27
|
collapseInlineTagWhitespace: true,
|
|
28
28
|
collapseWhitespace: true,
|
|
29
|
-
conservativeCollapse: true,
|
|
30
29
|
continueOnParseError: true,
|
|
31
30
|
decodeEntities: true,
|
|
32
31
|
minifyCSS: true,
|
|
@@ -64,4 +63,4 @@ export function getPreset(name) {
|
|
|
64
63
|
*/
|
|
65
64
|
export function getPresetNames() {
|
|
66
65
|
return Object.keys(presets);
|
|
67
|
-
}
|
|
66
|
+
}
|