htmlnano 0.2.0 → 0.2.4
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/.eslintignore +1 -0
- package/CHANGELOG.md +36 -0
- package/README.md +80 -13
- package/lib/helpers.js +10 -0
- package/lib/htmlnano.js +19 -18
- package/lib/modules/collapseBooleanAttributes.js +4 -0
- package/lib/modules/mergeScripts.js +19 -19
- package/lib/modules/minifyCss.js +2 -6
- package/lib/modules/removeUnusedCss.js +75 -0
- package/lib/presets/ampSafe.js +2 -1
- package/lib/presets/max.js +6 -1
- package/lib/presets/safe.js +4 -1
- package/package.json +23 -15
- package/test.js +6 -28
- package/test.html +0 -14
package/.eslintignore
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,30 @@ 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.4] - 2019-07-11
|
|
7
|
+
## Fixed
|
|
8
|
+
- Remove crossorigin from boolean attribute [#78], [#79].
|
|
9
|
+
- Disable SVGO plugin convertShapeToPath in safe preset [#76].
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
## [0.2.3] - 2019-02-14
|
|
13
|
+
## Fixed
|
|
14
|
+
- Keep `<g>` in SVG by default [#71].
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
## [0.2.2] - 2019-01-03
|
|
18
|
+
## Added
|
|
19
|
+
- `removeUnusedCss` module [#36].
|
|
20
|
+
|
|
21
|
+
## Fixed
|
|
22
|
+
- Bug when `tag === false` [#66].
|
|
23
|
+
- Add `crossorigin` to boolean attributes [#67].
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
## [0.2.1] - 2018-12-01
|
|
27
|
+
## Fixed
|
|
28
|
+
- Disable JS minifying on AMP pages [#65].
|
|
29
|
+
|
|
6
30
|
## [0.2.0] - 2018-09-14
|
|
7
31
|
## Breaking changes
|
|
8
32
|
- 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:
|
|
@@ -98,6 +122,10 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|
|
98
122
|
|
|
99
123
|
|
|
100
124
|
|
|
125
|
+
[0.2.4]: https://github.com/posthtml/htmlnano/compare/0.2.3...0.2.4
|
|
126
|
+
[0.2.3]: https://github.com/posthtml/htmlnano/compare/0.2.2...0.2.3
|
|
127
|
+
[0.2.2]: https://github.com/posthtml/htmlnano/compare/0.2.1...0.2.2
|
|
128
|
+
[0.2.1]: https://github.com/posthtml/htmlnano/compare/0.2.0...0.2.1
|
|
101
129
|
[0.2.0]: https://github.com/posthtml/htmlnano/compare/0.1.10...0.2.0
|
|
102
130
|
[0.1.10]: https://github.com/posthtml/htmlnano/compare/0.1.9...0.1.10
|
|
103
131
|
[0.1.9]: https://github.com/posthtml/htmlnano/compare/0.1.8...0.1.9
|
|
@@ -111,6 +139,13 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|
|
111
139
|
[0.1.1]: https://github.com/posthtml/htmlnano/compare/0.1.0...0.1.1
|
|
112
140
|
|
|
113
141
|
|
|
142
|
+
[#79]: https://github.com/posthtml/htmlnano/issues/79
|
|
143
|
+
[#78]: https://github.com/posthtml/htmlnano/issues/78
|
|
144
|
+
[#76]: https://github.com/posthtml/htmlnano/issues/76
|
|
145
|
+
[#71]: https://github.com/posthtml/htmlnano/issues/71
|
|
146
|
+
[#67]: https://github.com/posthtml/htmlnano/issues/67
|
|
147
|
+
[#66]: https://github.com/posthtml/htmlnano/issues/66
|
|
148
|
+
[#65]: https://github.com/posthtml/htmlnano/issues/65
|
|
114
149
|
[#64]: https://github.com/posthtml/htmlnano/issues/64
|
|
115
150
|
[#62]: https://github.com/posthtml/htmlnano/issues/62
|
|
116
151
|
[#59]: https://github.com/posthtml/htmlnano/issues/59
|
|
@@ -120,6 +155,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|
|
120
155
|
[#47]: https://github.com/posthtml/htmlnano/issues/47
|
|
121
156
|
[#42]: https://github.com/posthtml/htmlnano/issues/42
|
|
122
157
|
[#39]: https://github.com/posthtml/htmlnano/issues/39
|
|
158
|
+
[#36]: https://github.com/posthtml/htmlnano/issues/36
|
|
123
159
|
[#31]: https://github.com/posthtml/htmlnano/issues/31
|
|
124
160
|
[#30]: https://github.com/posthtml/htmlnano/issues/30
|
|
125
161
|
[#28]: https://github.com/posthtml/htmlnano/issues/28
|
package/README.md
CHANGED
|
@@ -4,20 +4,20 @@
|
|
|
4
4
|
|
|
5
5
|
Modular HTML minifier, built on top of the [PostHTML](https://github.com/posthtml/posthtml). Inspired by [cssnano](http://cssnano.co/).
|
|
6
6
|
|
|
7
|
+
> The author of htmlnano is available for hire as a full stack web developer: https://kirillmaltsev.net/services
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
## [Benchmark](https://github.com/maltsev/html-minifiers-benchmark/blob/master/README.md)
|
|
10
|
-
[html-minifier]: https://www.npmjs.com/package/html-minifier
|
|
11
|
-
[htmlnano]: https://www.npmjs.com/package/htmlnano
|
|
11
|
+
[html-minifier@3.5.20]: https://www.npmjs.com/package/html-minifier
|
|
12
|
+
[htmlnano@0.2.0]: https://www.npmjs.com/package/htmlnano
|
|
12
13
|
|
|
13
|
-
| Website | Source (KB) | [html-minifier] | [htmlnano] |
|
|
14
|
+
| Website | Source (KB) | [html-minifier@3.5.20] | [htmlnano@0.2.0] |
|
|
14
15
|
|---------|------------:|----------------:|-----------:|
|
|
15
|
-
| [stackoverflow.com](http://stackoverflow.com/) |
|
|
16
|
-
| [github.com](http://github.com/) |
|
|
17
|
-
| [en.wikipedia.org](https://en.wikipedia.org/wiki/Main_Page) |
|
|
18
|
-
| [npmjs.com](https://www.npmjs.com/features) |
|
|
19
|
-
| **Avg. minify rate** | 0% | **
|
|
20
|
-
|
|
16
|
+
| [stackoverflow.com](http://stackoverflow.com/) | 258 | 205 | 218 |
|
|
17
|
+
| [github.com](http://github.com/) | 63 | 51 | 56 |
|
|
18
|
+
| [en.wikipedia.org](https://en.wikipedia.org/wiki/Main_Page) | 77 | 69 | 74 |
|
|
19
|
+
| [npmjs.com](https://www.npmjs.com/features) | 32 | 29 | 30 |
|
|
20
|
+
| **Avg. minify rate** | 0% | **15%** | **9%** |
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
## Usage
|
|
@@ -272,6 +272,53 @@ Minified:
|
|
|
272
272
|
<img src="foo.jpg" alt="">
|
|
273
273
|
```
|
|
274
274
|
|
|
275
|
+
### removeUnusedCss
|
|
276
|
+
Removes unused CSS with [uncss](https://github.com/uncss/uncss) inside `<style>` tags.
|
|
277
|
+
|
|
278
|
+
##### Options
|
|
279
|
+
See [the documentation of uncss](https://github.com/uncss/uncss) for all supported options.
|
|
280
|
+
|
|
281
|
+
uncss options can be passed directly to the `removeUnusedCss` module:
|
|
282
|
+
```js
|
|
283
|
+
htmlnano.process(html, {
|
|
284
|
+
removeUnusedCss: {
|
|
285
|
+
ignore: ['.do-not-remove']
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
The following uncss options are ignored if passed to the module:
|
|
291
|
+
|
|
292
|
+
- `stylesheets`
|
|
293
|
+
- `ignoreSheets`
|
|
294
|
+
- `raw`
|
|
295
|
+
|
|
296
|
+
##### Example
|
|
297
|
+
Source:
|
|
298
|
+
```html
|
|
299
|
+
<div class="b">
|
|
300
|
+
<style>
|
|
301
|
+
.a {
|
|
302
|
+
margin: 10px 10px 10px 10px;
|
|
303
|
+
}
|
|
304
|
+
.b {
|
|
305
|
+
color: #ff0000;
|
|
306
|
+
}
|
|
307
|
+
</style>
|
|
308
|
+
</div>
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Optimized:
|
|
312
|
+
```html
|
|
313
|
+
<div class="b">
|
|
314
|
+
<style>
|
|
315
|
+
.b {
|
|
316
|
+
color: #ff0000;
|
|
317
|
+
}
|
|
318
|
+
</style>
|
|
319
|
+
</div>
|
|
320
|
+
```
|
|
321
|
+
|
|
275
322
|
|
|
276
323
|
### minifyCss
|
|
277
324
|
Minifies CSS with [cssnano](http://cssnano.co/) inside `<style>` tags and `style` attributes.
|
|
@@ -315,10 +362,20 @@ Minified:
|
|
|
315
362
|
|
|
316
363
|
|
|
317
364
|
### minifyJs
|
|
318
|
-
Minifies JS
|
|
365
|
+
Minifies JS using [Terser](https://github.com/fabiosantoscode/terser) inside `<script>` tags.
|
|
319
366
|
|
|
320
367
|
##### Options
|
|
321
|
-
See [the
|
|
368
|
+
See [the documentation of Terser](https://github.com/fabiosantoscode/terser#api-reference) for all supported options.
|
|
369
|
+
Terser options can be passed directly to the `minifyJs` module:
|
|
370
|
+
```js
|
|
371
|
+
htmlnano.process(html, {
|
|
372
|
+
minifyJs: {
|
|
373
|
+
output: { quote_style: 1 },
|
|
374
|
+
},
|
|
375
|
+
});
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
|
|
322
379
|
|
|
323
380
|
##### Example
|
|
324
381
|
Source:
|
|
@@ -361,10 +418,20 @@ Minified:
|
|
|
361
418
|
|
|
362
419
|
|
|
363
420
|
### minifySvg
|
|
364
|
-
Minifies SVG inside `<svg>` tags
|
|
421
|
+
Minifies SVG inside `<svg>` tags using [SVGO](https://github.com/svg/svgo/).
|
|
365
422
|
|
|
366
423
|
##### Options
|
|
367
|
-
See [the documentation of SVGO](https://github.com/svg/svgo/blob/master/README.md)
|
|
424
|
+
See [the documentation of SVGO](https://github.com/svg/svgo/blob/master/README.md) for all supported options.
|
|
425
|
+
SVGO options can be passed directly to the `minifySvg` module:
|
|
426
|
+
```js
|
|
427
|
+
htmlnano.process(html, {
|
|
428
|
+
minifySvg: {
|
|
429
|
+
plugins: [
|
|
430
|
+
{ collapseGroups: false },
|
|
431
|
+
],
|
|
432
|
+
},
|
|
433
|
+
});
|
|
434
|
+
```
|
|
368
435
|
|
|
369
436
|
##### Example
|
|
370
437
|
Source:
|
package/lib/helpers.js
CHANGED
|
@@ -6,6 +6,8 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.isAmpBoilerplate = isAmpBoilerplate;
|
|
7
7
|
exports.isComment = isComment;
|
|
8
8
|
exports.isConditionalComment = isConditionalComment;
|
|
9
|
+
exports.isStyleNode = isStyleNode;
|
|
10
|
+
exports.extractCssFromStyleNode = extractCssFromStyleNode;
|
|
9
11
|
var ampBoilerplateAttributes = ['amp-boilerplate', 'amp4ads-boilerplate', 'amp4email-boilerplate'];
|
|
10
12
|
|
|
11
13
|
function isAmpBoilerplate(node) {
|
|
@@ -48,4 +50,12 @@ function isComment(content) {
|
|
|
48
50
|
|
|
49
51
|
function isConditionalComment(content) {
|
|
50
52
|
return (content || '').trim().search(/<!--\[if/) === 0;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function isStyleNode(node) {
|
|
56
|
+
return node.tag === 'style' && !isAmpBoilerplate(node) && 'content' in node && node.content.length > 0;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function extractCssFromStyleNode(node) {
|
|
60
|
+
return Array.isArray(node.content) ? node.content.join(' ') : node.content;
|
|
51
61
|
}
|
package/lib/htmlnano.js
CHANGED
|
@@ -33,31 +33,32 @@ function htmlnano() {
|
|
|
33
33
|
return function minifier(tree) {
|
|
34
34
|
options = (0, _objectAssign2.default)({}, preset, options);
|
|
35
35
|
var promise = Promise.resolve(tree);
|
|
36
|
+
|
|
37
|
+
var _loop = function _loop(moduleName) {
|
|
38
|
+
if (!options[moduleName]) {
|
|
39
|
+
// The module is disabled
|
|
40
|
+
return 'continue';
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (_safe2.default[moduleName] === undefined) {
|
|
44
|
+
throw new Error('Module "' + moduleName + '" is not defined');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
var module = require('./modules/' + moduleName);
|
|
48
|
+
promise = promise.then(function (tree) {
|
|
49
|
+
return module.default(tree, options, options[moduleName]);
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
|
|
36
53
|
var _iteratorNormalCompletion = true;
|
|
37
54
|
var _didIteratorError = false;
|
|
38
55
|
var _iteratorError = undefined;
|
|
39
56
|
|
|
40
57
|
try {
|
|
41
|
-
var
|
|
58
|
+
for (var _iterator = Object.keys(options)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
|
42
59
|
var moduleName = _step.value;
|
|
43
60
|
|
|
44
|
-
|
|
45
|
-
// The module is disabled
|
|
46
|
-
return 'continue';
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (_safe2.default[moduleName] === undefined) {
|
|
50
|
-
throw new Error('Module "' + moduleName + '" is not defined');
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
var module = require('./modules/' + moduleName);
|
|
54
|
-
promise = promise.then(function (tree) {
|
|
55
|
-
return module.default(tree, options, options[moduleName]);
|
|
56
|
-
});
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
for (var _iterator = Object.keys(options)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
|
60
|
-
var _ret = _loop();
|
|
61
|
+
var _ret = _loop(moduleName);
|
|
61
62
|
|
|
62
63
|
if (_ret === 'continue') continue;
|
|
63
64
|
}
|
|
@@ -19,6 +19,10 @@ function collapseBooleanAttributes(tree, options, moduleOptions) {
|
|
|
19
19
|
for (var _iterator = Object.keys(node.attrs)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
|
20
20
|
var attrName = _step.value;
|
|
21
21
|
|
|
22
|
+
if (!node.tag) {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
|
|
22
26
|
if (node.tag.search('a-') === 0 && attrName === 'visible') {
|
|
23
27
|
continue;
|
|
24
28
|
}
|
|
@@ -34,32 +34,32 @@ function mergeScripts(tree) {
|
|
|
34
34
|
return node;
|
|
35
35
|
});
|
|
36
36
|
|
|
37
|
+
var _loop = function _loop(scriptKey) {
|
|
38
|
+
var scriptNodes = scriptNodesIndex[scriptKey];
|
|
39
|
+
var lastScriptNode = scriptNodes.pop();
|
|
40
|
+
scriptNodes.reverse().forEach(function (scriptNode) {
|
|
41
|
+
var scriptContent = (scriptNode.content || []).join(' ');
|
|
42
|
+
scriptContent = scriptContent.trim();
|
|
43
|
+
if (scriptContent.slice(-1) !== ';') {
|
|
44
|
+
scriptContent += ';';
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
lastScriptNode.content.unshift(scriptContent);
|
|
48
|
+
|
|
49
|
+
scriptNode.tag = false;
|
|
50
|
+
scriptNode.content = [];
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
|
|
37
54
|
var _iteratorNormalCompletion = true;
|
|
38
55
|
var _didIteratorError = false;
|
|
39
56
|
var _iteratorError = undefined;
|
|
40
57
|
|
|
41
58
|
try {
|
|
42
|
-
var
|
|
59
|
+
for (var _iterator = Object.keys(scriptNodesIndex)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
|
43
60
|
var scriptKey = _step.value;
|
|
44
61
|
|
|
45
|
-
|
|
46
|
-
var lastScriptNode = scriptNodes.pop();
|
|
47
|
-
scriptNodes.reverse().forEach(function (scriptNode) {
|
|
48
|
-
var scriptContent = (scriptNode.content || []).join(' ');
|
|
49
|
-
scriptContent = scriptContent.trim();
|
|
50
|
-
if (scriptContent.slice(-1) !== ';') {
|
|
51
|
-
scriptContent += ';';
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
lastScriptNode.content.unshift(scriptContent);
|
|
55
|
-
|
|
56
|
-
scriptNode.tag = false;
|
|
57
|
-
scriptNode.content = [];
|
|
58
|
-
});
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
for (var _iterator = Object.keys(scriptNodesIndex)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
|
62
|
-
_loop();
|
|
62
|
+
_loop(scriptKey);
|
|
63
63
|
}
|
|
64
64
|
} catch (err) {
|
|
65
65
|
_didIteratorError = true;
|
package/lib/modules/minifyCss.js
CHANGED
|
@@ -24,7 +24,7 @@ var postcssOptions = {
|
|
|
24
24
|
function minifyCss(tree, options, cssnanoOptions) {
|
|
25
25
|
var promises = [];
|
|
26
26
|
tree.walk(function (node) {
|
|
27
|
-
if (isStyleNode(node)) {
|
|
27
|
+
if ((0, _helpers.isStyleNode)(node)) {
|
|
28
28
|
promises.push(processStyleNode(node, cssnanoOptions));
|
|
29
29
|
} else if (node.attrs && node.attrs.style) {
|
|
30
30
|
promises.push(processStyleAttr(node, cssnanoOptions));
|
|
@@ -38,12 +38,8 @@ function minifyCss(tree, options, cssnanoOptions) {
|
|
|
38
38
|
});
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
function isStyleNode(node) {
|
|
42
|
-
return node.tag === 'style' && !(0, _helpers.isAmpBoilerplate)(node) && node.content && node.content.length;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
41
|
function processStyleNode(styleNode, cssnanoOptions) {
|
|
46
|
-
var css =
|
|
42
|
+
var css = (0, _helpers.extractCssFromStyleNode)(styleNode);
|
|
47
43
|
return _cssnano2.default.process(css, postcssOptions, cssnanoOptions).then(function (result) {
|
|
48
44
|
return styleNode.content = [result.css];
|
|
49
45
|
});
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
|
|
8
|
+
|
|
9
|
+
exports.default = removeUnusedCss;
|
|
10
|
+
|
|
11
|
+
var _helpers = require('../helpers');
|
|
12
|
+
|
|
13
|
+
var _uncss = require('uncss');
|
|
14
|
+
|
|
15
|
+
var _uncss2 = _interopRequireDefault(_uncss);
|
|
16
|
+
|
|
17
|
+
var _posthtmlRender = require('posthtml-render');
|
|
18
|
+
|
|
19
|
+
var _posthtmlRender2 = _interopRequireDefault(_posthtmlRender);
|
|
20
|
+
|
|
21
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
22
|
+
|
|
23
|
+
// These options must be set and shouldn't be overriden to ensure uncss doesn't look at linked stylesheets.
|
|
24
|
+
var uncssOptions = {
|
|
25
|
+
ignoreSheets: [/\s*/],
|
|
26
|
+
stylesheets: []
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/** Remove unused CSS using uncss */
|
|
30
|
+
function removeUnusedCss(tree, options, uncssOptions) {
|
|
31
|
+
var promises = [];
|
|
32
|
+
var html = (0, _posthtmlRender2.default)(tree);
|
|
33
|
+
tree.walk(function (node) {
|
|
34
|
+
if ((0, _helpers.isStyleNode)(node)) {
|
|
35
|
+
promises.push(processStyleNode(html, node, uncssOptions));
|
|
36
|
+
}
|
|
37
|
+
return node;
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
return Promise.all(promises).then(function () {
|
|
41
|
+
return tree;
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function processStyleNode(html, styleNode, uncssOptions) {
|
|
46
|
+
var css = (0, _helpers.extractCssFromStyleNode)(styleNode);
|
|
47
|
+
|
|
48
|
+
return runUncss(html, css, uncssOptions).then(function (css) {
|
|
49
|
+
// uncss may have left some style tags empty
|
|
50
|
+
if (css.trim().length === 0) {
|
|
51
|
+
styleNode.tag = false;
|
|
52
|
+
styleNode.content = [];
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
styleNode.content = [css];
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function runUncss(html, css, userOptions) {
|
|
60
|
+
if ((typeof userOptions === 'undefined' ? 'undefined' : _typeof(userOptions)) !== 'object') {
|
|
61
|
+
userOptions = {};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
var options = Object.assign({}, userOptions, uncssOptions);
|
|
65
|
+
return new Promise(function (resolve, reject) {
|
|
66
|
+
options.raw = css;
|
|
67
|
+
(0, _uncss2.default)(html, options, function (error, output) {
|
|
68
|
+
if (error) {
|
|
69
|
+
reject(error);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
resolve(output);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
}
|
package/lib/presets/ampSafe.js
CHANGED
package/lib/presets/max.js
CHANGED
|
@@ -22,5 +22,10 @@ function _interopRequireDefault(obj) {
|
|
|
22
22
|
exports.default = (0, _objectAssign2.default)({}, _safe2.default, {
|
|
23
23
|
collapseWhitespace: 'all',
|
|
24
24
|
removeComments: 'all',
|
|
25
|
-
removeRedundantAttributes: true
|
|
25
|
+
removeRedundantAttributes: true,
|
|
26
|
+
removeUnusedCss: {},
|
|
27
|
+
minifyCss: {
|
|
28
|
+
preset: 'default'
|
|
29
|
+
},
|
|
30
|
+
minifySvg: {}
|
|
26
31
|
});
|
package/lib/presets/safe.js
CHANGED
|
@@ -16,12 +16,15 @@ exports.default = {
|
|
|
16
16
|
deduplicateAttributeValues: true,
|
|
17
17
|
mergeScripts: true,
|
|
18
18
|
mergeStyles: true,
|
|
19
|
+
removeUnusedCss: false,
|
|
19
20
|
minifyCss: {
|
|
20
21
|
preset: 'default'
|
|
21
22
|
},
|
|
22
23
|
minifyJs: {},
|
|
23
24
|
minifyJson: {},
|
|
24
|
-
minifySvg: {
|
|
25
|
+
minifySvg: {
|
|
26
|
+
plugins: [{ collapseGroups: false }, { convertShapeToPath: false }]
|
|
27
|
+
},
|
|
25
28
|
removeEmptyAttributes: true,
|
|
26
29
|
removeRedundantAttributes: false,
|
|
27
30
|
removeComments: 'safe'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "htmlnano",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "Modular HTML minifier, built on top of the PostHTML",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"author": "Kirill Maltsev <maltsevkirill@gmail.com>",
|
|
@@ -11,7 +11,13 @@
|
|
|
11
11
|
"pretest": "npm run lint && npm run compile",
|
|
12
12
|
"test": ":",
|
|
13
13
|
"posttest": "mocha --require babel-core/register --recursive --check-leaks --globals addresses",
|
|
14
|
-
"prepare": "npm run compile"
|
|
14
|
+
"prepare": "npm run compile",
|
|
15
|
+
"release:patch": "release-it patch -n"
|
|
16
|
+
},
|
|
17
|
+
"release-it": {
|
|
18
|
+
"hooks": {
|
|
19
|
+
"before:init": "npm test"
|
|
20
|
+
}
|
|
15
21
|
},
|
|
16
22
|
"keywords": [
|
|
17
23
|
"posthtml",
|
|
@@ -22,27 +28,29 @@
|
|
|
22
28
|
],
|
|
23
29
|
"babel": {
|
|
24
30
|
"presets": [
|
|
25
|
-
"
|
|
31
|
+
"env"
|
|
26
32
|
]
|
|
27
33
|
},
|
|
28
34
|
"dependencies": {
|
|
29
|
-
"cssnano": "^4.1.
|
|
30
|
-
"normalize-html-whitespace": "^0.
|
|
35
|
+
"cssnano": "^4.1.10",
|
|
36
|
+
"normalize-html-whitespace": "^1.0.0",
|
|
31
37
|
"object-assign": "^4.0.1",
|
|
32
|
-
"posthtml": "^0.11.
|
|
33
|
-
"posthtml-render": "^1.1.
|
|
34
|
-
"svgo": "^1.
|
|
35
|
-
"terser": "^
|
|
38
|
+
"posthtml": "^0.11.4",
|
|
39
|
+
"posthtml-render": "^1.1.5",
|
|
40
|
+
"svgo": "^1.2.2",
|
|
41
|
+
"terser": "^4.1.2",
|
|
42
|
+
"uncss": "^0.17.0"
|
|
36
43
|
},
|
|
37
44
|
"devDependencies": {
|
|
38
45
|
"babel-cli": "^6.26.0",
|
|
39
46
|
"babel-core": "^6.26.3",
|
|
40
|
-
"babel-eslint": "^
|
|
41
|
-
"babel-preset-
|
|
42
|
-
"eslint": "^
|
|
43
|
-
"expect": "^
|
|
44
|
-
"mocha": "^
|
|
45
|
-
"
|
|
47
|
+
"babel-eslint": "^10.0.2",
|
|
48
|
+
"babel-preset-env": "^1.7.0",
|
|
49
|
+
"eslint": "^6.0.1",
|
|
50
|
+
"expect": "^24.8.0",
|
|
51
|
+
"mocha": "^6.1.0",
|
|
52
|
+
"release-it": "^12.3.3",
|
|
53
|
+
"rimraf": "^2.6.3"
|
|
46
54
|
},
|
|
47
55
|
"repository": {
|
|
48
56
|
"type": "git",
|
package/test.js
CHANGED
|
@@ -1,37 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
// 'collapseWhitespace': false,
|
|
5
|
-
// 'custom': false,
|
|
6
|
-
// 'example': false,
|
|
7
|
-
// 'mergeScripts': false,
|
|
8
|
-
// 'mergeStyles': false,
|
|
9
|
-
// 'minifyCss': false,
|
|
10
|
-
// 'minifyJs': false,
|
|
11
|
-
// 'minifyJson': false,
|
|
12
|
-
// 'minifySvg': false,
|
|
13
|
-
// 'removeComments': false,
|
|
14
|
-
// 'removeEmptyAttributes': false,
|
|
15
|
-
// 'removeRedundantAttributes': false,
|
|
16
|
-
};
|
|
1
|
+
const htmlnano = require('./index');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const safePreset = require('./lib/presets/safe').default;
|
|
17
4
|
|
|
18
|
-
|
|
19
|
-
<script>const foo = 'A:1';</script>
|
|
20
|
-
<script class="test">foo = 'B:1';</script>
|
|
21
|
-
<script type="text/javascript">foo = 'A:2';</script>
|
|
22
|
-
<script defer>foo = 'C:1';</script>
|
|
23
|
-
<script>foo = 'A:3';</script>
|
|
24
|
-
<script defer="defer">foo = 'C:2';</script>
|
|
25
|
-
<script class="test" type="text/javascript">foo = 'B:2';</script>
|
|
26
|
-
`;
|
|
5
|
+
const options = {};
|
|
27
6
|
|
|
28
|
-
|
|
7
|
+
const html = fs.readFileSync('./test.html', 'utf8');
|
|
29
8
|
|
|
30
9
|
htmlnano
|
|
31
10
|
.process(html, options)
|
|
32
11
|
.then(function (result) {
|
|
33
|
-
|
|
34
|
-
// result.html is minified
|
|
12
|
+
console.log(result.html);
|
|
35
13
|
})
|
|
36
14
|
.catch(function (err) {
|
|
37
15
|
console.error(err);
|