htmlnano 0.2.4 → 0.2.8
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/CHANGELOG.md +79 -10
- package/README.md +318 -18
- package/lib/helpers.js +16 -36
- package/lib/htmlnano.js +33 -73
- package/lib/modules/collapseAttributeWhitespace.js +21 -19
- package/lib/modules/collapseBooleanAttributes.js +34 -48
- package/lib/modules/collapseWhitespace.js +66 -32
- package/lib/modules/custom.js +12 -12
- package/lib/modules/deduplicateAttributeValues.js +34 -36
- package/lib/modules/mergeScripts.js +46 -63
- package/lib/modules/mergeStyles.js +33 -32
- package/lib/modules/minifyConditionalComments.js +52 -0
- package/lib/modules/minifyCss.js +33 -41
- package/lib/modules/minifyJs.js +72 -68
- package/lib/modules/minifyJson.js +23 -17
- package/lib/modules/minifySvg.js +19 -28
- package/lib/modules/minifyUrls.js +117 -0
- package/lib/modules/removeAttributeQuotes.js +19 -0
- package/lib/modules/removeComments.js +52 -34
- package/lib/modules/removeEmptyAttributes.js +19 -21
- package/lib/modules/removeOptionalTags.js +220 -0
- package/lib/modules/removeRedundantAttributes.js +82 -67
- package/lib/modules/removeUnusedCss.js +104 -52
- package/lib/modules/sortAttributes.js +120 -0
- package/lib/modules/sortAttributesWithLists.js +143 -0
- package/lib/presets/ampSafe.js +16 -17
- package/lib/presets/max.js +23 -21
- package/lib/presets/safe.js +38 -25
- package/package.json +29 -19
- package/test.js +29 -6
- package/lib/presets/hard.js +0 -26
package/CHANGELOG.md
CHANGED
|
@@ -3,48 +3,95 @@ All notable changes to this project will be documented in this file.
|
|
|
3
3
|
This project adheres to [Semantic Versioning](http://semver.org/).
|
|
4
4
|
|
|
5
5
|
|
|
6
|
+
## [0.2.8] - 2020-11-15
|
|
7
|
+
### Added
|
|
8
|
+
- [`removeOptionalTags`](https://github.com/posthtml/htmlnano#removeoptionaltags) [#110].
|
|
9
|
+
- [`sortAttributes`](https://github.com/posthtml/htmlnano#removeoptionaltags) [#113].
|
|
10
|
+
- `source[src]` and `srcset` support to `minifyUrls` [#117].
|
|
11
|
+
- [`minifyConditionalComments`](https://github.com/posthtml/htmlnano#minifyconditionalcomments) [#119].
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
- Sort by frequency `sortAttributesWithLists` [#111].
|
|
15
|
+
- Strip more spaces in `collapseWhitespace` [#112].
|
|
16
|
+
- Remove `loading="eager"` from `<img>` and `<iframe>` [#114].
|
|
17
|
+
- Remove redundant `type` from `<script>` [#114].
|
|
18
|
+
- Strip whitespaces between textnode and element [#116].
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
## [0.2.7] - 2020-10-17
|
|
23
|
+
### Added
|
|
24
|
+
- More aggressive whitespace removal option [#90].
|
|
25
|
+
- Cloudflare SSE support to `removeComments` [#94].
|
|
26
|
+
- Improve compression ratio by sorting attribute values [#95].
|
|
27
|
+
- New `minifyUrls` module [#98].
|
|
28
|
+
- New `removeAttributeQuotes` module [#104].
|
|
29
|
+
- Remove `type=text/css` for `link[rel=stylesheet]` [#102].
|
|
30
|
+
- Collapse `crossorigin` attributes [#107].
|
|
31
|
+
- Exclude excerpt comment for common CMS [#108].
|
|
32
|
+
|
|
33
|
+
### Fixed
|
|
34
|
+
- Keep JS inside SVG wrapped in `//<![CDATA[ //]]` [#88].
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
## [0.2.6] - 2020-07-15
|
|
38
|
+
### Added
|
|
39
|
+
- Let PostHTML options to be passed.
|
|
40
|
+
|
|
41
|
+
### Fixed
|
|
42
|
+
- `<script>` tags merging without content.
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
## [0.2.5] - 2019-11-09
|
|
46
|
+
### Added
|
|
47
|
+
- Option to remove unused CSS using PurgeCSS [#84].
|
|
48
|
+
|
|
49
|
+
### Fixed
|
|
50
|
+
- Keep the order of inline and external JS [#80].
|
|
51
|
+
|
|
52
|
+
|
|
6
53
|
## [0.2.4] - 2019-07-11
|
|
7
|
-
|
|
54
|
+
### Fixed
|
|
8
55
|
- Remove crossorigin from boolean attribute [#78], [#79].
|
|
9
56
|
- Disable SVGO plugin convertShapeToPath in safe preset [#76].
|
|
10
57
|
|
|
11
58
|
|
|
12
59
|
## [0.2.3] - 2019-02-14
|
|
13
|
-
|
|
60
|
+
### Fixed
|
|
14
61
|
- Keep `<g>` in SVG by default [#71].
|
|
15
62
|
|
|
16
63
|
|
|
17
64
|
## [0.2.2] - 2019-01-03
|
|
18
|
-
|
|
65
|
+
### Added
|
|
19
66
|
- `removeUnusedCss` module [#36].
|
|
20
67
|
|
|
21
|
-
|
|
68
|
+
### Fixed
|
|
22
69
|
- Bug when `tag === false` [#66].
|
|
23
70
|
- Add `crossorigin` to boolean attributes [#67].
|
|
24
71
|
|
|
25
72
|
|
|
26
73
|
## [0.2.1] - 2018-12-01
|
|
27
|
-
|
|
74
|
+
### Fixed
|
|
28
75
|
- Disable JS minifying on AMP pages [#65].
|
|
29
76
|
|
|
30
77
|
## [0.2.0] - 2018-09-14
|
|
31
|
-
|
|
78
|
+
### Breaking changes
|
|
32
79
|
- The API of `minifyCss` module has been changed since `cssnano` has been updated to version 4, which has a different API. Check the following resources for more info:
|
|
33
80
|
* [htmlnano docs](https://github.com/posthtml/htmlnano#minifycss)
|
|
34
81
|
* [cssnano docs](https://cssnano.co/guides/presets)
|
|
35
82
|
* Diff of commit [979f2c](https://github.com/posthtml/htmlnano/commit/979f2c821892c9e979e8b85f74ed0394330fceaf) with the changes of related docs.
|
|
36
83
|
|
|
37
|
-
|
|
84
|
+
### Added
|
|
38
85
|
- Add presets [#64].
|
|
39
86
|
- Add `collapseAttributeWhitespace` module for collapsing spaces in list-like attributes [#25].
|
|
40
87
|
- Add `deduplicateAttributeValues` module for de-duplicating values in list-like attributes [#39].
|
|
41
88
|
- Better support for AMP pages [#59].
|
|
42
89
|
- Collapse whitespaces between top-level tags [#24].
|
|
43
90
|
|
|
44
|
-
|
|
91
|
+
### Changed
|
|
45
92
|
- Improve whitespace normalization using `normalize-html-whitespace` [#21].
|
|
46
93
|
|
|
47
|
-
|
|
94
|
+
### Fixed
|
|
48
95
|
- Don't collapse `visible="false"` attributes in A-Frame pages [#62].
|
|
49
96
|
|
|
50
97
|
|
|
@@ -121,7 +168,10 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|
|
121
168
|
- Remove attributes that contains only white spaces.
|
|
122
169
|
|
|
123
170
|
|
|
124
|
-
|
|
171
|
+
[0.2.8]: https://github.com/posthtml/htmlnano/compare/0.2.7...0.2.8
|
|
172
|
+
[0.2.7]: https://github.com/posthtml/htmlnano/compare/0.2.6...0.2.7
|
|
173
|
+
[0.2.6]: https://github.com/posthtml/htmlnano/compare/0.2.5...0.2.6
|
|
174
|
+
[0.2.5]: https://github.com/posthtml/htmlnano/compare/0.2.4...0.2.5
|
|
125
175
|
[0.2.4]: https://github.com/posthtml/htmlnano/compare/0.2.3...0.2.4
|
|
126
176
|
[0.2.3]: https://github.com/posthtml/htmlnano/compare/0.2.2...0.2.3
|
|
127
177
|
[0.2.2]: https://github.com/posthtml/htmlnano/compare/0.2.1...0.2.2
|
|
@@ -139,6 +189,25 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|
|
139
189
|
[0.1.1]: https://github.com/posthtml/htmlnano/compare/0.1.0...0.1.1
|
|
140
190
|
|
|
141
191
|
|
|
192
|
+
[#119]: https://github.com/posthtml/htmlnano/issues/119
|
|
193
|
+
[#117]: https://github.com/posthtml/htmlnano/issues/117
|
|
194
|
+
[#116]: https://github.com/posthtml/htmlnano/issues/116
|
|
195
|
+
[#114]: https://github.com/posthtml/htmlnano/issues/114
|
|
196
|
+
[#113]: https://github.com/posthtml/htmlnano/issues/113
|
|
197
|
+
[#112]: https://github.com/posthtml/htmlnano/issues/112
|
|
198
|
+
[#111]: https://github.com/posthtml/htmlnano/issues/111
|
|
199
|
+
[#110]: https://github.com/posthtml/htmlnano/issues/110
|
|
200
|
+
[#107]: https://github.com/posthtml/htmlnano/issues/107
|
|
201
|
+
[#108]: https://github.com/posthtml/htmlnano/issues/108
|
|
202
|
+
[#102]: https://github.com/posthtml/htmlnano/issues/102
|
|
203
|
+
[#104]: https://github.com/posthtml/htmlnano/issues/104
|
|
204
|
+
[#98]: https://github.com/posthtml/htmlnano/issues/98
|
|
205
|
+
[#95]: https://github.com/posthtml/htmlnano/issues/95
|
|
206
|
+
[#94]: https://github.com/posthtml/htmlnano/issues/94
|
|
207
|
+
[#90]: https://github.com/posthtml/htmlnano/issues/90
|
|
208
|
+
[#88]: https://github.com/posthtml/htmlnano/issues/88
|
|
209
|
+
[#84]: https://github.com/posthtml/htmlnano/issues/84
|
|
210
|
+
[#80]: https://github.com/posthtml/htmlnano/issues/80
|
|
142
211
|
[#79]: https://github.com/posthtml/htmlnano/issues/79
|
|
143
212
|
[#78]: https://github.com/posthtml/htmlnano/issues/78
|
|
144
213
|
[#76]: https://github.com/posthtml/htmlnano/issues/76
|
package/README.md
CHANGED
|
@@ -8,16 +8,16 @@ Modular HTML minifier, built on top of the [PostHTML](https://github.com/posthtm
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
## [Benchmark](https://github.com/maltsev/html-minifiers-benchmark/blob/master/README.md)
|
|
11
|
-
[html-minifier@
|
|
12
|
-
[htmlnano@0.2.
|
|
11
|
+
[html-minifier@4.0.0]: https://www.npmjs.com/package/html-minifier
|
|
12
|
+
[htmlnano@0.2.6]: https://www.npmjs.com/package/htmlnano
|
|
13
13
|
|
|
14
|
-
| Website | Source (KB) | [html-minifier@
|
|
14
|
+
| Website | Source (KB) | [html-minifier@4.0.0] | [htmlnano@0.2.6] |
|
|
15
15
|
|---------|------------:|----------------:|-----------:|
|
|
16
|
-
| [stackoverflow.
|
|
17
|
-
| [github.com](
|
|
18
|
-
| [en.wikipedia.org](https://en.wikipedia.org/wiki/Main_Page) |
|
|
19
|
-
| [npmjs.com](https://www.npmjs.com/features) |
|
|
20
|
-
| **Avg. minify rate** | 0% | **
|
|
16
|
+
| [stackoverflow.blog](https://stackoverflow.blog/) | 76 | 67 | 66 |
|
|
17
|
+
| [github.com](https://github.com/) | 131 | 70 | 117 |
|
|
18
|
+
| [en.wikipedia.org](https://en.wikipedia.org/wiki/Main_Page) | 80 | 71 | 76 |
|
|
19
|
+
| [npmjs.com](https://www.npmjs.com/features) | 31 | 25 | 28 |
|
|
20
|
+
| **Avg. minify rate** | 0% | **22%** | **10%** |
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
## Usage
|
|
@@ -49,10 +49,17 @@ const options = {
|
|
|
49
49
|
removeEmptyAttributes: false, // Disable the module "removeEmptyAttributes"
|
|
50
50
|
collapseWhitespace: 'conservative' // Pass options to the module "collapseWhitespace"
|
|
51
51
|
};
|
|
52
|
+
// posthtml, posthtml-render, and posthtml-parse options
|
|
53
|
+
const postHtmlOptions = {
|
|
54
|
+
sync: true, // https://github.com/posthtml/posthtml#usage
|
|
55
|
+
lowerCaseTags: true, // https://github.com/posthtml/posthtml-parser#options
|
|
56
|
+
quoteAllAttributes: false, // https://github.com/posthtml/posthtml-render#options
|
|
57
|
+
};
|
|
52
58
|
|
|
53
59
|
htmlnano
|
|
54
60
|
// "preset" arg might be skipped (see "Presets" section below for more info)
|
|
55
|
-
|
|
61
|
+
// "postHtmlOptions" arg might be skipped
|
|
62
|
+
.process(html, options, preset, postHtmlOptions)
|
|
56
63
|
.then(function (result) {
|
|
57
64
|
// result.html is minified
|
|
58
65
|
})
|
|
@@ -76,9 +83,12 @@ const posthtmlPlugins = [
|
|
|
76
83
|
require('htmlnano')(options)
|
|
77
84
|
];
|
|
78
85
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
86
|
+
const postHtmlOptions = {
|
|
87
|
+
// See PostHTML docs
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
posthtml(posthtmlPlugins)
|
|
91
|
+
.process(html, posthtmlOptions)
|
|
82
92
|
.then(function (result) {
|
|
83
93
|
// result.html is minified
|
|
84
94
|
})
|
|
@@ -192,29 +202,39 @@ Collapses redundant white spaces (including new lines). It doesn’t affect whit
|
|
|
192
202
|
|
|
193
203
|
##### Options
|
|
194
204
|
- `conservative` — collapses all redundant white spaces to 1 space (default)
|
|
205
|
+
- `aggressive` — collapses all whitespaces that are redundant and safe to remove
|
|
195
206
|
- `all` — collapses all redundant white spaces
|
|
196
207
|
|
|
197
208
|
##### Side effects
|
|
198
|
-
|
|
199
|
-
|
|
209
|
+
|
|
210
|
+
*all*
|
|
211
|
+
`<i>hello</i> <i>world</i>` or `<i>hello</i><br><i>world</i>` after minification will be rendered as `helloworld`.
|
|
212
|
+
To prevent that use either the default `conservative` option, or the `aggressive` option.
|
|
200
213
|
|
|
201
214
|
##### Example
|
|
202
215
|
Source:
|
|
203
216
|
```html
|
|
204
217
|
<div>
|
|
205
218
|
hello world!
|
|
219
|
+
\t<a href="#">answer</a>
|
|
206
220
|
<style>div { color: red; } </style>
|
|
221
|
+
\t\t<main></main>
|
|
207
222
|
</div>
|
|
208
223
|
```
|
|
209
224
|
|
|
210
225
|
Minified (with `all`):
|
|
211
226
|
```html
|
|
212
|
-
<div>hello world!<style>div { color: red; } </style></div>
|
|
227
|
+
<div>hello world!<a href="#">answer</a><style>div { color: red; } </style><main></main></div>
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Minified (with `aggressive`):
|
|
231
|
+
```html
|
|
232
|
+
<div> hello world! <a href="#">answer</a> <style>div { color: red; } </style><main></main></div>
|
|
213
233
|
```
|
|
214
234
|
|
|
215
235
|
Minified (with `conservative`):
|
|
216
236
|
```html
|
|
217
|
-
<div> hello world! <style>div { color: red; } </style> </div>
|
|
237
|
+
<div> hello world! <a href="#">answer</a> <style>div { color: red; } </style> <main></main> </div>
|
|
218
238
|
```
|
|
219
239
|
|
|
220
240
|
|
|
@@ -272,8 +292,43 @@ Minified:
|
|
|
272
292
|
<img src="foo.jpg" alt="">
|
|
273
293
|
```
|
|
274
294
|
|
|
295
|
+
### removeAttributeQuotes
|
|
296
|
+
Remove quotes around attributes when possible, see [HTML Standard - 12.1.2.3 Attributes - Unquoted attribute value syntax](https://html.spec.whatwg.org/multipage/syntax.html#attributes-2).
|
|
297
|
+
|
|
298
|
+
##### Example
|
|
299
|
+
Source:
|
|
300
|
+
```html
|
|
301
|
+
<div class="foo" title="hello world"></div>
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
Minified:
|
|
305
|
+
```html
|
|
306
|
+
<div class=foo title="hello world"></div>
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
##### Notice
|
|
310
|
+
The feature is implemented by [posthtml-render's `quoteAllAttributes`](https://github.com/posthtml/posthtml-render#options), which is one of the PostHTML's option. So `removeAttributeQuotes` could be overriden by other PostHTML's plugins and PostHTML's configuration.
|
|
311
|
+
|
|
312
|
+
For example:
|
|
313
|
+
|
|
314
|
+
```js
|
|
315
|
+
posthtml([
|
|
316
|
+
htmlnano({
|
|
317
|
+
removeAttributeQuotes: true
|
|
318
|
+
})
|
|
319
|
+
]).process(html, {
|
|
320
|
+
quoteAllAttributes: true
|
|
321
|
+
})
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
`removeAttributeQuotes` will not work because PostHTML's `quoteAllAttributes` takes the priority.
|
|
325
|
+
|
|
275
326
|
### removeUnusedCss
|
|
276
|
-
|
|
327
|
+
|
|
328
|
+
Removes unused CSS inside `<style>` tags with either [uncss](https://github.com/uncss/uncss)
|
|
329
|
+
or [PurgeCSS](https://github.com/FullHuman/purgecss).
|
|
330
|
+
|
|
331
|
+
#### With uncss
|
|
277
332
|
|
|
278
333
|
##### Options
|
|
279
334
|
See [the documentation of uncss](https://github.com/uncss/uncss) for all supported options.
|
|
@@ -293,6 +348,30 @@ The following uncss options are ignored if passed to the module:
|
|
|
293
348
|
- `ignoreSheets`
|
|
294
349
|
- `raw`
|
|
295
350
|
|
|
351
|
+
#### With PurgeCSS
|
|
352
|
+
|
|
353
|
+
Use PurgeCSS instead of uncss by adding `tool: 'purgeCSS'` to the options.
|
|
354
|
+
|
|
355
|
+
##### Options
|
|
356
|
+
|
|
357
|
+
See [the documentation of PurgeCSS](https://www.purgecss.com) for all supported options.
|
|
358
|
+
|
|
359
|
+
PurgeCSS options can be passed directly to the `removeUnusedCss` module:
|
|
360
|
+
```js
|
|
361
|
+
htmlnano.process(html, {
|
|
362
|
+
removeUnusedCss: {
|
|
363
|
+
tool: 'purgeCSS',
|
|
364
|
+
whitelist: ['.do-not-remove']
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
The following PurgeCSS options are ignored if passed to the module:
|
|
370
|
+
|
|
371
|
+
- `content`
|
|
372
|
+
- `css`
|
|
373
|
+
- `extractors`
|
|
374
|
+
|
|
296
375
|
##### Example
|
|
297
376
|
Source:
|
|
298
377
|
```html
|
|
@@ -450,6 +529,49 @@ Minified:
|
|
|
450
529
|
<svg baseProfile="full" width="300" height="200" xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" fill="red"/><circle cx="150" cy="100" r="80" fill="green"/><text x="150" y="125" font-size="60" text-anchor="middle" fill="#fff">SVG</text></svg>
|
|
451
530
|
```
|
|
452
531
|
|
|
532
|
+
### minifyConditionalComments
|
|
533
|
+
|
|
534
|
+
Minify content inside conditional comments.
|
|
535
|
+
|
|
536
|
+
##### Example
|
|
537
|
+
|
|
538
|
+
Source:
|
|
539
|
+
|
|
540
|
+
```html
|
|
541
|
+
<!--[if lte IE 7]>
|
|
542
|
+
<style type="text/css">
|
|
543
|
+
.title {
|
|
544
|
+
color: red;
|
|
545
|
+
}
|
|
546
|
+
</style>
|
|
547
|
+
<![endif]-->
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
Minified:
|
|
551
|
+
|
|
552
|
+
```html
|
|
553
|
+
<!--[if lte IE 7]><style>.title {color:red}</style><![endif]-->
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
##### Notice
|
|
557
|
+
|
|
558
|
+
Due to [the limitation of PostHTML](https://github.com/posthtml/posthtml-parser/issues/9) (which is actually a issue from upstream [htmlparser2](https://github.com/fb55/htmlparser2/pull/146)), following html snippet is not supported:
|
|
559
|
+
|
|
560
|
+
```html
|
|
561
|
+
<!--[if lt IE 7]><html class="no-js ie6"><![endif]-->
|
|
562
|
+
<!--[if IE 7]><html class="no-js ie7"><![endif]-->
|
|
563
|
+
<!--[if IE 8]><html class="no-js ie8"><![endif]-->
|
|
564
|
+
<!--[if gt IE 8]><!--><html class="no-js"><!--<![endif]-->
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
Which will result in:
|
|
568
|
+
|
|
569
|
+
```html
|
|
570
|
+
<!--[if lt IE 7]><html class="no-js ie6"></html><![endif]-->
|
|
571
|
+
<!--[if IE 7]><html class="no-js ie7"></html><![endif]-->
|
|
572
|
+
<!--[if IE 8]><html class="no-js ie8"></html><![endif]-->
|
|
573
|
+
<!--[if gt IE 8]><!--><html class="no-js"></html><!--<![endif]-->
|
|
574
|
+
```
|
|
453
575
|
|
|
454
576
|
### removeRedundantAttributes
|
|
455
577
|
Removes redundant attributes from tags if they contain default values:
|
|
@@ -459,6 +581,7 @@ Removes redundant attributes from tags if they contain default values:
|
|
|
459
581
|
- `language="javascript"` and `type="text/javascript"` from `<script>`
|
|
460
582
|
- `charset` from `<script>` if it's an external script
|
|
461
583
|
- `media="all"` from `<style>` and `<link>`
|
|
584
|
+
- `type="text/css"` from `<link rel="stylesheet">`
|
|
462
585
|
|
|
463
586
|
##### Options
|
|
464
587
|
This module is disabled by default, change option to true to enable this module.
|
|
@@ -600,13 +723,190 @@ const options = {
|
|
|
600
723
|
|
|
601
724
|
`options` is an object with all options that were passed to the plugin.
|
|
602
725
|
|
|
726
|
+
### sortAttributesWithLists
|
|
727
|
+
Sort values in list-like attributes (`class`, `rel`, `ping`).
|
|
728
|
+
|
|
729
|
+
The module won't impact the plain-text size of the output. However it will improve the compression ratio of gzip/brotli used in HTTP compression.
|
|
730
|
+
|
|
731
|
+
##### Options
|
|
732
|
+
|
|
733
|
+
- `alphabetical`: Default option. Sort attribute values in alphabetical order.
|
|
734
|
+
- `frequency`: Sort attribute values by frequency.
|
|
735
|
+
|
|
736
|
+
##### Example
|
|
737
|
+
|
|
738
|
+
**alphabetical**
|
|
739
|
+
|
|
740
|
+
Source:
|
|
741
|
+
```html
|
|
742
|
+
<div class="foo baz bar">click</div>
|
|
743
|
+
```
|
|
744
|
+
|
|
745
|
+
Processed:
|
|
746
|
+
```html
|
|
747
|
+
<div class="bar baz foo">click</div>
|
|
748
|
+
```
|
|
749
|
+
|
|
750
|
+
**frequency**
|
|
751
|
+
|
|
752
|
+
Source:
|
|
753
|
+
```html
|
|
754
|
+
<div class="foo baz bar"></div><div class="bar foo"></div>
|
|
755
|
+
```
|
|
756
|
+
|
|
757
|
+
Processed:
|
|
758
|
+
```html
|
|
759
|
+
<div class="foo bar baz"></div><div class="foo bar"></div>
|
|
760
|
+
```
|
|
761
|
+
|
|
762
|
+
### sortAttributes
|
|
763
|
+
Sort attributes inside elements.
|
|
764
|
+
|
|
765
|
+
The module won't impact the plain-text size of the output. However it will improve the compression ratio of gzip/brotli used in HTTP compression.
|
|
766
|
+
|
|
767
|
+
##### Options
|
|
768
|
+
|
|
769
|
+
- `alphabetical`: Default option. Sort attributes in alphabetical order.
|
|
770
|
+
- `frequency`: Sort attributes by frequency.
|
|
771
|
+
|
|
772
|
+
##### Example
|
|
773
|
+
|
|
774
|
+
**alphabetical**
|
|
775
|
+
|
|
776
|
+
Source:
|
|
777
|
+
```html
|
|
778
|
+
<input type="text" class="form-control" name="testInput" autofocus="" autocomplete="off" id="testId">
|
|
779
|
+
```
|
|
780
|
+
|
|
781
|
+
Processed:
|
|
782
|
+
```html
|
|
783
|
+
<input autocomplete="off" autofocus="" class="form-control" id="testId" name="testInput" type="text">
|
|
784
|
+
```
|
|
785
|
+
|
|
786
|
+
**frequency**
|
|
787
|
+
|
|
788
|
+
Source:
|
|
789
|
+
```html
|
|
790
|
+
<input type="text" class="form-control" name="testInput" id="testId">
|
|
791
|
+
<a id="testId" href="#" class="testClass"></a>
|
|
792
|
+
<img width="20" src="../images/image.png" height="40" alt="image" class="cls" id="id2">
|
|
793
|
+
```
|
|
794
|
+
|
|
795
|
+
Processed:
|
|
796
|
+
```html
|
|
797
|
+
<input class="form-control" id="testId" type="text" name="testInput">
|
|
798
|
+
<a class="testClass" id="testId" href="#"></a>
|
|
799
|
+
<img class="cls" id="id2" width="20" src="../images/image.png" height="40" alt="image">
|
|
800
|
+
```
|
|
801
|
+
|
|
802
|
+
### minifyUrls
|
|
803
|
+
Convert absolute URL to relative URL using [relateurl](https://www.npmjs.com/package/relateurl).
|
|
804
|
+
|
|
805
|
+
##### Options
|
|
806
|
+
|
|
807
|
+
The base URL to resolve against. Support `String` & `URL`.
|
|
808
|
+
|
|
809
|
+
```js
|
|
810
|
+
htmlnano.process(html, {
|
|
811
|
+
minifyUrls: 'https://example.com' // Valid configuration
|
|
812
|
+
});
|
|
813
|
+
```
|
|
814
|
+
|
|
815
|
+
```js
|
|
816
|
+
htmlnano.process(html, {
|
|
817
|
+
minifyUrls: new URL('https://example.com') // Valid configuration
|
|
818
|
+
});
|
|
819
|
+
```
|
|
820
|
+
|
|
821
|
+
```js
|
|
822
|
+
htmlnano.process(html, {
|
|
823
|
+
minifyUrls: false // The module will be disabled
|
|
824
|
+
});
|
|
825
|
+
```
|
|
826
|
+
|
|
827
|
+
```js
|
|
828
|
+
htmlnano.process(html, {
|
|
829
|
+
minifyUrls: true // Invalid configuration, the module will be disabled
|
|
830
|
+
});
|
|
831
|
+
```
|
|
832
|
+
|
|
833
|
+
##### Example
|
|
834
|
+
|
|
835
|
+
**Basic Usage**
|
|
836
|
+
|
|
837
|
+
Configuration:
|
|
838
|
+
|
|
839
|
+
```js
|
|
840
|
+
htmlnano.process(html, {
|
|
841
|
+
minifyUrls: 'https://example.com'
|
|
842
|
+
});
|
|
843
|
+
```
|
|
844
|
+
|
|
845
|
+
Source:
|
|
846
|
+
|
|
847
|
+
```html
|
|
848
|
+
<a href="https://example.com/foo/bar/baz">bar</a>
|
|
849
|
+
```
|
|
850
|
+
|
|
851
|
+
Minified:
|
|
852
|
+
|
|
853
|
+
```html
|
|
854
|
+
<a href="foo/bar/baz">bar</a>
|
|
855
|
+
```
|
|
856
|
+
|
|
857
|
+
**With sub-directory**
|
|
858
|
+
|
|
859
|
+
Configuration:
|
|
860
|
+
|
|
861
|
+
```js
|
|
862
|
+
htmlnano.process(html, {
|
|
863
|
+
minifyUrls: 'https://example.com/foo/baz/'
|
|
864
|
+
});
|
|
865
|
+
```
|
|
866
|
+
|
|
867
|
+
Source:
|
|
868
|
+
|
|
869
|
+
```html
|
|
870
|
+
<a href="https://example.com/foo/bar">bar</a>
|
|
871
|
+
```
|
|
872
|
+
|
|
873
|
+
Minified:
|
|
874
|
+
|
|
875
|
+
```html
|
|
876
|
+
<a href="../bar">bar</a>
|
|
877
|
+
```
|
|
878
|
+
|
|
879
|
+
## removeOptionalTags
|
|
880
|
+
Remove certain tags that can be omitted, see [HTML Standard - 13.1.2.4 Optional tags](https://html.spec.whatwg.org/multipage/syntax.html#optional-tags).
|
|
881
|
+
|
|
882
|
+
##### Example
|
|
883
|
+
|
|
884
|
+
Source:
|
|
885
|
+
|
|
886
|
+
```html
|
|
887
|
+
<html><head><title>Title</title></head><body><p>Hi</p></body></html>
|
|
888
|
+
```
|
|
889
|
+
|
|
890
|
+
Minified:
|
|
891
|
+
|
|
892
|
+
```html
|
|
893
|
+
<title>Title</title><p>Hi</p>
|
|
894
|
+
```
|
|
895
|
+
##### Notice
|
|
896
|
+
Due to [the limitation of PostHTML](https://github.com/posthtml/htmlnano/issues/99), htmlnano can't remove only the start tag or the end tag of an element. Currently, htmlnano only supports removing the following optional tags, as htmlnano can remove their start tag and end tag at the same time:
|
|
897
|
+
|
|
898
|
+
- `html`
|
|
899
|
+
- `head`
|
|
900
|
+
- `body`
|
|
901
|
+
- `colgroup`
|
|
902
|
+
- `tbody`
|
|
603
903
|
|
|
604
904
|
## Contribute
|
|
605
905
|
Since the minifier is modular, it's very easy to add new modules:
|
|
606
906
|
|
|
607
907
|
1. Create a ES6-file inside `lib/modules/` with a function that does some minification. For example you can check [`lib/modules/example.es6`](https://github.com/posthtml/htmlnano/blob/master/lib/modules/example.es6).
|
|
608
908
|
|
|
609
|
-
2. Add the module
|
|
909
|
+
2. Add the module's name into one of those [presets](https://github.com/posthtml/htmlnano/tree/master/lib/presets). You can choose either `ampSafe`, `max`, or `safe`.
|
|
610
910
|
|
|
611
911
|
3. Create a JS-file inside `test/modules/` with some unit-tests.
|
|
612
912
|
|
package/lib/helpers.js
CHANGED
|
@@ -1,61 +1,41 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
|
|
4
|
+
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.isAmpBoilerplate = isAmpBoilerplate;
|
|
7
7
|
exports.isComment = isComment;
|
|
8
8
|
exports.isConditionalComment = isConditionalComment;
|
|
9
9
|
exports.isStyleNode = isStyleNode;
|
|
10
10
|
exports.extractCssFromStyleNode = extractCssFromStyleNode;
|
|
11
|
-
|
|
11
|
+
const ampBoilerplateAttributes = ['amp-boilerplate', 'amp4ads-boilerplate', 'amp4email-boilerplate'];
|
|
12
12
|
|
|
13
13
|
function isAmpBoilerplate(node) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
try {
|
|
22
|
-
for (var _iterator = ampBoilerplateAttributes[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
|
23
|
-
var attr = _step.value;
|
|
24
|
-
|
|
25
|
-
if (attr in node.attrs) {
|
|
26
|
-
return true;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
} catch (err) {
|
|
30
|
-
_didIteratorError = true;
|
|
31
|
-
_iteratorError = err;
|
|
32
|
-
} finally {
|
|
33
|
-
try {
|
|
34
|
-
if (!_iteratorNormalCompletion && _iterator.return) {
|
|
35
|
-
_iterator.return();
|
|
36
|
-
}
|
|
37
|
-
} finally {
|
|
38
|
-
if (_didIteratorError) {
|
|
39
|
-
throw _iteratorError;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
14
|
+
if (!node.attrs) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
for (const attr of ampBoilerplateAttributes) {
|
|
19
|
+
if (attr in node.attrs) {
|
|
20
|
+
return true;
|
|
42
21
|
}
|
|
22
|
+
}
|
|
43
23
|
|
|
44
|
-
|
|
24
|
+
return false;
|
|
45
25
|
}
|
|
46
26
|
|
|
47
27
|
function isComment(content) {
|
|
48
|
-
|
|
28
|
+
return (content || '').trim().search('<!--') === 0;
|
|
49
29
|
}
|
|
50
30
|
|
|
51
31
|
function isConditionalComment(content) {
|
|
52
|
-
|
|
32
|
+
return (content || '').trim().search(/<!--\[if/) === 0;
|
|
53
33
|
}
|
|
54
34
|
|
|
55
35
|
function isStyleNode(node) {
|
|
56
|
-
|
|
36
|
+
return node.tag === 'style' && !isAmpBoilerplate(node) && 'content' in node && node.content.length > 0;
|
|
57
37
|
}
|
|
58
38
|
|
|
59
39
|
function extractCssFromStyleNode(node) {
|
|
60
|
-
|
|
40
|
+
return Array.isArray(node.content) ? node.content.join(' ') : node.content;
|
|
61
41
|
}
|