html-minifier-next 1.1.5 → 1.2.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 +25 -23
- package/cli.js +3 -2
- package/dist/htmlminifier.cjs +9 -10
- package/dist/htmlminifier.esm.bundle.js +559 -329
- package/dist/htmlminifier.umd.bundle.js +559 -329
- package/dist/htmlminifier.umd.bundle.min.js +3 -3
- package/package.json +14 -12
- package/src/htmlminifier.js +38 -32
- package/src/htmlparser.js +9 -9
package/README.md
CHANGED
|
@@ -41,7 +41,7 @@ const { minify } = require('html-minifier-next');
|
|
|
41
41
|
const result = await minify('<p title="blah" id="moo">foo</p>', {
|
|
42
42
|
removeAttributeQuotes: true,
|
|
43
43
|
});
|
|
44
|
-
result; //
|
|
44
|
+
result; // “<p title=blah id=moo>foo</p>”
|
|
45
45
|
```
|
|
46
46
|
|
|
47
47
|
See [the original blog post](http://perfectionkills.com/experimenting-with-html-minifier) for details of [how it works](http://perfectionkills.com/experimenting-with-html-minifier#how_it_works), [description of each option](http://perfectionkills.com/experimenting-with-html-minifier#options), [testing results](http://perfectionkills.com/experimenting-with-html-minifier#field_testing), and [conclusions](http://perfectionkills.com/experimenting-with-html-minifier#cost_and_benefits).
|
|
@@ -54,21 +54,22 @@ How does HTMLMinifier compare to other solutions, like [minimize](https://github
|
|
|
54
54
|
|
|
55
55
|
| Site | Original size (KB) | HTMLMinifier | minimize | htmlcompressor.com |
|
|
56
56
|
| --- | --- | --- | --- | --- |
|
|
57
|
-
| [
|
|
58
|
-
| [
|
|
59
|
-
| [
|
|
60
|
-
| [
|
|
61
|
-
| [
|
|
62
|
-
| [
|
|
63
|
-
| [
|
|
64
|
-
| [
|
|
65
|
-
| [
|
|
66
|
-
| [
|
|
67
|
-
| [
|
|
68
|
-
| [
|
|
69
|
-
| [
|
|
70
|
-
| [
|
|
71
|
-
| [
|
|
57
|
+
| [A List Apart](https://alistapart.com/) | 64 | **54** | 59 | 57 |
|
|
58
|
+
| [Amazon](https://www.amazon.com/) | 206 | **195** | 203 | 200 |
|
|
59
|
+
| [BBC](https://www.bbc.co.uk/) | 767 | **703** | 761 | n/a |
|
|
60
|
+
| [CSS-Tricks](https://css-tricks.com/) | 166 | **124** | 152 | 148 |
|
|
61
|
+
| [ECMAScript](https://tc39.es/ecma262/) | 7204 | **6361** | 6581 | n/a |
|
|
62
|
+
| [EFF](https://www.eff.org/) | 57 | **48** | 52 | 52 |
|
|
63
|
+
| [FAZ](https://www.faz.net/aktuell/) | 1767 | **1641** | 1679 | n/a |
|
|
64
|
+
| [Frontend Dogma](https://frontenddogma.com/) | 119 | **114** | 128 | 118 |
|
|
65
|
+
| [Google](https://www.google.com/) | 51 | **46** | 50 | 50 |
|
|
66
|
+
| [HTMLMinifier](https://github.com/kangax/html-minifier) | 373 | **250** | 349 | n/a |
|
|
67
|
+
| [Mastodon](https://mastodon.social/explore) | 37 | **28** | 36 | 36 |
|
|
68
|
+
| [NBC](https://www.nbc.com/) | 601 | **549** | 593 | n/a |
|
|
69
|
+
| [New York Times](https://www.nytimes.com/) | 822 | **701** | 811 | n/a |
|
|
70
|
+
| [United Nations](https://www.un.org/) | 9 | **7** | 8 | 8 |
|
|
71
|
+
| [W3C](https://www.w3.org/) | 50 | **36** | 41 | 39 |
|
|
72
|
+
| [Wikipedia](https://en.wikipedia.org/wiki/Main_Page) | 225 | **204** | 215 | 215 |
|
|
72
73
|
|
|
73
74
|
## Options quick reference
|
|
74
75
|
|
|
@@ -76,7 +77,7 @@ Most of the options are disabled by default.
|
|
|
76
77
|
|
|
77
78
|
| Option | Description | Default |
|
|
78
79
|
| --- | --- | --- |
|
|
79
|
-
| `caseSensitive` | Treat attributes in case sensitive manner (useful for custom HTML
|
|
80
|
+
| `caseSensitive` | Treat attributes in case sensitive manner (useful for custom HTML elements) | `false` |
|
|
80
81
|
| `collapseBooleanAttributes` | [Omit attribute values from boolean attributes](http://perfectionkills.com/experimenting-with-html-minifier#collapse_boolean_attributes) | `false` |
|
|
81
82
|
| `customFragmentQuantifierLimit` | Set maximum quantifier limit for custom fragments to prevent ReDoS attacks | `200` |
|
|
82
83
|
| `collapseInlineTagWhitespace` | Don’t leave any spaces between `display:inline;` elements when collapsing. Must be used in conjunction with `collapseWhitespace=true` | `false` |
|
|
@@ -91,7 +92,8 @@ Most of the options are disabled by default.
|
|
|
91
92
|
| `html5` | Parse input according to HTML5 specifications | `true` |
|
|
92
93
|
| `ignoreCustomComments` | Array of regexes that allow to ignore certain comments, when matched | `[ /^!/, /^\s*#/ ]` |
|
|
93
94
|
| `ignoreCustomFragments` | Array of regexes that allow to ignore certain fragments, when matched (e.g. `<?php ... ?>`, `{{ ... }}`, etc.) | `[ /<%[\s\S]*?%>/, /<\?[\s\S]*?\?>/ ]` |
|
|
94
|
-
| `includeAutoGeneratedTags` | Insert
|
|
95
|
+
| `includeAutoGeneratedTags` | Insert elements generated by HTML parser | `true` |
|
|
96
|
+
| `inlineCustomElements` | Array of names of custom elements which are inline | `[]` |
|
|
95
97
|
| `keepClosingSlash` | Keep the trailing slash on singleton elements | `false` |
|
|
96
98
|
| `maxInputLength` | Maximum input length to prevent ReDoS attacks (disabled by default) | `undefined` |
|
|
97
99
|
| `maxLineLength` | Specify a maximum line length. Compressed output will be split by newlines at valid HTML split-points |
|
|
@@ -110,8 +112,8 @@ Most of the options are disabled by default.
|
|
|
110
112
|
| `removeEmptyElements` | [Remove all elements with empty contents](http://perfectionkills.com/experimenting-with-html-minifier#remove_empty_elements) | `false` |
|
|
111
113
|
| `removeOptionalTags` | [Remove optional tags](http://perfectionkills.com/experimenting-with-html-minifier#remove_optional_tags) | `false` |
|
|
112
114
|
| `removeRedundantAttributes` | [Remove attributes when value matches default.](http://perfectionkills.com/experimenting-with-html-minifier#remove_redundant_attributes) | `false` |
|
|
113
|
-
| `removeScriptTypeAttributes` | Remove `type="text/javascript"` from `script`
|
|
114
|
-
| `removeStyleLinkTypeAttributes`| Remove `type="text/css"` from `style` and `link`
|
|
115
|
+
| `removeScriptTypeAttributes` | Remove `type="text/javascript"` from `script` elements. Other `type` attribute values are left intact | `false` |
|
|
116
|
+
| `removeStyleLinkTypeAttributes`| Remove `type="text/css"` from `style` and `link` elements. Other `type` attribute values are left intact | `false` |
|
|
115
117
|
| `removeTagWhitespace` | Remove space between attributes whenever possible. **Note that this will result in invalid HTML!** | `false` |
|
|
116
118
|
| `sortAttributes` | [Sort attributes by frequency](#sorting-attributes--style-classes) | `false` |
|
|
117
119
|
| `sortClassName` | [Sort style classes by frequency](#sorting-attributes--style-classes) | `false` |
|
|
@@ -130,11 +132,11 @@ If you have chunks of markup you would like preserved, you can wrap them `<!-- h
|
|
|
130
132
|
|
|
131
133
|
### Minifying JSON-LD
|
|
132
134
|
|
|
133
|
-
You can minify script
|
|
135
|
+
You can minify script elements with JSON-LD by setting the option `{ processScripts: ['application/ld+json'] }`. Note that this minification is very rudimentary, it is mainly useful for removing newlines and excessive whitespace.
|
|
134
136
|
|
|
135
|
-
### Preserving SVG
|
|
137
|
+
### Preserving SVG elements
|
|
136
138
|
|
|
137
|
-
SVG
|
|
139
|
+
SVG elements are automatically recognized, and when they are minified, both case-sensitivity and closing-slashes are preserved, regardless of the minification settings used for the rest of the file.
|
|
138
140
|
|
|
139
141
|
### Working with invalid markup
|
|
140
142
|
|
package/cli.js
CHANGED
|
@@ -113,6 +113,7 @@ const mainOptions = {
|
|
|
113
113
|
ignoreCustomComments: ['Array of regex\'es that allow to ignore certain comments, when matched', parseJSONRegExpArray],
|
|
114
114
|
ignoreCustomFragments: ['Array of regex\'es that allow to ignore certain fragments, when matched (e.g. <?php ... ?>, {{ ... }})', parseJSONRegExpArray],
|
|
115
115
|
includeAutoGeneratedTags: 'Insert tags generated by HTML parser',
|
|
116
|
+
inlineCustomElements: ['Array of names of custom elements which are inline', parseJSONArray],
|
|
116
117
|
keepClosingSlash: 'Keep the trailing slash on singleton elements',
|
|
117
118
|
maxInputLength: ['Maximum input length to prevent ReDoS attacks', parseInt],
|
|
118
119
|
maxLineLength: ['Max line length', parseInt],
|
|
@@ -140,7 +141,7 @@ const mainOptions = {
|
|
|
140
141
|
useShortDoctype: 'Replaces the doctype with the short (HTML5) doctype'
|
|
141
142
|
};
|
|
142
143
|
|
|
143
|
-
//
|
|
144
|
+
// Configure command line flags
|
|
144
145
|
const mainOptionKeys = Object.keys(mainOptions);
|
|
145
146
|
mainOptionKeys.forEach(function (key) {
|
|
146
147
|
const option = mainOptions[key];
|
|
@@ -304,4 +305,4 @@ if (inputDir || outputDir) {
|
|
|
304
305
|
process.stdin.on('data', function (data) {
|
|
305
306
|
content += data;
|
|
306
307
|
}).on('end', writeMinify);
|
|
307
|
-
}
|
|
308
|
+
}
|
package/dist/htmlminifier.cjs
CHANGED
|
@@ -496,9 +496,7 @@ class TokenChain {
|
|
|
496
496
|
}
|
|
497
497
|
}
|
|
498
498
|
|
|
499
|
-
|
|
500
|
-
return str && str.replace(/^[ \n\r\t\f]+/, '').replace(/[ \n\r\t\f]+$/, '');
|
|
501
|
-
}
|
|
499
|
+
const trimWhitespace = str => str && str.replace(/^[ \n\r\t\f]+/, '').replace(/[ \n\r\t\f]+$/, '');
|
|
502
500
|
|
|
503
501
|
function collapseWhitespaceAll(str) {
|
|
504
502
|
// Non-breaking space is specifically handled inside the replacer function here:
|
|
@@ -550,14 +548,14 @@ function collapseWhitespace(str, options, trimLeft, trimRight, collapseAll) {
|
|
|
550
548
|
return lineBreakBefore + str + lineBreakAfter;
|
|
551
549
|
}
|
|
552
550
|
|
|
553
|
-
// non-empty
|
|
554
|
-
const
|
|
555
|
-
// non-empty
|
|
551
|
+
// non-empty elements that will maintain whitespace around them
|
|
552
|
+
const inlineHtmlElements = ['a', 'abbr', 'acronym', 'b', 'bdi', 'bdo', 'big', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'img', 'input', 'ins', 'kbd', 'label', 'mark', 'math', 'meter', 'nobr', 'object', 'output', 'progress', 'q', 'rp', 'rt', 'rtc', 'ruby', 's', 'samp', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'svg', 'textarea', 'time', 'tt', 'u', 'var', 'wbr'];
|
|
553
|
+
// non-empty elements that will maintain whitespace within them
|
|
556
554
|
const inlineTextTags = new Set(['a', 'abbr', 'acronym', 'b', 'big', 'del', 'em', 'font', 'i', 'ins', 'kbd', 'mark', 'nobr', 'rp', 's', 'samp', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'time', 'tt', 'u', 'var']);
|
|
557
|
-
// self-closing
|
|
555
|
+
// self-closing elements that will maintain whitespace around them
|
|
558
556
|
const selfClosingInlineTags = new Set(['comment', 'img', 'input', 'wbr']);
|
|
559
557
|
|
|
560
|
-
function collapseWhitespaceSmart(str, prevTag, nextTag, options) {
|
|
558
|
+
function collapseWhitespaceSmart(str, prevTag, nextTag, options, inlineTags) {
|
|
561
559
|
let trimLeft = prevTag && !selfClosingInlineTags.has(prevTag);
|
|
562
560
|
if (trimLeft && !options.collapseInlineTagWhitespace) {
|
|
563
561
|
trimLeft = prevTag.charAt(0) === '/' ? !inlineTags.has(prevTag.slice(1)) : !inlineTextTags.has(prevTag);
|
|
@@ -1357,6 +1355,7 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1357
1355
|
let uidIgnore;
|
|
1358
1356
|
let uidAttr;
|
|
1359
1357
|
let uidPattern;
|
|
1358
|
+
let inlineTags = new Set([...inlineHtmlElements, ...(options.inlineCustomElements ?? [])]);
|
|
1360
1359
|
|
|
1361
1360
|
// temporarily replace ignored chunks with comments,
|
|
1362
1361
|
// so that we don't have to worry what's there.
|
|
@@ -1488,7 +1487,7 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1488
1487
|
const match = str.match(/^<\/([\w:-]+)>$/);
|
|
1489
1488
|
if (match) {
|
|
1490
1489
|
endTag = match[1];
|
|
1491
|
-
} else if (/>$/.test(str) || (buffer[index] = collapseWhitespaceSmart(str, null, nextTag, options))) {
|
|
1490
|
+
} else if (/>$/.test(str) || (buffer[index] = collapseWhitespaceSmart(str, null, nextTag, options, inlineTags))) {
|
|
1492
1491
|
break;
|
|
1493
1492
|
}
|
|
1494
1493
|
}
|
|
@@ -1699,7 +1698,7 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1699
1698
|
}
|
|
1700
1699
|
}
|
|
1701
1700
|
if (prevTag || nextTag) {
|
|
1702
|
-
text = collapseWhitespaceSmart(text, prevTag, nextTag, options);
|
|
1701
|
+
text = collapseWhitespaceSmart(text, prevTag, nextTag, options, inlineTags);
|
|
1703
1702
|
} else {
|
|
1704
1703
|
text = collapseWhitespace(text, options, true, true);
|
|
1705
1704
|
}
|