html-minifier-next 3.2.2 → 4.1.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 +66 -27
- package/cli.js +1 -1
- package/dist/htmlminifier.cjs +372 -35
- package/dist/htmlminifier.esm.bundle.js +3914 -24726
- package/dist/types/htmlminifier.d.ts +382 -0
- package/dist/types/htmlminifier.d.ts.map +1 -0
- package/dist/types/htmlparser.d.ts +8 -0
- package/dist/types/htmlparser.d.ts.map +1 -0
- package/dist/types/tokenchain.d.ts +9 -0
- package/dist/types/tokenchain.d.ts.map +1 -0
- package/dist/types/utils.d.ts +2 -0
- package/dist/types/utils.d.ts.map +1 -0
- package/package.json +13 -7
- package/src/htmlminifier.js +373 -36
- package/dist/htmlminifier.umd.bundle.js +0 -62195
- package/dist/htmlminifier.umd.bundle.min.js +0 -9
package/README.md
CHANGED
|
@@ -97,7 +97,7 @@ const { minify } = require('html-minifier-next');
|
|
|
97
97
|
})();
|
|
98
98
|
```
|
|
99
99
|
|
|
100
|
-
See [the original blog post](
|
|
100
|
+
See [the original blog post](https://perfectionkills.com/experimenting-with-html-minifier) for details of [how it works](https://perfectionkills.com/experimenting-with-html-minifier#how_it_works), [description of each option](https://perfectionkills.com/experimenting-with-html-minifier#options), [testing results](https://perfectionkills.com/experimenting-with-html-minifier#field_testing), and [conclusions](https://perfectionkills.com/experimenting-with-html-minifier#cost_and_benefits).
|
|
101
101
|
|
|
102
102
|
For lint-like capabilities, take a look at [HTMLLint](https://github.com/kangax/html-lint).
|
|
103
103
|
|
|
@@ -110,9 +110,9 @@ Options can be used in config files (camelCase) or via CLI flags (kebab-case wit
|
|
|
110
110
|
| Option (config/CLI) | Description | Default |
|
|
111
111
|
| --- | --- | --- |
|
|
112
112
|
| `caseSensitive`<br>`--case-sensitive` | Treat attributes in case-sensitive manner (useful for custom HTML elements) | `false` |
|
|
113
|
-
| `collapseBooleanAttributes`<br>`--collapse-boolean-attributes` | [Omit attribute values from boolean attributes](
|
|
113
|
+
| `collapseBooleanAttributes`<br>`--collapse-boolean-attributes` | [Omit attribute values from boolean attributes](https://perfectionkills.com/experimenting-with-html-minifier#collapse_boolean_attributes) | `false` |
|
|
114
114
|
| `collapseInlineTagWhitespace`<br>`--collapse-inline-tag-whitespace` | Don’t leave any spaces between `display: inline;` elements when collapsing—use with `collapseWhitespace: true` | `false` |
|
|
115
|
-
| `collapseWhitespace`<br>`--collapse-whitespace` | [Collapse whitespace that contributes to text nodes in a document tree](
|
|
115
|
+
| `collapseWhitespace`<br>`--collapse-whitespace` | [Collapse whitespace that contributes to text nodes in a document tree](https://perfectionkills.com/experimenting-with-html-minifier#collapse_whitespace) | `false` |
|
|
116
116
|
| `conservativeCollapse`<br>`--conservative-collapse` | Always collapse to 1 space (never remove it entirely)—use with `collapseWhitespace: true` | `false` |
|
|
117
117
|
| `continueOnParseError`<br>`--continue-on-parse-error` | [Handle parse errors](https://html.spec.whatwg.org/multipage/parsing.html#parse-errors) instead of aborting | `false` |
|
|
118
118
|
| `customAttrAssign`<br>`--custom-attr-assign` | Arrays of regexes that allow to support custom attribute assign expressions (e.g., `<div flex?="{{mode != cover}}"></div>`) | `[]` |
|
|
@@ -129,7 +129,7 @@ Options can be used in config files (camelCase) or via CLI flags (kebab-case wit
|
|
|
129
129
|
| `keepClosingSlash`<br>`--keep-closing-slash` | Keep the trailing slash on void elements | `false` |
|
|
130
130
|
| `maxInputLength`<br>`--max-input-length` | Maximum input length to prevent ReDoS attacks (disabled by default) | `undefined` |
|
|
131
131
|
| `maxLineLength`<br>`--max-line-length` | Specify a maximum line length; compressed output will be split by newlines at valid HTML split-points | |
|
|
132
|
-
| `minifyCSS`<br>`--minify-css` | Minify CSS in `style` elements and `style` attributes (uses [
|
|
132
|
+
| `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)`) |
|
|
133
133
|
| `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)`) |
|
|
134
134
|
| `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)`) |
|
|
135
135
|
| `noNewlinesBeforeTagClose`<br>`--no-newlines-before-tag-close` | Never add a newline before a tag that closes an element | `false` |
|
|
@@ -138,11 +138,11 @@ Options can be used in config files (camelCase) or via CLI flags (kebab-case wit
|
|
|
138
138
|
| `processConditionalComments`<br>`--process-conditional-comments` | Process contents of conditional comments through minifier | `false` |
|
|
139
139
|
| `processScripts`<br>`--process-scripts` | Array of strings corresponding to types of `script` elements to process through minifier (e.g., `text/ng-template`, `text/x-handlebars-template`, etc.) | `[]` |
|
|
140
140
|
| `quoteCharacter`<br>`--quote-character` | Type of quote to use for attribute values (`'` or `"`) | |
|
|
141
|
-
| `removeAttributeQuotes`<br>`--remove-attribute-quotes` | [Remove quotes around attributes when possible](
|
|
142
|
-
| `removeComments`<br>`--remove-comments` | [Strip HTML comments](
|
|
143
|
-
| `removeEmptyAttributes`<br>`--remove-empty-attributes` | [Remove all attributes with whitespace-only values](
|
|
144
|
-
| `removeEmptyElements`<br>`--remove-empty-elements` | [Remove all elements with empty contents](
|
|
145
|
-
| `removeOptionalTags`<br>`--remove-optional-tags` | [Remove optional tags](
|
|
141
|
+
| `removeAttributeQuotes`<br>`--remove-attribute-quotes` | [Remove quotes around attributes when possible](https://perfectionkills.com/experimenting-with-html-minifier#remove_attribute_quotes) | `false` |
|
|
142
|
+
| `removeComments`<br>`--remove-comments` | [Strip HTML comments](https://perfectionkills.com/experimenting-with-html-minifier#remove_comments) | `false` |
|
|
143
|
+
| `removeEmptyAttributes`<br>`--remove-empty-attributes` | [Remove all attributes with whitespace-only values](https://perfectionkills.com/experimenting-with-html-minifier#remove_empty_or_blank_attributes) | `false` (could be `true`, `Function(attrName, tag)`) |
|
|
144
|
+
| `removeEmptyElements`<br>`--remove-empty-elements` | [Remove all elements with empty contents](https://perfectionkills.com/experimenting-with-html-minifier#remove_empty_elements) | `false` |
|
|
145
|
+
| `removeOptionalTags`<br>`--remove-optional-tags` | [Remove optional tags](https://perfectionkills.com/experimenting-with-html-minifier#remove_optional_tags) | `false` |
|
|
146
146
|
| `removeRedundantAttributes`<br>`--remove-redundant-attributes` | [Remove attributes when value matches default](https://meiert.com/blog/optional-html/#toc-attribute-values) | `false` |
|
|
147
147
|
| `removeScriptTypeAttributes`<br>`--remove-script-type-attributes` | Remove `type="text/javascript"` from `script` elements; other `type` attribute values are left intact | `false` |
|
|
148
148
|
| `removeStyleLinkTypeAttributes`<br>`--remove-style-link-type-attributes` | Remove `type="text/css"` from `style` and `link` elements; other `type` attribute values are left intact | `false` |
|
|
@@ -150,37 +150,76 @@ Options can be used in config files (camelCase) or via CLI flags (kebab-case wit
|
|
|
150
150
|
| `sortAttributes`<br>`--sort-attributes` | [Sort attributes by frequency](#sorting-attributes-and-style-classes) | `false` |
|
|
151
151
|
| `sortClassName`<br>`--sort-class-name` | [Sort style classes by frequency](#sorting-attributes-and-style-classes) | `false` |
|
|
152
152
|
| `trimCustomFragments`<br>`--trim-custom-fragments` | Trim whitespace around `ignoreCustomFragments` | `false` |
|
|
153
|
-
| `useShortDoctype`<br>`--use-short-doctype` | [Replaces the doctype with the short (HTML) doctype](
|
|
153
|
+
| `useShortDoctype`<br>`--use-short-doctype` | [Replaces the doctype with the short (HTML) doctype](https://perfectionkills.com/experimenting-with-html-minifier#use_short_doctype) | `false` |
|
|
154
154
|
|
|
155
155
|
### Sorting attributes and style classes
|
|
156
156
|
|
|
157
|
-
Minifier options like `sortAttributes` and `sortClassName` won
|
|
157
|
+
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.
|
|
158
|
+
|
|
159
|
+
### CSS minification with Lightning CSS
|
|
160
|
+
|
|
161
|
+
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.
|
|
162
|
+
|
|
163
|
+
You can pass Lightning CSS configuration options by providing an object:
|
|
164
|
+
|
|
165
|
+
```js
|
|
166
|
+
const result = await minify(html, {
|
|
167
|
+
minifyCSS: {
|
|
168
|
+
targets: {
|
|
169
|
+
// Browser targets for vendor prefix handling
|
|
170
|
+
chrome: 95,
|
|
171
|
+
firefox: 90,
|
|
172
|
+
safari: 14
|
|
173
|
+
},
|
|
174
|
+
unusedSymbols: ['unused-class', 'old-animation']
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Available Lightning CSS options when passed as an object:
|
|
180
|
+
|
|
181
|
+
* `targets`: Browser targets for vendor prefix optimization (e.g., `{ chrome: 95, firefox: 90 }`)
|
|
182
|
+
* `unusedSymbols`: Array of class names, IDs, keyframe names, and CSS variables to remove
|
|
183
|
+
* `errorRecovery`: Boolean to skip invalid rules instead of throwing errors (disabled in Lightning CSS, but enabled by default in HMN)
|
|
184
|
+
* `sourceMap`: Boolean to generate source maps
|
|
185
|
+
|
|
186
|
+
For advanced usage, you can also pass a function:
|
|
187
|
+
|
|
188
|
+
```js
|
|
189
|
+
const result = await minify(html, {
|
|
190
|
+
minifyCSS: function(text, type) {
|
|
191
|
+
// `text`: CSS string to minify
|
|
192
|
+
// `type`: `inline` for style attributes, `media` for media queries, `undefined` for `<style>` elements
|
|
193
|
+
return yourCustomMinifier(text);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
```
|
|
158
197
|
|
|
159
198
|
## Minification comparison
|
|
160
199
|
|
|
161
|
-
How does HTML Minifier Next compare to other solutions, like [minimize](https://github.com/Swaagie/minimize), [htmlcompressor.com](http://htmlcompressor.com/), [htmlnano](https://github.com/posthtml/htmlnano), and [minify-html](https://github.com/wilsonzlin/minify-html)? (All with the most aggressive settings,
|
|
200
|
+
How does HTML Minifier Next compare to other solutions, like [minimize](https://github.com/Swaagie/minimize), [htmlcompressor.com](http://htmlcompressor.com/), [htmlnano](https://github.com/posthtml/htmlnano), and [minify-html](https://github.com/wilsonzlin/minify-html)? (All with the most aggressive settings, though without [hyper-optimization](https://meiert.com/blog/the-ways-of-writing-html/#toc-hyper-optimized).)
|
|
162
201
|
|
|
163
202
|
| Site | Original Size (KB) | HTML Minifier Next | minimize | htmlcompressor.com | htmlnano | minify-html |
|
|
164
203
|
| --- | --- | --- | --- | --- | --- | --- |
|
|
165
|
-
| [A List Apart](https://alistapart.com/) | 62 | **
|
|
204
|
+
| [A List Apart](https://alistapart.com/) | 62 | **52** | 58 | 56 | 54 | 55 |
|
|
166
205
|
| [Amazon](https://www.amazon.com/) | 206 | **195** | 203 | 200 | 196 | n/a |
|
|
167
|
-
| [Apple](https://www.apple.com/) |
|
|
168
|
-
| [BBC](https://www.bbc.co.uk/) |
|
|
169
|
-
| [CSS-Tricks](https://css-tricks.com/) |
|
|
170
|
-
| [ECMAScript](https://tc39.es/ecma262/) |
|
|
171
|
-
| [EFF](https://www.eff.org/) | 57 | **48** | 52 |
|
|
172
|
-
| [FAZ](https://www.faz.net/aktuell/) |
|
|
173
|
-
| [Frontend Dogma](https://frontenddogma.com/) |
|
|
206
|
+
| [Apple](https://www.apple.com/) | 153 | **116** | 140 | 140 | 133 | 138 |
|
|
207
|
+
| [BBC](https://www.bbc.co.uk/) | 590 | **534** | 585 | n/a | 553 | 555 |
|
|
208
|
+
| [CSS-Tricks](https://css-tricks.com/) | 165 | **124** | 151 | 147 | 129 | 146 |
|
|
209
|
+
| [ECMAScript](https://tc39.es/ecma262/) | 7238 | **6342** | 6614 | n/a | 6561 | 6567 |
|
|
210
|
+
| [EFF](https://www.eff.org/) | 57 | **48** | 52 | 51 | 51 | 49 |
|
|
211
|
+
| [FAZ](https://www.faz.net/aktuell/) | 1847 | 1722 | 1762 | n/a | **1628** | n/a |
|
|
212
|
+
| [Frontend Dogma](https://frontenddogma.com/) | 219 | **211** | 237 | 218 | 232 | 218 |
|
|
174
213
|
| [Google](https://www.google.com/) | 18 | **16** | 18 | 18 | 17 | n/a |
|
|
175
|
-
| [Ground News](https://ground.news/) |
|
|
214
|
+
| [Ground News](https://ground.news/) | 1709 | **1463** | 1696 | n/a | 1567 | n/a |
|
|
176
215
|
| [HTML](https://html.spec.whatwg.org/multipage/) | 149 | **147** | 155 | 148 | 153 | 149 |
|
|
177
|
-
| [Leanpub](https://leanpub.com/) |
|
|
216
|
+
| [Leanpub](https://leanpub.com/) | 1424 | **1190** | 1418 | n/a | 1197 | n/a |
|
|
178
217
|
| [Mastodon](https://mastodon.social/explore) | 35 | **26** | 34 | 34 | 30 | 33 |
|
|
179
|
-
| [MDN](https://developer.mozilla.org/en-US/) | 107 | **
|
|
180
|
-
| [Middle East Eye](https://www.middleeasteye.net/) | 224 | **197** |
|
|
181
|
-
| [SitePoint](https://www.sitepoint.com/) |
|
|
182
|
-
| [United Nations](https://www.un.org/en/) | 151 | **
|
|
183
|
-
| [W3C](https://www.w3.org/) | 50 | **36** | 41 | 39 |
|
|
218
|
+
| [MDN](https://developer.mozilla.org/en-US/) | 107 | **62** | 67 | 68 | 64 | n/a |
|
|
219
|
+
| [Middle East Eye](https://www.middleeasteye.net/) | 224 | **197** | 203 | 204 | 204 | 201 |
|
|
220
|
+
| [SitePoint](https://www.sitepoint.com/) | 536 | **405** | 532 | n/a | 474 | 516 |
|
|
221
|
+
| [United Nations](https://www.un.org/en/) | 151 | **113** | 130 | 123 | 121 | 125 |
|
|
222
|
+
| [W3C](https://www.w3.org/) | 50 | **36** | 41 | 39 | 39 | 39 |
|
|
184
223
|
|
|
185
224
|
## Examples
|
|
186
225
|
|
package/cli.js
CHANGED
|
@@ -135,7 +135,7 @@ const mainOptions = {
|
|
|
135
135
|
keepClosingSlash: 'Keep the trailing slash on void elements',
|
|
136
136
|
maxInputLength: ['Maximum input length to prevent ReDoS attacks', parseValidInt('maxInputLength')],
|
|
137
137
|
maxLineLength: ['Specify a maximum line length; compressed output will be split by newlines at valid HTML split-points', parseValidInt('maxLineLength')],
|
|
138
|
-
minifyCSS: ['Minify CSS in “style” elements and “style” attributes (uses
|
|
138
|
+
minifyCSS: ['Minify CSS in “style” elements and “style” attributes (uses Lightning CSS)', parseJSON],
|
|
139
139
|
minifyJS: ['Minify JavaScript in “script” elements and event attributes (uses Terser)', parseJSON],
|
|
140
140
|
minifyURLs: ['Minify URLs in various attributes (uses relateurl)', parseJSON],
|
|
141
141
|
noNewlinesBeforeTagClose: 'Never add a newline before a tag that closes an element',
|
package/dist/htmlminifier.cjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var
|
|
5
|
+
var lightningcss = require('lightningcss');
|
|
6
6
|
var entities = require('entities');
|
|
7
7
|
var RelateURL = require('relateurl');
|
|
8
8
|
var terser = require('terser');
|
|
@@ -920,12 +920,8 @@ function isContentSecurityPolicy(tag, attrs) {
|
|
|
920
920
|
}
|
|
921
921
|
}
|
|
922
922
|
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
}
|
|
926
|
-
|
|
927
|
-
// Wrap CSS declarations for CleanCSS > 3.x
|
|
928
|
-
// See https://github.com/jakubpawlowicz/clean-css/issues/418
|
|
923
|
+
// Wrap CSS declarations for inline styles and media queries
|
|
924
|
+
// This ensures proper context for CSS minification
|
|
929
925
|
function wrapCSS(text, type) {
|
|
930
926
|
switch (type) {
|
|
931
927
|
case 'inline':
|
|
@@ -1257,7 +1253,7 @@ const processOptions = (inputOptions) => {
|
|
|
1257
1253
|
return;
|
|
1258
1254
|
}
|
|
1259
1255
|
|
|
1260
|
-
const
|
|
1256
|
+
const lightningCssOptions = typeof option === 'object' ? option : {};
|
|
1261
1257
|
|
|
1262
1258
|
options.minifyCSS = async function (text, type) {
|
|
1263
1259
|
text = await replaceAsync(
|
|
@@ -1278,17 +1274,38 @@ const processOptions = (inputOptions) => {
|
|
|
1278
1274
|
|
|
1279
1275
|
const inputCSS = wrapCSS(text, type);
|
|
1280
1276
|
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
const outputCSS = unwrapCSS(output.styles, type);
|
|
1289
|
-
resolve(outputCSS);
|
|
1277
|
+
try {
|
|
1278
|
+
const result = lightningcss.transform({
|
|
1279
|
+
filename: 'input.css',
|
|
1280
|
+
code: Buffer.from(inputCSS),
|
|
1281
|
+
minify: true,
|
|
1282
|
+
errorRecovery: true,
|
|
1283
|
+
...lightningCssOptions
|
|
1290
1284
|
});
|
|
1291
|
-
|
|
1285
|
+
|
|
1286
|
+
const outputCSS = unwrapCSS(result.code.toString(), type);
|
|
1287
|
+
|
|
1288
|
+
// If Lightning CSS removed significant content that looks like template syntax or UIDs, return original
|
|
1289
|
+
// This preserves:
|
|
1290
|
+
// 1. Template code like `<?php ?>`, `<%= %>`, `{{ }}`, etc. (contain `<` or `>` but not `CDATA`)
|
|
1291
|
+
// 2. UIDs representing custom fragments (only lowercase letters and digits, no spaces)
|
|
1292
|
+
// CDATA sections, HTML entities, and other invalid CSS are allowed to be removed
|
|
1293
|
+
const isCDATA = text.includes('<![CDATA[');
|
|
1294
|
+
const uidPattern = /[a-z0-9]{10,}/; // UIDs are long alphanumeric strings
|
|
1295
|
+
const hasUID = uidPattern.test(text) && !isCDATA; // Exclude CDATA from UID detection
|
|
1296
|
+
const looksLikeTemplate = (text.includes('<') || text.includes('>')) && !isCDATA;
|
|
1297
|
+
|
|
1298
|
+
// Preserve if output is empty and input had template syntax or UIDs
|
|
1299
|
+
// This catches cases where Lightning CSS removed content that should be preserved
|
|
1300
|
+
if (text.trim() && !outputCSS.trim() && (looksLikeTemplate || hasUID)) {
|
|
1301
|
+
return text;
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
return outputCSS;
|
|
1305
|
+
} catch (err) {
|
|
1306
|
+
options.log && options.log(err);
|
|
1307
|
+
return text;
|
|
1308
|
+
}
|
|
1292
1309
|
};
|
|
1293
1310
|
} else if (key === 'minifyJS' && typeof option !== 'function') {
|
|
1294
1311
|
if (!option) {
|
|
@@ -1526,23 +1543,7 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1526
1543
|
return chunks[1] + uidAttr + index + uidAttr + chunks[2];
|
|
1527
1544
|
});
|
|
1528
1545
|
|
|
1529
|
-
|
|
1530
|
-
new CleanCSS().minify(wrapCSS(text, type)).warnings.forEach(function (warning) {
|
|
1531
|
-
const match = uidPattern.exec(warning);
|
|
1532
|
-
if (match) {
|
|
1533
|
-
const id = uidAttr + match[2] + uidAttr;
|
|
1534
|
-
text = text.replace(id, ignoreCSS(id));
|
|
1535
|
-
ids.push(id);
|
|
1536
|
-
}
|
|
1537
|
-
});
|
|
1538
|
-
|
|
1539
|
-
return fn(text, type).then(chunk => {
|
|
1540
|
-
ids.forEach(function (id) {
|
|
1541
|
-
chunk = chunk.replace(ignoreCSS(id), id);
|
|
1542
|
-
});
|
|
1543
|
-
|
|
1544
|
-
return chunk;
|
|
1545
|
-
});
|
|
1546
|
+
return fn(text, type);
|
|
1546
1547
|
};
|
|
1547
1548
|
})(options.minifyCSS);
|
|
1548
1549
|
}
|
|
@@ -1981,6 +1982,11 @@ function joinResultSegments(results, options, restoreCustom, restoreIgnore) {
|
|
|
1981
1982
|
return options.collapseWhitespace ? collapseWhitespace(str, options, true, true) : str;
|
|
1982
1983
|
}
|
|
1983
1984
|
|
|
1985
|
+
/**
|
|
1986
|
+
* @param {string} value
|
|
1987
|
+
* @param {MinifierOptions} [options]
|
|
1988
|
+
* @returns {Promise<string>}
|
|
1989
|
+
*/
|
|
1984
1990
|
const minify = async function (value, options) {
|
|
1985
1991
|
const start = Date.now();
|
|
1986
1992
|
options = processOptions(options || {});
|
|
@@ -1991,5 +1997,336 @@ const minify = async function (value, options) {
|
|
|
1991
1997
|
|
|
1992
1998
|
var htmlminifier = { minify };
|
|
1993
1999
|
|
|
2000
|
+
/**
|
|
2001
|
+
* @typedef {Object} HTMLAttribute
|
|
2002
|
+
* Representation of an attribute from the HTML parser.
|
|
2003
|
+
*
|
|
2004
|
+
* @prop {string} name
|
|
2005
|
+
* @prop {string} [value]
|
|
2006
|
+
* @prop {string} [quote]
|
|
2007
|
+
* @prop {string} [customAssign]
|
|
2008
|
+
* @prop {string} [customOpen]
|
|
2009
|
+
* @prop {string} [customClose]
|
|
2010
|
+
*/
|
|
2011
|
+
|
|
2012
|
+
/**
|
|
2013
|
+
* @typedef {Object} MinifierOptions
|
|
2014
|
+
* Options that control how HTML is minified. All of these are optional
|
|
2015
|
+
* and usually default to a disabled/safe value unless noted.
|
|
2016
|
+
*
|
|
2017
|
+
* @prop {(tag: string, attrs: HTMLAttribute[], canCollapseWhitespace: (tag: string) => boolean) => boolean} [canCollapseWhitespace]
|
|
2018
|
+
* Predicate that determines whether whitespace inside a given element
|
|
2019
|
+
* can be collapsed.
|
|
2020
|
+
*
|
|
2021
|
+
* Default: Built-in `canCollapseWhitespace` function
|
|
2022
|
+
*
|
|
2023
|
+
* @prop {(tag: string | null, attrs: HTMLAttribute[] | undefined, canTrimWhitespace: (tag: string) => boolean) => boolean} [canTrimWhitespace]
|
|
2024
|
+
* Predicate that determines whether leading/trailing whitespace around
|
|
2025
|
+
* the element may be trimmed.
|
|
2026
|
+
*
|
|
2027
|
+
* Default: Built-in `canTrimWhitespace` function
|
|
2028
|
+
*
|
|
2029
|
+
* @prop {boolean} [caseSensitive]
|
|
2030
|
+
* When true, tag and attribute names are treated as case-sensitive.
|
|
2031
|
+
* Useful for custom HTML tags.
|
|
2032
|
+
* If false (default) names are lower-cased via the `name` function.
|
|
2033
|
+
*
|
|
2034
|
+
* Default: `false`
|
|
2035
|
+
*
|
|
2036
|
+
* @prop {boolean} [collapseBooleanAttributes]
|
|
2037
|
+
* Collapse boolean attributes to their name only (for example
|
|
2038
|
+
* `disabled="disabled"` -> `disabled`).
|
|
2039
|
+
* See also: https://perfectionkills.com/experimenting-with-html-minifier/#collapse_boolean_attributes
|
|
2040
|
+
*
|
|
2041
|
+
* Default: `false`
|
|
2042
|
+
*
|
|
2043
|
+
* @prop {boolean} [collapseInlineTagWhitespace]
|
|
2044
|
+
* When false (default) whitespace around `inline` tags is preserved in
|
|
2045
|
+
* more cases. When true, whitespace around inline tags may be collapsed.
|
|
2046
|
+
* Must also enable `collapseWhitespace` to have effect.
|
|
2047
|
+
*
|
|
2048
|
+
* Default: `false`
|
|
2049
|
+
*
|
|
2050
|
+
* @prop {boolean} [collapseWhitespace]
|
|
2051
|
+
* Collapse multiple whitespace characters into one where allowed. Also
|
|
2052
|
+
* controls trimming behaviour in several code paths.
|
|
2053
|
+
* See also: https://perfectionkills.com/experimenting-with-html-minifier/#collapse_whitespace
|
|
2054
|
+
*
|
|
2055
|
+
* Default: `false`
|
|
2056
|
+
*
|
|
2057
|
+
* @prop {boolean} [conservativeCollapse]
|
|
2058
|
+
* If true, be conservative when collapsing whitespace (preserve more
|
|
2059
|
+
* whitespace in edge cases). Affects collapse algorithms.
|
|
2060
|
+
* Must also enable `collapseWhitespace` to have effect.
|
|
2061
|
+
*
|
|
2062
|
+
* Default: `false`
|
|
2063
|
+
*
|
|
2064
|
+
* @prop {boolean} [continueOnParseError]
|
|
2065
|
+
* When true, the parser will attempt to continue on recoverable parse
|
|
2066
|
+
* errors. Otherwise, parsing errors may throw.
|
|
2067
|
+
*
|
|
2068
|
+
* Default: `false`
|
|
2069
|
+
*
|
|
2070
|
+
* @prop {RegExp[]} [customAttrAssign]
|
|
2071
|
+
* Array of regexes used to recognise custom attribute assignment
|
|
2072
|
+
* operators (e.g. `'<div flex?="{{mode != cover}}"></div>'`).
|
|
2073
|
+
* These are concatenated with the built-in assignment patterns.
|
|
2074
|
+
*
|
|
2075
|
+
* Default: `[]`
|
|
2076
|
+
*
|
|
2077
|
+
* @prop {RegExp} [customAttrCollapse]
|
|
2078
|
+
* Regex matching attribute names whose values should be collapsed.
|
|
2079
|
+
* Basically used to remove newlines and excess spaces inside attribute values,
|
|
2080
|
+
* e.g. `/ng-class/`.
|
|
2081
|
+
*
|
|
2082
|
+
* @prop {[RegExp, RegExp][]} [customAttrSurround]
|
|
2083
|
+
* Array of `[openRegExp, closeRegExp]` pairs used by the parser to
|
|
2084
|
+
* detect custom attribute surround patterns (for non-standard syntaxes,
|
|
2085
|
+
* e.g. `<input {{#if value}}checked="checked"{{/if}}>`).
|
|
2086
|
+
*
|
|
2087
|
+
* @prop {RegExp[]} [customEventAttributes]
|
|
2088
|
+
* Array of regexes used to detect event handler attributes for `minifyJS`
|
|
2089
|
+
* (e.g. `ng-click`). The default matches standard `on…` event attributes.
|
|
2090
|
+
*
|
|
2091
|
+
* Default: `[/^on[a-z]{3,}$/]`
|
|
2092
|
+
*
|
|
2093
|
+
* @prop {number} [customFragmentQuantifierLimit]
|
|
2094
|
+
* Limits the quantifier used when building a safe regex for custom
|
|
2095
|
+
* fragments to avoid ReDoS. See source use for details.
|
|
2096
|
+
*
|
|
2097
|
+
* Default: `200`
|
|
2098
|
+
*
|
|
2099
|
+
* @prop {boolean} [decodeEntities]
|
|
2100
|
+
* When true, decodes HTML entities in text and attributes before
|
|
2101
|
+
* processing, and re-encodes ambiguous ampersands when outputting.
|
|
2102
|
+
*
|
|
2103
|
+
* Default: `false`
|
|
2104
|
+
*
|
|
2105
|
+
* @prop {boolean} [html5]
|
|
2106
|
+
* Parse and emit using HTML5 rules. Set to `false` to use non-HTML5
|
|
2107
|
+
* parsing behavior.
|
|
2108
|
+
*
|
|
2109
|
+
* Default: `true`
|
|
2110
|
+
*
|
|
2111
|
+
* @prop {RegExp[]} [ignoreCustomComments]
|
|
2112
|
+
* Comments matching any pattern in this array of regexes will be
|
|
2113
|
+
* preserved when `removeComments` is enabled. The default preserves
|
|
2114
|
+
* “bang” comments and comments starting with `#`.
|
|
2115
|
+
*
|
|
2116
|
+
* Default: `[/^!/, /^\s*#/]`
|
|
2117
|
+
*
|
|
2118
|
+
* @prop {RegExp[]} [ignoreCustomFragments]
|
|
2119
|
+
* Array of regexes used to identify fragments that should be
|
|
2120
|
+
* preserved (for example server templates). These fragments are temporarily
|
|
2121
|
+
* replaced during minification to avoid corrupting template code.
|
|
2122
|
+
* The default preserves ASP/PHP-style tags.
|
|
2123
|
+
*
|
|
2124
|
+
* Default: `[/<%[\s\S]*?%>/, /<\?[\s\S]*?\?>/]`
|
|
2125
|
+
*
|
|
2126
|
+
* @prop {boolean} [includeAutoGeneratedTags]
|
|
2127
|
+
* If false, tags marked as auto-generated by the parser will be omitted
|
|
2128
|
+
* from output. Useful to skip injected tags.
|
|
2129
|
+
*
|
|
2130
|
+
* Default: `true`
|
|
2131
|
+
*
|
|
2132
|
+
* @prop {ArrayLike<string>} [inlineCustomElements]
|
|
2133
|
+
* Collection of custom element tag names that should be treated as inline
|
|
2134
|
+
* elements for white-space handling, alongside the built-in inline elements.
|
|
2135
|
+
*
|
|
2136
|
+
* Default: `[]`
|
|
2137
|
+
*
|
|
2138
|
+
* @prop {boolean} [keepClosingSlash]
|
|
2139
|
+
* Preserve the trailing slash in self-closing tags when present.
|
|
2140
|
+
*
|
|
2141
|
+
* Default: `false`
|
|
2142
|
+
*
|
|
2143
|
+
* @prop {(message: unknown) => void} [log]
|
|
2144
|
+
* Logging function used by the minifier for warnings/errors/info.
|
|
2145
|
+
* You can directly provide `console.log`, but `message` may also be an `Error`
|
|
2146
|
+
* object or other non-string value.
|
|
2147
|
+
*
|
|
2148
|
+
* Default: `() => {}` (no-op function)
|
|
2149
|
+
*
|
|
2150
|
+
* @prop {number} [maxInputLength]
|
|
2151
|
+
* The maximum allowed input length. Used as a guard against ReDoS via
|
|
2152
|
+
* pathological inputs. If the input exceeds this length an error is
|
|
2153
|
+
* thrown.
|
|
2154
|
+
*
|
|
2155
|
+
* Default: No limit
|
|
2156
|
+
*
|
|
2157
|
+
* @prop {number} [maxLineLength]
|
|
2158
|
+
* Maximum line length for the output. When set the minifier will wrap
|
|
2159
|
+
* output to the given number of characters where possible.
|
|
2160
|
+
*
|
|
2161
|
+
* Default: No limit
|
|
2162
|
+
*
|
|
2163
|
+
* @prop {boolean | import("lightningcss").TransformOptions<import("lightningcss").CustomAtRules> | ((text: string, type?: string) => Promise<string> | string)} [minifyCSS]
|
|
2164
|
+
* When true, enables CSS minification for inline `<style>` tags or
|
|
2165
|
+
* `style` attributes. If an object is provided, it is passed to
|
|
2166
|
+
* [Lightning CSS](https://www.npmjs.com/package/lightningcss)
|
|
2167
|
+
* as transform options. If a function is provided, it will be used to perform
|
|
2168
|
+
* custom CSS minification. If disabled, CSS is not minified.
|
|
2169
|
+
*
|
|
2170
|
+
* Default: `false`
|
|
2171
|
+
*
|
|
2172
|
+
* @prop {boolean | import("terser").MinifyOptions | ((text: string, inline?: boolean) => Promise<string> | string)} [minifyJS]
|
|
2173
|
+
* When true, enables JS minification for `<script>` contents and
|
|
2174
|
+
* event handler attributes. If an object is provided, it is passed to
|
|
2175
|
+
* [terser](https://www.npmjs.com/package/terser) as minify options.
|
|
2176
|
+
* If a function is provided, it will be used to perform
|
|
2177
|
+
* custom JS minification. If disabled, JS is not minified.
|
|
2178
|
+
*
|
|
2179
|
+
* Default: `false`
|
|
2180
|
+
*
|
|
2181
|
+
* @prop {boolean | string | import("relateurl").Options | ((text: string) => Promise<string> | string)} [minifyURLs]
|
|
2182
|
+
* When true, enables URL rewriting/minification. If an object is provided,
|
|
2183
|
+
* it is passed to [relateurl](https://www.npmjs.com/package/relateurl)
|
|
2184
|
+
* as options. If a string is provided, it is treated as an `{ site: string }`
|
|
2185
|
+
* options object. If a function is provided, it will be used to perform
|
|
2186
|
+
* custom URL minification. If disabled, URLs are not minified.
|
|
2187
|
+
*
|
|
2188
|
+
* Default: `false`
|
|
2189
|
+
*
|
|
2190
|
+
* @prop {(name: string) => string} [name]
|
|
2191
|
+
* Function used to normalise tag/attribute names. By default, this lowercases
|
|
2192
|
+
* names, unless `caseSensitive` is enabled.
|
|
2193
|
+
*
|
|
2194
|
+
* Default: `(name) => name.toLowerCase()`,
|
|
2195
|
+
* or `(name) => name` (no-op function) if `caseSensitive` is enabled.
|
|
2196
|
+
*
|
|
2197
|
+
* @prop {boolean} [noNewlinesBeforeTagClose]
|
|
2198
|
+
* When wrapping lines, prevent inserting a newline directly before a
|
|
2199
|
+
* closing tag (useful to keep tags like `</a>` on the same line).
|
|
2200
|
+
*
|
|
2201
|
+
* Default: `false`
|
|
2202
|
+
*
|
|
2203
|
+
* @prop {boolean} [preserveLineBreaks]
|
|
2204
|
+
* Preserve a single line break at the start/end of text nodes when
|
|
2205
|
+
* collapsing/trimming whitespace.
|
|
2206
|
+
* Must also enable `collapseWhitespace` to have effect.
|
|
2207
|
+
*
|
|
2208
|
+
* Default: `false`
|
|
2209
|
+
*
|
|
2210
|
+
* @prop {boolean} [preventAttributesEscaping]
|
|
2211
|
+
* When true, attribute values will not be HTML-escaped (dangerous for
|
|
2212
|
+
* untrusted input). By default, attributes are escaped.
|
|
2213
|
+
*
|
|
2214
|
+
* Default: `false`
|
|
2215
|
+
*
|
|
2216
|
+
* @prop {boolean} [processConditionalComments]
|
|
2217
|
+
* When true, conditional comments (for example `<!--[if IE]> … <![endif]-->`)
|
|
2218
|
+
* will have their inner content processed by the minifier.
|
|
2219
|
+
* Useful to minify HTML that appears inside conditional comments.
|
|
2220
|
+
*
|
|
2221
|
+
* Default: `false`
|
|
2222
|
+
*
|
|
2223
|
+
* @prop {string[]} [processScripts]
|
|
2224
|
+
* Array of `type` attribute values for `<script>` elements whose contents
|
|
2225
|
+
* should be processed as HTML
|
|
2226
|
+
* (e.g. `text/ng-template`, `text/x-handlebars-template`, etc.).
|
|
2227
|
+
* When present, the contents of matching script tags are recursively minified,
|
|
2228
|
+
* like normal HTML content.
|
|
2229
|
+
*
|
|
2230
|
+
* Default: `[]`
|
|
2231
|
+
*
|
|
2232
|
+
* @prop {"\"" | "'"} [quoteCharacter]
|
|
2233
|
+
* Preferred quote character for attribute values. If unspecified the
|
|
2234
|
+
* minifier picks the safest quote based on the attribute value.
|
|
2235
|
+
*
|
|
2236
|
+
* Default: Auto-detected
|
|
2237
|
+
*
|
|
2238
|
+
* @prop {boolean} [removeAttributeQuotes]
|
|
2239
|
+
* Remove quotes around attribute values where it is safe to do so.
|
|
2240
|
+
* See also: https://perfectionkills.com/experimenting-with-html-minifier/#remove_attribute_quotes
|
|
2241
|
+
*
|
|
2242
|
+
* Default: `false`
|
|
2243
|
+
*
|
|
2244
|
+
* @prop {boolean} [removeComments]
|
|
2245
|
+
* Remove HTML comments. Comments that match `ignoreCustomComments` will
|
|
2246
|
+
* still be preserved.
|
|
2247
|
+
* See also: https://perfectionkills.com/experimenting-with-html-minifier/#remove_comments
|
|
2248
|
+
*
|
|
2249
|
+
* Default: `false`
|
|
2250
|
+
*
|
|
2251
|
+
* @prop {boolean | ((attrName: string, tag: string) => boolean)} [removeEmptyAttributes]
|
|
2252
|
+
* If true, removes attributes whose values are empty (some attributes
|
|
2253
|
+
* are excluded by name). Can also be a function to customise which empty
|
|
2254
|
+
* attributes are removed.
|
|
2255
|
+
* See also: https://perfectionkills.com/experimenting-with-html-minifier/#remove_empty_or_blank_attributes
|
|
2256
|
+
*
|
|
2257
|
+
* Default: `false`
|
|
2258
|
+
*
|
|
2259
|
+
* @prop {boolean} [removeEmptyElements]
|
|
2260
|
+
* Remove elements that are empty and safe to remove (for example
|
|
2261
|
+
* `<script />` without `src`).
|
|
2262
|
+
* See also: https://perfectionkills.com/experimenting-with-html-minifier/#remove_empty_elements
|
|
2263
|
+
*
|
|
2264
|
+
* Default: `false`
|
|
2265
|
+
*
|
|
2266
|
+
* @prop {boolean} [removeOptionalTags]
|
|
2267
|
+
* Drop optional start/end tags where the HTML specification permits it
|
|
2268
|
+
* (for example `</li>`, optional `<html>` etc.).
|
|
2269
|
+
* See also: https://perfectionkills.com/experimenting-with-html-minifier/#remove_optional_tags
|
|
2270
|
+
*
|
|
2271
|
+
* Default: `false`
|
|
2272
|
+
*
|
|
2273
|
+
* @prop {boolean} [removeRedundantAttributes]
|
|
2274
|
+
* Remove attributes that are redundant because they match the element's
|
|
2275
|
+
* default values (for example `<button type="submit">`).
|
|
2276
|
+
* See also: https://perfectionkills.com/experimenting-with-html-minifier/#remove_redundant_attributes
|
|
2277
|
+
*
|
|
2278
|
+
* Default: `false`
|
|
2279
|
+
*
|
|
2280
|
+
* @prop {boolean} [removeScriptTypeAttributes]
|
|
2281
|
+
* Remove `type` attributes from `<script>` when they are unnecessary
|
|
2282
|
+
* (e.g. `type="text/javascript"`).
|
|
2283
|
+
*
|
|
2284
|
+
* Default: `false`
|
|
2285
|
+
*
|
|
2286
|
+
* @prop {boolean} [removeStyleLinkTypeAttributes]
|
|
2287
|
+
* Remove `type` attributes from `<style>` and `<link>` elements when
|
|
2288
|
+
* they are unnecessary (e.g. `type="text/css"`).
|
|
2289
|
+
*
|
|
2290
|
+
* Default: `false`
|
|
2291
|
+
*
|
|
2292
|
+
* @prop {boolean} [removeTagWhitespace]
|
|
2293
|
+
* **Note that this will currently result in invalid HTML!**
|
|
2294
|
+
*
|
|
2295
|
+
* When true, extra whitespace between tag name and attributes (or before
|
|
2296
|
+
* the closing bracket) will be removed where possible. Affects output spacing
|
|
2297
|
+
* such as the space used in the short doctype representation.
|
|
2298
|
+
*
|
|
2299
|
+
* Default: `false`
|
|
2300
|
+
*
|
|
2301
|
+
* @prop {boolean | ((tag: string, attrs: HTMLAttribute[]) => void)} [sortAttributes]
|
|
2302
|
+
* When true, enables sorting of attributes. If a function is provided it
|
|
2303
|
+
* will be used as a custom attribute sorter, which should mutate `attrs`
|
|
2304
|
+
* in-place to the desired order. If disabled, the minifier will attempt to
|
|
2305
|
+
* preserve the order from the input.
|
|
2306
|
+
*
|
|
2307
|
+
* Default: `false`
|
|
2308
|
+
*
|
|
2309
|
+
* @prop {boolean | ((value: string) => string)} [sortClassName]
|
|
2310
|
+
* When true, enables sorting of class names inside `class` attributes.
|
|
2311
|
+
* If a function is provided it will be used to transform/sort the class
|
|
2312
|
+
* name string. If disabled, the minifier will attempt to preserve the
|
|
2313
|
+
* class-name order from the input.
|
|
2314
|
+
*
|
|
2315
|
+
* Default: `false`
|
|
2316
|
+
*
|
|
2317
|
+
* @prop {boolean} [trimCustomFragments]
|
|
2318
|
+
* When true, whitespace around ignored custom fragments may be trimmed
|
|
2319
|
+
* more aggressively. This affects how preserved fragments interact with
|
|
2320
|
+
* surrounding whitespace collapse.
|
|
2321
|
+
*
|
|
2322
|
+
* Default: `false`
|
|
2323
|
+
*
|
|
2324
|
+
* @prop {boolean} [useShortDoctype]
|
|
2325
|
+
* Replace the HTML doctype with the short `<!doctype html>` form.
|
|
2326
|
+
* See also: https://perfectionkills.com/experimenting-with-html-minifier/#use_short_doctype
|
|
2327
|
+
*
|
|
2328
|
+
* Default: `false`
|
|
2329
|
+
*/
|
|
2330
|
+
|
|
1994
2331
|
exports.default = htmlminifier;
|
|
1995
2332
|
exports.minify = minify;
|