htmlnano 1.1.1 → 2.0.2
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 +31 -0
- package/README.md +8 -13
- package/docs/docs/050-modules.md +54 -2
- package/docs/package-lock.json +14644 -824
- package/docs/versioned_docs/version-2.0.0/010-introduction.md +22 -0
- package/docs/versioned_docs/version-2.0.0/020-usage.md +77 -0
- package/docs/versioned_docs/version-2.0.0/030-config.md +21 -0
- package/docs/versioned_docs/version-2.0.0/040-presets.md +75 -0
- package/docs/versioned_docs/version-2.0.0/050-modules.md +838 -0
- package/docs/versioned_docs/version-2.0.0/060-contribute.md +16 -0
- package/docs/versioned_sidebars/version-2.0.0-sidebars.json +8 -0
- package/docs/versions.json +1 -0
- package/lib/helpers.js +15 -2
- package/lib/htmlnano.js +85 -4
- package/lib/modules/collapseAttributeWhitespace.js +20 -20
- package/lib/modules/collapseBooleanAttributes.js +13 -19
- package/lib/modules/deduplicateAttributeValues.js +10 -16
- package/lib/modules/minifyCss.js +8 -8
- package/lib/modules/minifyJs.js +5 -8
- package/lib/modules/minifyJson.js +12 -24
- package/lib/modules/minifySvg.js +8 -4
- package/lib/modules/minifyUrls.js +29 -22
- package/lib/modules/normalizeAttributeValues.js +9 -15
- package/lib/modules/removeComments.js +17 -9
- package/lib/modules/removeEmptyAttributes.js +13 -16
- package/lib/modules/removeRedundantAttributes.js +19 -23
- package/lib/modules/removeUnusedCss.js +10 -10
- package/lib/presets/max.js +2 -0
- package/lib/presets/safe.js +2 -2
- package/package.json +49 -13
- package/uncss-fork.patch +0 -13
|
@@ -3,28 +3,36 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.
|
|
6
|
+
exports.onContent = onContent;
|
|
7
|
+
exports.onNode = onNode;
|
|
7
8
|
|
|
8
9
|
var _helpers = require("../helpers");
|
|
9
10
|
|
|
10
11
|
const MATCH_EXCERPT_REGEXP = /<!-- ?more ?-->/i;
|
|
11
12
|
/** Removes HTML comments */
|
|
12
13
|
|
|
13
|
-
function
|
|
14
|
+
function onNode(options, removeType) {
|
|
14
15
|
if (removeType !== 'all' && removeType !== 'safe' && !isMatcher(removeType)) {
|
|
15
16
|
removeType = 'safe';
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
if (node
|
|
20
|
-
|
|
21
|
-
} else if (isCommentToRemove(node, removeType)) {
|
|
22
|
-
node = '';
|
|
19
|
+
return node => {
|
|
20
|
+
if (isCommentToRemove(node, removeType)) {
|
|
21
|
+
return '';
|
|
23
22
|
}
|
|
24
23
|
|
|
25
24
|
return node;
|
|
26
|
-
}
|
|
27
|
-
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function onContent(options, removeType) {
|
|
29
|
+
if (removeType !== 'all' && removeType !== 'safe' && !isMatcher(removeType)) {
|
|
30
|
+
removeType = 'safe';
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return contents => {
|
|
34
|
+
return contents.filter(content => !isCommentToRemove(content, removeType));
|
|
35
|
+
};
|
|
28
36
|
}
|
|
29
37
|
|
|
30
38
|
function isCommentToRemove(text, removeType) {
|
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.
|
|
6
|
+
exports.onAttrs = onAttrs;
|
|
7
|
+
|
|
8
|
+
var _helpers = require("../helpers");
|
|
9
|
+
|
|
7
10
|
const safeToRemoveAttrs = {
|
|
8
11
|
id: null,
|
|
9
12
|
class: null,
|
|
@@ -52,24 +55,18 @@ const safeToRemoveAttrs = {
|
|
|
52
55
|
value: ['button', 'input', 'li'],
|
|
53
56
|
width: ['canvas', 'embed', 'iframe', 'img', 'input', 'object', 'video']
|
|
54
57
|
};
|
|
55
|
-
/** Removes empty attributes */
|
|
56
|
-
|
|
57
|
-
function removeEmptyAttributes(tree) {
|
|
58
|
-
tree.walk(node => {
|
|
59
|
-
if (!node.attrs) {
|
|
60
|
-
return node;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
Object.entries(node.attrs).forEach(([attrName, attrValue]) => {
|
|
64
|
-
const attrNameLower = attrName.toLowerCase();
|
|
65
58
|
|
|
66
|
-
|
|
59
|
+
function onAttrs() {
|
|
60
|
+
return (attrs, node) => {
|
|
61
|
+
const newAttrs = { ...attrs
|
|
62
|
+
};
|
|
63
|
+
Object.entries(attrs).forEach(([attrName, attrValue]) => {
|
|
64
|
+
if ((0, _helpers.isEventHandler)(attrName) || Object.hasOwnProperty.call(safeToRemoveAttrs, attrName) && (safeToRemoveAttrs[attrName] === null || safeToRemoveAttrs[attrName].includes(node.tag))) {
|
|
67
65
|
if (attrValue === '' || (attrValue || '').match(/^\s+$/)) {
|
|
68
|
-
delete
|
|
66
|
+
delete newAttrs[attrName];
|
|
69
67
|
}
|
|
70
68
|
}
|
|
71
69
|
});
|
|
72
|
-
return
|
|
73
|
-
}
|
|
74
|
-
return tree;
|
|
70
|
+
return newAttrs;
|
|
71
|
+
};
|
|
75
72
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.
|
|
6
|
+
exports.onAttrs = onAttrs;
|
|
7
7
|
exports.redundantScriptTypes = void 0;
|
|
8
8
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#JavaScript_types
|
|
9
9
|
const redundantScriptTypes = new Set(['application/javascript', 'application/ecmascript', 'application/x-ecmascript', 'application/x-javascript', 'text/javascript', 'text/ecmascript', 'text/javascript1.0', 'text/javascript1.1', 'text/javascript1.2', 'text/javascript1.3', 'text/javascript1.4', 'text/javascript1.5', 'text/jscript', 'text/livescript', 'text/x-ecmascript', 'text/x-javascript']);
|
|
@@ -20,8 +20,8 @@ const redundantAttributes = {
|
|
|
20
20
|
},
|
|
21
21
|
'script': {
|
|
22
22
|
'language': 'javascript',
|
|
23
|
-
'type':
|
|
24
|
-
for (const [attrName, attrValue] of Object.entries(
|
|
23
|
+
'type': attrs => {
|
|
24
|
+
for (const [attrName, attrValue] of Object.entries(attrs)) {
|
|
25
25
|
if (attrName.toLowerCase() !== 'type') {
|
|
26
26
|
continue;
|
|
27
27
|
}
|
|
@@ -32,10 +32,10 @@ const redundantAttributes = {
|
|
|
32
32
|
return false;
|
|
33
33
|
},
|
|
34
34
|
// Remove attribute if the function returns false
|
|
35
|
-
'charset':
|
|
35
|
+
'charset': attrs => {
|
|
36
36
|
// The charset attribute only really makes sense on “external” SCRIPT elements:
|
|
37
37
|
// http://perfectionkills.com/optimizing-html/#8_script_charset
|
|
38
|
-
return
|
|
38
|
+
return !attrs.src;
|
|
39
39
|
}
|
|
40
40
|
},
|
|
41
41
|
'style': {
|
|
@@ -44,13 +44,13 @@ const redundantAttributes = {
|
|
|
44
44
|
},
|
|
45
45
|
'link': {
|
|
46
46
|
'media': 'all',
|
|
47
|
-
'type':
|
|
47
|
+
'type': attrs => {
|
|
48
48
|
// https://html.spec.whatwg.org/multipage/links.html#link-type-stylesheet
|
|
49
49
|
let isRelStyleSheet = false;
|
|
50
50
|
let isTypeTextCSS = false;
|
|
51
51
|
|
|
52
|
-
if (
|
|
53
|
-
for (const [attrName, attrValue] of Object.entries(
|
|
52
|
+
if (attrs) {
|
|
53
|
+
for (const [attrName, attrValue] of Object.entries(attrs)) {
|
|
54
54
|
if (attrName.toLowerCase() === 'rel' && attrValue === 'stylesheet') {
|
|
55
55
|
isRelStyleSheet = true;
|
|
56
56
|
}
|
|
@@ -115,13 +115,10 @@ const tagsHaveRedundantAttributes = new Set(Object.keys(redundantAttributes));
|
|
|
115
115
|
const tagsHaveMissingValueDefaultAttributes = new Set(Object.keys(canBeReplacedWithEmptyStringAttributes));
|
|
116
116
|
/** Removes redundant attributes */
|
|
117
117
|
|
|
118
|
-
function
|
|
119
|
-
|
|
120
|
-
if (!node.tag)
|
|
121
|
-
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
node.attrs = node.attrs || {};
|
|
118
|
+
function onAttrs() {
|
|
119
|
+
return (attrs, node) => {
|
|
120
|
+
if (!node.tag) return attrs;
|
|
121
|
+
const newAttrs = attrs;
|
|
125
122
|
|
|
126
123
|
if (tagsHaveRedundantAttributes.has(node.tag)) {
|
|
127
124
|
const tagRedundantAttributes = redundantAttributes[node.tag];
|
|
@@ -131,13 +128,13 @@ function removeRedundantAttributes(tree) {
|
|
|
131
128
|
let isRemove = false;
|
|
132
129
|
|
|
133
130
|
if (typeof tagRedundantAttributeValue === 'function') {
|
|
134
|
-
isRemove = tagRedundantAttributeValue(
|
|
135
|
-
} else if (
|
|
131
|
+
isRemove = tagRedundantAttributeValue(attrs);
|
|
132
|
+
} else if (attrs[redundantAttributeName] === tagRedundantAttributeValue) {
|
|
136
133
|
isRemove = true;
|
|
137
134
|
}
|
|
138
135
|
|
|
139
136
|
if (isRemove) {
|
|
140
|
-
delete
|
|
137
|
+
delete newAttrs[redundantAttributeName];
|
|
141
138
|
}
|
|
142
139
|
}
|
|
143
140
|
}
|
|
@@ -149,17 +146,16 @@ function removeRedundantAttributes(tree) {
|
|
|
149
146
|
let tagMissingValueDefaultAttribute = tagMissingValueDefaultAttributes[canBeReplacedWithEmptyStringAttributeName];
|
|
150
147
|
let isReplace = false;
|
|
151
148
|
|
|
152
|
-
if (
|
|
149
|
+
if (attrs[canBeReplacedWithEmptyStringAttributeName] === tagMissingValueDefaultAttribute) {
|
|
153
150
|
isReplace = true;
|
|
154
151
|
}
|
|
155
152
|
|
|
156
153
|
if (isReplace) {
|
|
157
|
-
|
|
154
|
+
newAttrs[canBeReplacedWithEmptyStringAttributeName] = '';
|
|
158
155
|
}
|
|
159
156
|
}
|
|
160
157
|
}
|
|
161
158
|
|
|
162
|
-
return
|
|
163
|
-
}
|
|
164
|
-
return tree;
|
|
159
|
+
return newAttrs;
|
|
160
|
+
};
|
|
165
161
|
}
|
|
@@ -7,13 +7,9 @@ exports.default = removeUnusedCss;
|
|
|
7
7
|
|
|
8
8
|
var _helpers = require("../helpers");
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
const uncss = (0, _helpers.optionalRequire)('uncss');
|
|
11
|
+
const purgecss = (0, _helpers.optionalRequire)('purgecss'); // These options must be set and shouldn't be overriden to ensure uncss doesn't look at linked stylesheets.
|
|
11
12
|
|
|
12
|
-
var _purgecss = _interopRequireDefault(require("purgecss"));
|
|
13
|
-
|
|
14
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
15
|
-
|
|
16
|
-
// These options must be set and shouldn't be overriden to ensure uncss doesn't look at linked stylesheets.
|
|
17
13
|
const uncssOptions = {
|
|
18
14
|
ignoreSheets: [/\s*/],
|
|
19
15
|
stylesheets: []
|
|
@@ -43,7 +39,7 @@ function runUncss(html, css, userOptions) {
|
|
|
43
39
|
};
|
|
44
40
|
return new Promise((resolve, reject) => {
|
|
45
41
|
options.raw = css;
|
|
46
|
-
(
|
|
42
|
+
uncss(html, options, (error, output) => {
|
|
47
43
|
if (error) {
|
|
48
44
|
reject(error);
|
|
49
45
|
return;
|
|
@@ -100,7 +96,7 @@ function runPurgecss(tree, css, userOptions) {
|
|
|
100
96
|
extensions: ['html']
|
|
101
97
|
}]
|
|
102
98
|
};
|
|
103
|
-
return new
|
|
99
|
+
return new purgecss.PurgeCSS().purge(options).then(result => {
|
|
104
100
|
return result[0].css;
|
|
105
101
|
});
|
|
106
102
|
}
|
|
@@ -113,9 +109,13 @@ function removeUnusedCss(tree, options, userOptions) {
|
|
|
113
109
|
tree.walk(node => {
|
|
114
110
|
if ((0, _helpers.isStyleNode)(node)) {
|
|
115
111
|
if (userOptions.tool === 'purgeCSS') {
|
|
116
|
-
|
|
112
|
+
if (purgecss) {
|
|
113
|
+
promises.push(processStyleNodePurgeCSS(tree, node, userOptions));
|
|
114
|
+
}
|
|
117
115
|
} else {
|
|
118
|
-
|
|
116
|
+
if (uncss) {
|
|
117
|
+
promises.push(processStyleNodeUnCSS(html, node, userOptions));
|
|
118
|
+
}
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
|
package/lib/presets/max.js
CHANGED
package/lib/presets/safe.js
CHANGED
|
@@ -17,8 +17,8 @@ var _default = {
|
|
|
17
17
|
collapseWhitespace: 'conservative',
|
|
18
18
|
custom: [],
|
|
19
19
|
deduplicateAttributeValues: true,
|
|
20
|
-
mergeScripts:
|
|
21
|
-
mergeStyles:
|
|
20
|
+
mergeScripts: false,
|
|
21
|
+
mergeStyles: false,
|
|
22
22
|
removeUnusedCss: false,
|
|
23
23
|
minifyCss: {
|
|
24
24
|
preset: 'default'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "htmlnano",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.2",
|
|
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>",
|
|
@@ -40,28 +40,64 @@
|
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"cosmiconfig": "^7.0.1",
|
|
43
|
-
"cssnano": "^5.0.8",
|
|
44
|
-
"postcss": "^8.3.6",
|
|
45
43
|
"posthtml": "^0.16.5",
|
|
46
|
-
"
|
|
47
|
-
"relateurl": "^0.2.7",
|
|
48
|
-
"srcset": "^4.0.0",
|
|
49
|
-
"svgo": "^2.6.1",
|
|
50
|
-
"terser": "^5.8.0",
|
|
51
|
-
"timsort": "^0.3.0",
|
|
52
|
-
"uncss": "^0.17.3"
|
|
44
|
+
"timsort": "^0.3.0"
|
|
53
45
|
},
|
|
54
46
|
"devDependencies": {
|
|
55
47
|
"@babel/cli": "^7.15.7",
|
|
56
48
|
"@babel/core": "^7.15.5",
|
|
49
|
+
"@babel/eslint-parser": "^7.17.0",
|
|
57
50
|
"@babel/preset-env": "^7.15.6",
|
|
58
51
|
"@babel/register": "^7.15.3",
|
|
59
|
-
"
|
|
60
|
-
"eslint": "^
|
|
52
|
+
"cssnano": "^5.0.11",
|
|
53
|
+
"eslint": "^8.12.0",
|
|
61
54
|
"expect": "^27.2.0",
|
|
62
55
|
"mocha": "^9.1.0",
|
|
56
|
+
"postcss": "^8.3.11",
|
|
57
|
+
"purgecss": "^4.0.3",
|
|
58
|
+
"relateurl": "^0.2.7",
|
|
63
59
|
"release-it": "^14.11.5",
|
|
64
|
-
"rimraf": "^3.0.2"
|
|
60
|
+
"rimraf": "^3.0.2",
|
|
61
|
+
"srcset": "^5.0.0",
|
|
62
|
+
"svgo": "^2.8.0",
|
|
63
|
+
"terser": "^5.10.0",
|
|
64
|
+
"uncss": "^0.17.3"
|
|
65
|
+
},
|
|
66
|
+
"peerDependencies": {
|
|
67
|
+
"cssnano": "^5.0.11",
|
|
68
|
+
"postcss": "^8.3.11",
|
|
69
|
+
"purgecss": "^4.0.3",
|
|
70
|
+
"relateurl": "^0.2.7",
|
|
71
|
+
"srcset": "^5.0.0",
|
|
72
|
+
"svgo": "^2.8.0",
|
|
73
|
+
"terser": "^5.10.0",
|
|
74
|
+
"uncss": "^0.17.3"
|
|
75
|
+
},
|
|
76
|
+
"peerDependenciesMeta": {
|
|
77
|
+
"cssnano": {
|
|
78
|
+
"optional": true
|
|
79
|
+
},
|
|
80
|
+
"postcss": {
|
|
81
|
+
"optional": true
|
|
82
|
+
},
|
|
83
|
+
"purgecss": {
|
|
84
|
+
"optional": true
|
|
85
|
+
},
|
|
86
|
+
"relateurl": {
|
|
87
|
+
"optional": true
|
|
88
|
+
},
|
|
89
|
+
"srcset": {
|
|
90
|
+
"optional": true
|
|
91
|
+
},
|
|
92
|
+
"svgo": {
|
|
93
|
+
"optional": true
|
|
94
|
+
},
|
|
95
|
+
"terser": {
|
|
96
|
+
"optional": true
|
|
97
|
+
},
|
|
98
|
+
"uncss": {
|
|
99
|
+
"optional": true
|
|
100
|
+
}
|
|
65
101
|
},
|
|
66
102
|
"repository": {
|
|
67
103
|
"type": "git",
|
package/uncss-fork.patch
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
diff --git a/package.json b/package.json
|
|
2
|
-
index a127c0f..66455bb 100644
|
|
3
|
-
--- a/package.json
|
|
4
|
-
+++ b/package.json
|
|
5
|
-
@@ -49,7 +49,7 @@
|
|
6
|
-
"svgo": "^2.4.0",
|
|
7
|
-
"terser": "^5.7.0",
|
|
8
|
-
"timsort": "^0.3.0",
|
|
9
|
-
- "uncss": "^0.17.3"
|
|
10
|
-
+ "@novaatwarren/uncss": "^0.17.4"
|
|
11
|
-
},
|
|
12
|
-
"devDependencies": {
|
|
13
|
-
"@babel/cli": "^7.14.3",
|