html-minifier-next 1.3.3 → 1.4.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 +33 -33
- package/cli.js +27 -27
- package/package.json +5 -5
- package/src/htmlminifier.js +20 -2
- package/src/htmlparser.js +5 -5
- package/dist/htmlminifier.cjs +0 -1878
- package/dist/htmlminifier.esm.bundle.js +0 -61760
- package/dist/htmlminifier.umd.bundle.js +0 -61771
- package/dist/htmlminifier.umd.bundle.min.js +0 -9
package/README.md
CHANGED
|
@@ -57,7 +57,7 @@ Use `html-minifier-next --help` to check all available options:
|
|
|
57
57
|
| --- | --- | --- |
|
|
58
58
|
| `--input-dir <dir>` | Specify an input directory | `--input-dir=src` |
|
|
59
59
|
| `--output-dir <dir>` | Specify an output directory | `--output-dir=dist` |
|
|
60
|
-
| `--file-ext <extensions>` | Specify file extension(s) to process (overrides config file setting) | `--file-ext=html
|
|
60
|
+
| `--file-ext <extensions>` | Specify file extension(s) to process (overrides config file setting) | `--file-ext=html`, `--file-ext=html,htm,php`, `--file-ext="html, htm, php"` |
|
|
61
61
|
| `-o --output <file>` | Specify output file (single file mode) | `-o minified.html` |
|
|
62
62
|
| `-c --config-file <file>` | Use a configuration file | `--config-file=html-minifier.json` |
|
|
63
63
|
|
|
@@ -157,59 +157,59 @@ Most of the options are disabled by default.
|
|
|
157
157
|
| `caseSensitive` | Treat attributes in case-sensitive manner (useful for custom HTML elements) | `false` |
|
|
158
158
|
| `collapseBooleanAttributes` | [Omit attribute values from boolean attributes](http://perfectionkills.com/experimenting-with-html-minifier#collapse_boolean_attributes) | `false` |
|
|
159
159
|
| `customFragmentQuantifierLimit` | Set maximum quantifier limit for custom fragments to prevent ReDoS attacks | `200` |
|
|
160
|
-
| `collapseInlineTagWhitespace` | Don’t leave any spaces between `display:inline;` elements when collapsing
|
|
161
|
-
| `collapseWhitespace` | [Collapse
|
|
162
|
-
| `conservativeCollapse` | Always collapse to 1 space (never remove it entirely)
|
|
163
|
-
| `continueOnParseError` | [Handle parse errors](https://html.spec.whatwg.org/multipage/parsing.html#parse-errors) instead of aborting
|
|
164
|
-
| `customAttrAssign` | Arrays of
|
|
165
|
-
| `customAttrCollapse` | Regex that specifies custom attribute to strip newlines from (e.g
|
|
166
|
-
| `customAttrSurround` | Arrays of regexes that allow to support custom attribute surround expressions (e.g
|
|
167
|
-
| `customEventAttributes` | Arrays of regexes that allow to support custom event attributes for `minifyJS` (e.g
|
|
160
|
+
| `collapseInlineTagWhitespace` | Don’t leave any spaces between `display: inline;` elements when collapsing—use with `collapseWhitespace=true` | `false` |
|
|
161
|
+
| `collapseWhitespace` | [Collapse whitespace that contributes to text nodes in a document tree](http://perfectionkills.com/experimenting-with-html-minifier#collapse_whitespace) | `false` |
|
|
162
|
+
| `conservativeCollapse` | Always collapse to 1 space (never remove it entirely)—use with `collapseWhitespace=true` | `false` |
|
|
163
|
+
| `continueOnParseError` | [Handle parse errors](https://html.spec.whatwg.org/multipage/parsing.html#parse-errors) instead of aborting | `false` |
|
|
164
|
+
| `customAttrAssign` | Arrays of regexes that allow to support custom attribute assign expressions (e.g., `'<div flex?="{{mode != cover}}"></div>'`) | `[]` |
|
|
165
|
+
| `customAttrCollapse` | Regex that specifies custom attribute to strip newlines from (e.g., `/ng-class/`) | |
|
|
166
|
+
| `customAttrSurround` | Arrays of regexes that allow to support custom attribute surround expressions (e.g., `<input {{#if value}}checked="checked"{{/if}}>`) | `[]` |
|
|
167
|
+
| `customEventAttributes` | Arrays of regexes that allow to support custom event attributes for `minifyJS` (e.g., `ng-click`) | `[ /^on[a-z]{3,}$/ ]` |
|
|
168
168
|
| `decodeEntities` | Use direct Unicode characters whenever possible | `false` |
|
|
169
|
-
| `html5` | Parse input according to
|
|
169
|
+
| `html5` | Parse input according to the HTML specification | `true` |
|
|
170
170
|
| `ignoreCustomComments` | Array of regexes that allow to ignore certain comments, when matched | `[ /^!/, /^\s*#/ ]` |
|
|
171
|
-
| `ignoreCustomFragments` | Array of regexes that allow to ignore certain fragments, when matched (e.g
|
|
171
|
+
| `ignoreCustomFragments` | Array of regexes that allow to ignore certain fragments, when matched (e.g., `<?php … ?>`, `{{ … }}`, etc.) | `[ /<%[\s\S]*?%>/, /<\?[\s\S]*?\?>/ ]` |
|
|
172
172
|
| `includeAutoGeneratedTags` | Insert elements generated by HTML parser | `true` |
|
|
173
173
|
| `inlineCustomElements` | Array of names of custom elements which are inline | `[]` |
|
|
174
|
-
| `keepClosingSlash` | Keep the trailing slash on
|
|
174
|
+
| `keepClosingSlash` | Keep the trailing slash on void elements | `false` |
|
|
175
175
|
| `maxInputLength` | Maximum input length to prevent ReDoS attacks (disabled by default) | `undefined` |
|
|
176
|
-
| `maxLineLength` | Specify a maximum line length
|
|
177
|
-
| `minifyCSS` | Minify CSS in style elements and style attributes (uses [clean-css](https://github.com/jakubpawlowicz/clean-css)) | `false` (could be `true`, `Object`, `Function(text, type)`) |
|
|
178
|
-
| `minifyJS` | Minify JavaScript in script elements and event attributes (uses [Terser](https://github.com/terser/terser)) | `false` (could be `true`, `Object`, `Function(text, inline)`) |
|
|
176
|
+
| `maxLineLength` | Specify a maximum line length; compressed output will be split by newlines at valid HTML split-points | |
|
|
177
|
+
| `minifyCSS` | Minify CSS in `style` elements and `style` attributes (uses [clean-css](https://github.com/jakubpawlowicz/clean-css)) | `false` (could be `true`, `Object`, `Function(text, type)`) |
|
|
178
|
+
| `minifyJS` | Minify JavaScript in `script` elements and event attributes (uses [Terser](https://github.com/terser/terser)) | `false` (could be `true`, `Object`, `Function(text, inline)`) |
|
|
179
179
|
| `minifyURLs` | Minify URLs in various attributes (uses [relateurl](https://github.com/stevenvachon/relateurl)) | `false` (could be `String`, `Object`, `Function(text)`) |
|
|
180
180
|
| `noNewlinesBeforeTagClose` | Never add a newline before a tag that closes an element | `false` |
|
|
181
|
-
| `preserveLineBreaks` | Always collapse to 1 line break (never remove it entirely) when whitespace between tags
|
|
181
|
+
| `preserveLineBreaks` | Always collapse to 1 line break (never remove it entirely) when whitespace between tags includes a line break—use with `collapseWhitespace=true` | `false` |
|
|
182
182
|
| `preventAttributesEscaping` | Prevents the escaping of the values of attributes | `false` |
|
|
183
183
|
| `processConditionalComments` | Process contents of conditional comments through minifier | `false` |
|
|
184
|
-
| `processScripts` | Array of strings corresponding to types of script elements to process through minifier (e.g
|
|
185
|
-
| `quoteCharacter` | Type of quote to use for attribute values (
|
|
184
|
+
| `processScripts` | Array of strings corresponding to types of `script` elements to process through minifier (e.g., `text/ng-template`, `text/x-handlebars-template`, etc.) | `[]` |
|
|
185
|
+
| `quoteCharacter` | Type of quote to use for attribute values (`'` or `"`) | |
|
|
186
186
|
| `removeAttributeQuotes` | [Remove quotes around attributes when possible](http://perfectionkills.com/experimenting-with-html-minifier#remove_attribute_quotes) | `false` |
|
|
187
187
|
| `removeComments` | [Strip HTML comments](http://perfectionkills.com/experimenting-with-html-minifier#remove_comments) | `false` |
|
|
188
188
|
| `removeEmptyAttributes` | [Remove all attributes with whitespace-only values](http://perfectionkills.com/experimenting-with-html-minifier#remove_empty_or_blank_attributes) | `false` (could be `true`, `Function(attrName, tag)`) |
|
|
189
189
|
| `removeEmptyElements` | [Remove all elements with empty contents](http://perfectionkills.com/experimenting-with-html-minifier#remove_empty_elements) | `false` |
|
|
190
190
|
| `removeOptionalTags` | [Remove optional tags](http://perfectionkills.com/experimenting-with-html-minifier#remove_optional_tags) | `false` |
|
|
191
191
|
| `removeRedundantAttributes` | [Remove attributes when value matches default.](http://perfectionkills.com/experimenting-with-html-minifier#remove_redundant_attributes) | `false` |
|
|
192
|
-
| `removeScriptTypeAttributes` | Remove `type="text/javascript"` from `script` elements
|
|
193
|
-
| `removeStyleLinkTypeAttributes`| Remove `type="text/css"` from `style` and `link` elements
|
|
194
|
-
| `removeTagWhitespace` | Remove space between attributes whenever possible
|
|
195
|
-
| `sortAttributes` | [Sort attributes by frequency](#sorting-attributes
|
|
196
|
-
| `sortClassName` | [Sort style classes by frequency](#sorting-attributes
|
|
197
|
-
| `trimCustomFragments` | Trim
|
|
198
|
-
| `useShortDoctype` | [Replaces the
|
|
192
|
+
| `removeScriptTypeAttributes` | Remove `type="text/javascript"` from `script` elements; other `type` attribute values are left intact | `false` |
|
|
193
|
+
| `removeStyleLinkTypeAttributes`| Remove `type="text/css"` from `style` and `link` elements; other `type` attribute values are left intact | `false` |
|
|
194
|
+
| `removeTagWhitespace` | Remove space between attributes whenever possible; **note that this will result in invalid HTML** | `false` |
|
|
195
|
+
| `sortAttributes` | [Sort attributes by frequency](#sorting-attributes-and-style-classes) | `false` |
|
|
196
|
+
| `sortClassName` | [Sort style classes by frequency](#sorting-attributes-and-style-classes) | `false` |
|
|
197
|
+
| `trimCustomFragments` | Trim whitespace around `ignoreCustomFragments` | `false` |
|
|
198
|
+
| `useShortDoctype` | [Replaces the doctype with the short (HTML) doctype](http://perfectionkills.com/experimenting-with-html-minifier#use_short_doctype) | `false` |
|
|
199
199
|
|
|
200
|
-
### Sorting attributes
|
|
200
|
+
### Sorting attributes and style classes
|
|
201
201
|
|
|
202
|
-
Minifier options like `sortAttributes` and `sortClassName` won’t impact the plain
|
|
202
|
+
Minifier options like `sortAttributes` and `sortClassName` won’t impact the plain‑text size of the output. However, they form long, repetitive character chains that should improve the compression ratio of gzip used for HTTP.
|
|
203
203
|
|
|
204
204
|
## Special cases
|
|
205
205
|
|
|
206
206
|
### Ignoring chunks of markup
|
|
207
207
|
|
|
208
|
-
If you have chunks of markup you would like preserved, you can wrap them `<!-- htmlmin:ignore -->`.
|
|
208
|
+
If you have chunks of markup you would like preserved, you can wrap them with `<!-- htmlmin:ignore -->`.
|
|
209
209
|
|
|
210
210
|
### Minifying JSON-LD
|
|
211
211
|
|
|
212
|
-
You can minify script elements with JSON-LD by setting
|
|
212
|
+
You can minify `script` elements with JSON-LD by setting `{ processScripts: ['application/ld+json'] }`. Note that this minification is rudimentary; it’s mainly useful for removing newlines and excessive whitespace.
|
|
213
213
|
|
|
214
214
|
### Preserving SVG elements
|
|
215
215
|
|
|
@@ -219,9 +219,11 @@ SVG elements are automatically recognized, and when they are minified, both case
|
|
|
219
219
|
|
|
220
220
|
HTML Minifier **can’t work with invalid or partial chunks of markup**. This is because it parses markup into a tree structure, then modifies it (removing anything that was specified for removal, ignoring anything that was specified to be ignored, etc.), then it creates a markup out of that tree and returns it.
|
|
221
221
|
|
|
222
|
-
Input markup (e.g
|
|
222
|
+
Input markup (e.g., `<p id="">foo`) → Internal representation of markup in a form of tree (e.g., `{ tag: "p", attr: "id", children: ["foo"] }`) → Transformation of internal representation (e.g., removal of `id` attribute) → Output of resulting markup (e.g., `<p>foo</p>`)
|
|
223
223
|
|
|
224
|
-
HTML Minifier can’t know that original markup
|
|
224
|
+
HTML Minifier can’t know that the original markup represented only part of the tree. It parses a complete tree and, in doing so, loses information about the input being malformed or partial. As a result, it can’t emit a partial or malformed tree.
|
|
225
|
+
|
|
226
|
+
To validate HTML markup, use [the W3C validator](https://validator.w3.org/) or one of [several validator packages](https://meiert.com/blog/html-validator-packages/).
|
|
225
227
|
|
|
226
228
|
## Security
|
|
227
229
|
|
|
@@ -237,8 +239,6 @@ This minifier includes protection against regular expression denial of service (
|
|
|
237
239
|
|
|
238
240
|
**Important:** When using custom `ignoreCustomFragments`, ensure your regular expressions don’t contain unlimited quantifiers (`*`, `+`) without bounds, as these can lead to ReDoS vulnerabilities.
|
|
239
241
|
|
|
240
|
-
(Further improvements are needed. Contributions welcome.)
|
|
241
|
-
|
|
242
242
|
#### Custom fragment examples
|
|
243
243
|
|
|
244
244
|
**Safe patterns** (recommended):
|
package/cli.js
CHANGED
|
@@ -97,48 +97,48 @@ function parseJSONRegExpArray(value) {
|
|
|
97
97
|
const parseString = value => value;
|
|
98
98
|
|
|
99
99
|
const mainOptions = {
|
|
100
|
-
caseSensitive: 'Treat attributes in case
|
|
100
|
+
caseSensitive: 'Treat attributes in case-sensitive manner (useful for custom HTML elements)',
|
|
101
101
|
collapseBooleanAttributes: 'Omit attribute values from boolean attributes',
|
|
102
102
|
customFragmentQuantifierLimit: ['Set maximum quantifier limit for custom fragments to prevent ReDoS attacks (default: 200)', parseInt],
|
|
103
|
-
collapseInlineTagWhitespace: '
|
|
104
|
-
collapseWhitespace: 'Collapse
|
|
105
|
-
conservativeCollapse: 'Always collapse to 1 space (never remove it entirely)',
|
|
103
|
+
collapseInlineTagWhitespace: 'Don’t leave any spaces between “display: inline;” elements when collapsing—use with “collapseWhitespace=true”',
|
|
104
|
+
collapseWhitespace: 'Collapse whitespace that contributes to text nodes in a document tree',
|
|
105
|
+
conservativeCollapse: 'Always collapse to 1 space (never remove it entirely)—use with “collapseWhitespace=true”',
|
|
106
106
|
continueOnParseError: 'Handle parse errors instead of aborting',
|
|
107
|
-
customAttrAssign: ['Arrays of
|
|
108
|
-
customAttrCollapse: ['Regex that specifies custom attribute to strip newlines from (e.g
|
|
109
|
-
customAttrSurround: ['Arrays of
|
|
110
|
-
customEventAttributes: ['Arrays of
|
|
107
|
+
customAttrAssign: ['Arrays of regexes that allow to support custom attribute assign expressions (e.g., “<div flex?="{{mode != cover}}"></div>”)', parseJSONRegExpArray],
|
|
108
|
+
customAttrCollapse: ['Regex that specifies custom attribute to strip newlines from (e.g., /ng-class/)', parseRegExp],
|
|
109
|
+
customAttrSurround: ['Arrays of regexes that allow to support custom attribute surround expressions (e.g., “<input {{#if value}}checked="checked"{{/if}}>”)', parseJSONRegExpArray],
|
|
110
|
+
customEventAttributes: ['Arrays of regexes that allow to support custom event attributes for minifyJS (e.g., “ng-click”)', parseJSONRegExpArray],
|
|
111
111
|
decodeEntities: 'Use direct Unicode characters whenever possible',
|
|
112
|
-
html5: 'Parse input according to
|
|
113
|
-
ignoreCustomComments: ['Array of
|
|
114
|
-
ignoreCustomFragments: ['Array of
|
|
115
|
-
includeAutoGeneratedTags: 'Insert
|
|
112
|
+
html5: 'Parse input according to the HTML specification',
|
|
113
|
+
ignoreCustomComments: ['Array of regexes that allow to ignore certain comments, when matched', parseJSONRegExpArray],
|
|
114
|
+
ignoreCustomFragments: ['Array of regexes that allow to ignore certain fragments, when matched (e.g., “<?php … ?>”, “{{ … }}”)', parseJSONRegExpArray],
|
|
115
|
+
includeAutoGeneratedTags: 'Insert elements generated by HTML parser',
|
|
116
116
|
inlineCustomElements: ['Array of names of custom elements which are inline', parseJSONArray],
|
|
117
|
-
keepClosingSlash: 'Keep the trailing slash on
|
|
117
|
+
keepClosingSlash: 'Keep the trailing slash on void elements',
|
|
118
118
|
maxInputLength: ['Maximum input length to prevent ReDoS attacks', parseInt],
|
|
119
|
-
maxLineLength: ['
|
|
120
|
-
minifyCSS: ['Minify CSS in style elements and style attributes (uses clean-css)', parseJSON],
|
|
121
|
-
minifyJS: ['Minify
|
|
119
|
+
maxLineLength: ['Specify a maximum line length; compressed output will be split by newlines at valid HTML split-points', parseInt],
|
|
120
|
+
minifyCSS: ['Minify CSS in “style” elements and “style” attributes (uses clean-css)', parseJSON],
|
|
121
|
+
minifyJS: ['Minify JavaScript in “script” elements and event attributes (uses Terser)', parseJSON],
|
|
122
122
|
minifyURLs: ['Minify URLs in various attributes (uses relateurl)', parseJSON],
|
|
123
123
|
noNewlinesBeforeTagClose: 'Never add a newline before a tag that closes an element',
|
|
124
|
-
preserveLineBreaks: 'Always collapse to 1 line break (never remove it entirely) when whitespace between tags
|
|
125
|
-
preventAttributesEscaping: 'Prevents the escaping of the values of attributes
|
|
124
|
+
preserveLineBreaks: 'Always collapse to 1 line break (never remove it entirely) when whitespace between tags includes a line break—use with “collapseWhitespace=true”',
|
|
125
|
+
preventAttributesEscaping: 'Prevents the escaping of the values of attributes',
|
|
126
126
|
processConditionalComments: 'Process contents of conditional comments through minifier',
|
|
127
|
-
processScripts: ['Array of strings corresponding to types of script elements to process through minifier (e.g
|
|
128
|
-
quoteCharacter: ['Type of quote to use for attribute values (
|
|
129
|
-
removeAttributeQuotes: 'Remove quotes around attributes when possible
|
|
127
|
+
processScripts: ['Array of strings corresponding to types of “script” elements to process through minifier (e.g., “text/ng-template”, “text/x-handlebars-template”, etc.)', parseJSONArray],
|
|
128
|
+
quoteCharacter: ['Type of quote to use for attribute values (“\'” or “\"”)', parseString],
|
|
129
|
+
removeAttributeQuotes: 'Remove quotes around attributes when possible',
|
|
130
130
|
removeComments: 'Strip HTML comments',
|
|
131
131
|
removeEmptyAttributes: 'Remove all attributes with whitespace-only values',
|
|
132
132
|
removeEmptyElements: 'Remove all elements with empty contents',
|
|
133
133
|
removeOptionalTags: 'Remove unrequired tags',
|
|
134
|
-
removeRedundantAttributes: 'Remove attributes when value matches default
|
|
135
|
-
removeScriptTypeAttributes: '
|
|
136
|
-
removeStyleLinkTypeAttributes: 'Remove type="text/css" from style and link
|
|
137
|
-
removeTagWhitespace: 'Remove space between attributes whenever possible',
|
|
134
|
+
removeRedundantAttributes: 'Remove attributes when value matches default',
|
|
135
|
+
removeScriptTypeAttributes: 'Remove “type="text/javascript"” from “script” elements; other “type” attribute values are left intact',
|
|
136
|
+
removeStyleLinkTypeAttributes: 'Remove “type="text/css"” from “style” and “link” elements; other “type” attribute values are left intact',
|
|
137
|
+
removeTagWhitespace: 'Remove space between attributes whenever possible; note that this will result in invalid HTML',
|
|
138
138
|
sortAttributes: 'Sort attributes by frequency',
|
|
139
139
|
sortClassName: 'Sort style classes by frequency',
|
|
140
|
-
trimCustomFragments: 'Trim
|
|
141
|
-
useShortDoctype: 'Replaces the doctype with the short (
|
|
140
|
+
trimCustomFragments: 'Trim whitespace around “ignoreCustomFragments”',
|
|
141
|
+
useShortDoctype: 'Replaces the doctype with the short (HTML) doctype'
|
|
142
142
|
};
|
|
143
143
|
|
|
144
144
|
// Configure command line flags
|
package/package.json
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"description": "Highly configurable, well-tested, JavaScript-based HTML minifier.",
|
|
16
16
|
"devDependencies": {
|
|
17
17
|
"@commitlint/cli": "^19.8.1",
|
|
18
|
-
"@jest/globals": "^30.
|
|
18
|
+
"@jest/globals": "^30.1.2",
|
|
19
19
|
"@rollup/plugin-commonjs": "^28.0.6",
|
|
20
20
|
"@rollup/plugin-json": "^6.1.0",
|
|
21
21
|
"@rollup/plugin-node-resolve": "^16.0.1",
|
|
@@ -25,11 +25,11 @@
|
|
|
25
25
|
"eslint": "^9.33.0",
|
|
26
26
|
"husky": "^9.1.7",
|
|
27
27
|
"is-ci": "^4.1.0",
|
|
28
|
-
"jest": "^30.
|
|
28
|
+
"jest": "^30.1.3",
|
|
29
29
|
"lint-staged": "^16.1.5",
|
|
30
|
-
"rollup": "^4.
|
|
30
|
+
"rollup": "^4.50.0",
|
|
31
31
|
"rollup-plugin-polyfill-node": "^0.13.0",
|
|
32
|
-
"vite": "^7.1.
|
|
32
|
+
"vite": "^7.1.5"
|
|
33
33
|
},
|
|
34
34
|
"exports": {
|
|
35
35
|
".": {
|
|
@@ -88,5 +88,5 @@
|
|
|
88
88
|
"test:watch": "NODE_OPTIONS='--experimental-vm-modules --no-warnings' jest --watch"
|
|
89
89
|
},
|
|
90
90
|
"type": "module",
|
|
91
|
-
"version": "1.
|
|
91
|
+
"version": "1.4.1"
|
|
92
92
|
}
|
package/src/htmlminifier.js
CHANGED
|
@@ -260,7 +260,7 @@ function isSrcset(attrName, tag) {
|
|
|
260
260
|
return attrName === 'srcset' && srcsetTags.has(tag);
|
|
261
261
|
}
|
|
262
262
|
|
|
263
|
-
async function cleanAttributeValue(tag, attrName, attrValue, options, attrs) {
|
|
263
|
+
async function cleanAttributeValue(tag, attrName, attrValue, options, attrs, minifyHTMLSelf) {
|
|
264
264
|
if (isEventAttribute(attrName, options)) {
|
|
265
265
|
attrValue = trimWhitespace(attrValue).replace(/^javascript:\s*/i, '');
|
|
266
266
|
return options.minifyJS(attrValue, true);
|
|
@@ -318,6 +318,13 @@ async function cleanAttributeValue(tag, attrName, attrValue, options, attrs) {
|
|
|
318
318
|
} else if (isMediaQuery(tag, attrs, attrName)) {
|
|
319
319
|
attrValue = trimWhitespace(attrValue);
|
|
320
320
|
return options.minifyCSS(attrValue, 'media');
|
|
321
|
+
} else if (tag === 'iframe' && attrName === 'srcdoc') {
|
|
322
|
+
// Recursively minify HTML content within srcdoc attribute
|
|
323
|
+
// Fast-path: skip if nothing would change
|
|
324
|
+
if (!shouldMinifyInnerHTML(options)) {
|
|
325
|
+
return attrValue;
|
|
326
|
+
}
|
|
327
|
+
return minifyHTMLSelf(attrValue, options, true);
|
|
321
328
|
}
|
|
322
329
|
return attrValue;
|
|
323
330
|
}
|
|
@@ -557,7 +564,7 @@ async function normalizeAttr(attr, attrs, tag, options) {
|
|
|
557
564
|
}
|
|
558
565
|
|
|
559
566
|
if (attrValue) {
|
|
560
|
-
attrValue = await cleanAttributeValue(tag, attrName, attrValue, options, attrs);
|
|
567
|
+
attrValue = await cleanAttributeValue(tag, attrName, attrValue, options, attrs, minifyHTML);
|
|
561
568
|
}
|
|
562
569
|
|
|
563
570
|
if (options.removeEmptyAttributes &&
|
|
@@ -632,6 +639,17 @@ function identityAsync(value) {
|
|
|
632
639
|
return Promise.resolve(value);
|
|
633
640
|
}
|
|
634
641
|
|
|
642
|
+
function shouldMinifyInnerHTML(options) {
|
|
643
|
+
return Boolean(
|
|
644
|
+
options.collapseWhitespace ||
|
|
645
|
+
options.removeComments ||
|
|
646
|
+
options.removeOptionalTags ||
|
|
647
|
+
options.minifyJS !== identity ||
|
|
648
|
+
options.minifyCSS !== identityAsync ||
|
|
649
|
+
options.minifyURLs !== identity
|
|
650
|
+
);
|
|
651
|
+
}
|
|
652
|
+
|
|
635
653
|
const processOptions = (inputOptions) => {
|
|
636
654
|
const options = {
|
|
637
655
|
name: function (name) {
|
package/src/htmlparser.js
CHANGED
|
@@ -36,7 +36,7 @@ class CaseInsensitiveSet extends Set {
|
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
// Regular
|
|
39
|
+
// Regular expressions for parsing tags and attributes
|
|
40
40
|
const singleAttrIdentifier = /([^\s"'<>/=]+)/;
|
|
41
41
|
const singleAttrAssigns = [/=/];
|
|
42
42
|
const singleAttrValues = [
|
|
@@ -67,10 +67,10 @@ let IS_REGEX_CAPTURING_BROKEN = false;
|
|
|
67
67
|
IS_REGEX_CAPTURING_BROKEN = g === '';
|
|
68
68
|
});
|
|
69
69
|
|
|
70
|
-
// Empty
|
|
70
|
+
// Empty elements
|
|
71
71
|
const empty = new CaseInsensitiveSet(['area', 'base', 'basefont', 'br', 'col', 'embed', 'frame', 'hr', 'img', 'input', 'isindex', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr']);
|
|
72
72
|
|
|
73
|
-
// Inline
|
|
73
|
+
// Inline elements
|
|
74
74
|
const inline = new CaseInsensitiveSet(['a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'noscript', 'object', 'q', 's', 'samp', 'script', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'svg', 'textarea', 'tt', 'u', 'var']);
|
|
75
75
|
|
|
76
76
|
// Elements that you can, intentionally, leave open
|
|
@@ -80,10 +80,10 @@ const closeSelf = new CaseInsensitiveSet(['colgroup', 'dd', 'dt', 'li', 'option'
|
|
|
80
80
|
// Attributes that have their values filled in disabled='disabled'
|
|
81
81
|
const fillAttrs = new CaseInsensitiveSet(['checked', 'compact', 'declare', 'defer', 'disabled', 'ismap', 'multiple', 'nohref', 'noresize', 'noshade', 'nowrap', 'readonly', 'selected']);
|
|
82
82
|
|
|
83
|
-
// Special
|
|
83
|
+
// Special elements (can contain anything)
|
|
84
84
|
const special = new CaseInsensitiveSet(['script', 'style']);
|
|
85
85
|
|
|
86
|
-
// HTML5
|
|
86
|
+
// HTML5 elements https://html.spec.whatwg.org/multipage/indices.html#elements-3
|
|
87
87
|
// Phrasing Content https://html.spec.whatwg.org/multipage/dom.html#phrasing-content
|
|
88
88
|
const nonPhrasing = new CaseInsensitiveSet(['address', 'article', 'aside', 'base', 'blockquote', 'body', 'caption', 'col', 'colgroup', 'dd', 'details', 'dialog', 'div', 'dl', 'dt', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'legend', 'li', 'menuitem', 'meta', 'ol', 'optgroup', 'option', 'param', 'rp', 'rt', 'source', 'style', 'summary', 'tbody', 'td', 'tfoot', 'th', 'thead', 'title', 'tr', 'track', 'ul']);
|
|
89
89
|
|