htmlnano 2.1.2 → 2.1.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/README.md +54 -12
- package/dist/_modules/collapseAttributeWhitespace.d.mts +57 -0
- package/dist/_modules/collapseAttributeWhitespace.d.ts +57 -0
- package/dist/_modules/collapseAttributeWhitespace.js +296 -0
- package/dist/_modules/collapseAttributeWhitespace.mjs +293 -0
- package/dist/_modules/collapseBooleanAttributes.d.mts +60 -0
- package/dist/_modules/collapseBooleanAttributes.d.ts +60 -0
- package/dist/_modules/collapseBooleanAttributes.js +159 -0
- package/{lib/modules → dist/_modules}/collapseBooleanAttributes.mjs +39 -57
- package/dist/_modules/collapseWhitespace.d.mts +57 -0
- package/dist/_modules/collapseWhitespace.d.ts +57 -0
- package/dist/_modules/collapseWhitespace.js +172 -0
- package/dist/_modules/collapseWhitespace.mjs +170 -0
- package/dist/_modules/custom.d.mts +57 -0
- package/dist/_modules/custom.d.ts +57 -0
- package/dist/_modules/custom.js +22 -0
- package/dist/_modules/custom.mjs +20 -0
- package/dist/_modules/deduplicateAttributeValues.d.mts +56 -0
- package/dist/_modules/deduplicateAttributeValues.d.ts +56 -0
- package/dist/_modules/deduplicateAttributeValues.js +38 -0
- package/dist/_modules/deduplicateAttributeValues.mjs +36 -0
- package/dist/_modules/example.d.mts +59 -0
- package/dist/_modules/example.d.ts +59 -0
- package/dist/_modules/example.js +67 -0
- package/dist/_modules/example.mjs +65 -0
- package/dist/_modules/mergeScripts.d.mts +56 -0
- package/dist/_modules/mergeScripts.d.ts +56 -0
- package/dist/_modules/mergeScripts.js +53 -0
- package/dist/_modules/mergeScripts.mjs +51 -0
- package/dist/_modules/mergeStyles.d.mts +56 -0
- package/dist/_modules/mergeStyles.d.ts +56 -0
- package/dist/_modules/mergeStyles.js +42 -0
- package/dist/_modules/mergeStyles.mjs +40 -0
- package/dist/_modules/minifyConditionalComments.d.mts +56 -0
- package/dist/_modules/minifyConditionalComments.d.ts +56 -0
- package/dist/_modules/minifyConditionalComments.js +54 -0
- package/{lib/modules → dist/_modules}/minifyConditionalComments.mjs +21 -22
- package/dist/_modules/minifyCss.d.mts +56 -0
- package/dist/_modules/minifyCss.d.ts +56 -0
- package/dist/_modules/minifyCss.js +84 -0
- package/dist/_modules/minifyCss.mjs +82 -0
- package/dist/_modules/minifyJs.d.mts +56 -0
- package/dist/_modules/minifyJs.d.ts +56 -0
- package/dist/_modules/minifyJs.js +108 -0
- package/dist/_modules/minifyJs.mjs +106 -0
- package/dist/_modules/minifyJson.d.mts +56 -0
- package/dist/_modules/minifyJson.d.ts +56 -0
- package/dist/_modules/minifyJson.js +35 -0
- package/dist/_modules/minifyJson.mjs +33 -0
- package/dist/_modules/minifySvg.d.mts +56 -0
- package/dist/_modules/minifySvg.d.ts +56 -0
- package/dist/_modules/minifySvg.js +40 -0
- package/dist/_modules/minifySvg.mjs +38 -0
- package/dist/_modules/minifyUrls.d.mts +56 -0
- package/dist/_modules/minifyUrls.d.ts +56 -0
- package/dist/_modules/minifyUrls.js +180 -0
- package/dist/_modules/minifyUrls.mjs +178 -0
- package/dist/_modules/normalizeAttributeValues.d.mts +56 -0
- package/dist/_modules/normalizeAttributeValues.d.ts +56 -0
- package/dist/_modules/normalizeAttributeValues.js +234 -0
- package/dist/_modules/normalizeAttributeValues.mjs +232 -0
- package/dist/_modules/removeAttributeQuotes.d.mts +56 -0
- package/dist/_modules/removeAttributeQuotes.d.ts +56 -0
- package/dist/_modules/removeAttributeQuotes.js +15 -0
- package/dist/_modules/removeAttributeQuotes.mjs +13 -0
- package/dist/_modules/removeComments.d.mts +58 -0
- package/dist/_modules/removeComments.d.ts +58 -0
- package/dist/_modules/removeComments.js +83 -0
- package/{lib/modules → dist/_modules}/removeComments.mjs +24 -35
- package/dist/_modules/removeEmptyAttributes.d.mts +56 -0
- package/dist/_modules/removeEmptyAttributes.d.ts +56 -0
- package/dist/_modules/removeEmptyAttributes.js +197 -0
- package/dist/_modules/removeEmptyAttributes.mjs +195 -0
- package/dist/_modules/removeOptionalTags.d.mts +56 -0
- package/dist/_modules/removeOptionalTags.d.ts +56 -0
- package/dist/_modules/removeOptionalTags.js +190 -0
- package/{lib/modules → dist/_modules}/removeOptionalTags.mjs +54 -91
- package/dist/_modules/removeRedundantAttributes.d.mts +57 -0
- package/dist/_modules/removeRedundantAttributes.d.ts +57 -0
- package/dist/_modules/removeRedundantAttributes.js +128 -0
- package/{lib/modules → dist/_modules}/removeRedundantAttributes.mjs +43 -59
- package/dist/_modules/removeUnusedCss.d.mts +60 -0
- package/dist/_modules/removeUnusedCss.d.ts +60 -0
- package/dist/_modules/removeUnusedCss.js +134 -0
- package/dist/_modules/removeUnusedCss.mjs +132 -0
- package/dist/_modules/sortAttributes.d.mts +57 -0
- package/dist/_modules/sortAttributes.d.ts +57 -0
- package/dist/_modules/sortAttributes.js +102 -0
- package/{lib/modules → dist/_modules}/sortAttributes.mjs +39 -58
- package/dist/_modules/sortAttributesWithLists.d.mts +56 -0
- package/dist/_modules/sortAttributesWithLists.d.ts +56 -0
- package/dist/_modules/sortAttributesWithLists.js +118 -0
- package/{lib/modules → dist/_modules}/sortAttributesWithLists.mjs +41 -59
- package/dist/helpers.d.ts +16 -0
- package/dist/helpers.js +72 -0
- package/dist/helpers.mjs +63 -0
- package/dist/index.d.ts +79 -0
- package/dist/index.js +223 -0
- package/dist/index.mjs +209 -0
- package/dist/presets/ampSafe.d.ts +47 -0
- package/dist/presets/ampSafe.js +19 -0
- package/{lib → dist}/presets/ampSafe.mjs +6 -4
- package/dist/presets/max.d.ts +47 -0
- package/dist/presets/max.js +28 -0
- package/{lib → dist}/presets/max.mjs +6 -4
- package/dist/presets/safe.d.ts +47 -0
- package/dist/presets/safe.js +60 -0
- package/{lib → dist}/presets/safe.mjs +13 -20
- package/package.json +53 -56
- package/.eslintignore +0 -3
- package/CHANGELOG.md +0 -409
- package/docs/README.md +0 -33
- package/docs/babel.config.js +0 -3
- package/docs/docs/010-introduction.md +0 -22
- package/docs/docs/020-usage.md +0 -117
- package/docs/docs/030-config.md +0 -21
- package/docs/docs/040-presets.md +0 -75
- package/docs/docs/050-modules.md +0 -855
- package/docs/docs/060-contribute.md +0 -16
- package/docs/docusaurus.config.js +0 -65
- package/docs/netlify.toml +0 -4
- package/docs/package-lock.json +0 -21630
- package/docs/package.json +0 -40
- package/docs/sidebars.js +0 -26
- package/docs/versioned_docs/version-1.1.1/010-introduction.md +0 -22
- package/docs/versioned_docs/version-1.1.1/020-usage.md +0 -77
- package/docs/versioned_docs/version-1.1.1/030-config.md +0 -21
- package/docs/versioned_docs/version-1.1.1/040-presets.md +0 -75
- package/docs/versioned_docs/version-1.1.1/050-modules.md +0 -785
- package/docs/versioned_docs/version-1.1.1/060-contribute.md +0 -16
- package/docs/versioned_docs/version-2.0.0/010-introduction.md +0 -22
- package/docs/versioned_docs/version-2.0.0/020-usage.md +0 -77
- package/docs/versioned_docs/version-2.0.0/030-config.md +0 -21
- package/docs/versioned_docs/version-2.0.0/040-presets.md +0 -75
- package/docs/versioned_docs/version-2.0.0/050-modules.md +0 -838
- package/docs/versioned_docs/version-2.0.0/060-contribute.md +0 -16
- package/docs/versioned_sidebars/version-1.1.1-sidebars.json +0 -8
- package/docs/versioned_sidebars/version-2.0.0-sidebars.json +0 -8
- package/docs/versions.json +0 -4
- package/index.cjs +0 -11
- package/index.d.cts +0 -3
- package/index.d.mts +0 -3
- package/index.d.ts +0 -94
- package/index.mjs +0 -2
- package/lib/helpers.cjs +0 -79
- package/lib/helpers.mjs +0 -53
- package/lib/htmlnano.cjs +0 -202
- package/lib/htmlnano.mjs +0 -198
- package/lib/modules/collapseAttributeWhitespace.cjs +0 -86
- package/lib/modules/collapseAttributeWhitespace.mjs +0 -104
- package/lib/modules/collapseBooleanAttributes.cjs +0 -62
- package/lib/modules/collapseWhitespace.cjs +0 -100
- package/lib/modules/collapseWhitespace.mjs +0 -132
- package/lib/modules/custom.cjs +0 -19
- package/lib/modules/custom.mjs +0 -16
- package/lib/modules/deduplicateAttributeValues.cjs +0 -38
- package/lib/modules/deduplicateAttributeValues.mjs +0 -40
- package/lib/modules/example.cjs +0 -85
- package/lib/modules/example.mjs +0 -75
- package/lib/modules/mergeScripts.cjs +0 -54
- package/lib/modules/mergeScripts.mjs +0 -56
- package/lib/modules/mergeStyles.cjs +0 -38
- package/lib/modules/mergeStyles.mjs +0 -36
- package/lib/modules/minifyConditionalComments.cjs +0 -47
- package/lib/modules/minifyCss.cjs +0 -73
- package/lib/modules/minifyCss.mjs +0 -88
- package/lib/modules/minifyJs.cjs +0 -103
- package/lib/modules/minifyJs.mjs +0 -121
- package/lib/modules/minifyJson.cjs +0 -24
- package/lib/modules/minifyJson.mjs +0 -21
- package/lib/modules/minifySvg.cjs +0 -37
- package/lib/modules/minifySvg.mjs +0 -30
- package/lib/modules/minifyUrls.cjs +0 -141
- package/lib/modules/minifyUrls.mjs +0 -229
- package/lib/modules/normalizeAttributeValues.cjs +0 -120
- package/lib/modules/normalizeAttributeValues.mjs +0 -140
- package/lib/modules/removeAttributeQuotes.cjs +0 -17
- package/lib/modules/removeAttributeQuotes.mjs +0 -12
- package/lib/modules/removeComments.cjs +0 -86
- package/lib/modules/removeEmptyAttributes.cjs +0 -72
- package/lib/modules/removeEmptyAttributes.mjs +0 -121
- package/lib/modules/removeOptionalTags.cjs +0 -183
- package/lib/modules/removeRedundantAttributes.cjs +0 -112
- package/lib/modules/removeUnusedCss.cjs +0 -113
- package/lib/modules/removeUnusedCss.mjs +0 -122
- package/lib/modules/sortAttributes.cjs +0 -98
- package/lib/modules/sortAttributesWithLists.cjs +0 -114
- package/lib/presets/ampSafe.cjs +0 -18
- package/lib/presets/max.cjs +0 -27
- package/lib/presets/safe.cjs +0 -65
- package/test.js +0 -23
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import { isComment } from '../helpers.mjs';
|
|
2
|
-
|
|
3
|
-
const noWhitespaceCollapseElements = new Set([
|
|
4
|
-
'script',
|
|
5
|
-
'style',
|
|
6
|
-
'pre',
|
|
7
|
-
'textarea'
|
|
8
|
-
]);
|
|
9
|
-
|
|
10
|
-
const noTrimWhitespacesArroundElements = new Set([
|
|
11
|
-
// non-empty tags that will maintain whitespace around them
|
|
12
|
-
'a', 'abbr', 'acronym', 'b', 'bdi', 'bdo', 'big', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'ins', 'kbd', 'label', 'mark', 'math', 'nobr', 'object', 'q', 'rp', 'rt', 'rtc', 'ruby', 's', 'samp', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'svg', 'textarea', 'time', 'tt', 'u', 'var',
|
|
13
|
-
// self-closing tags that will maintain whitespace around them
|
|
14
|
-
'comment', 'img', 'input', 'wbr'
|
|
15
|
-
]);
|
|
16
|
-
|
|
17
|
-
const noTrimWhitespacesInsideElements = new Set([
|
|
18
|
-
// non-empty tags that will maintain whitespace within them
|
|
19
|
-
'a', 'abbr', 'acronym', 'b', 'big', 'del', 'em', 'font', 'i', 'ins', 'kbd', 'mark', 'nobr', 'rp', 's', 'samp', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'time', 'tt', 'u', 'var'
|
|
20
|
-
]);
|
|
21
|
-
|
|
22
|
-
const startsWithWhitespacePattern = /^\s/;
|
|
23
|
-
const endsWithWhitespacePattern = /\s$/;
|
|
24
|
-
// See https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace and https://infra.spec.whatwg.org/#ascii-whitespace
|
|
25
|
-
const multipleWhitespacePattern = /[\t\n\f\r ]+/g;
|
|
26
|
-
const NONE = '';
|
|
27
|
-
const SINGLE_SPACE = ' ';
|
|
28
|
-
const validOptions = ['all', 'aggressive', 'conservative'];
|
|
29
|
-
|
|
30
|
-
/** Collapses redundant whitespaces */
|
|
31
|
-
export default function collapseWhitespace(tree, options, collapseType, parent) {
|
|
32
|
-
collapseType = validOptions.includes(collapseType) ? collapseType : 'conservative';
|
|
33
|
-
|
|
34
|
-
tree.forEach((node, index) => {
|
|
35
|
-
const prevNode = tree[index - 1];
|
|
36
|
-
const nextNode = tree[index + 1];
|
|
37
|
-
|
|
38
|
-
if (typeof node === 'string') {
|
|
39
|
-
const parentNodeTag = parent && parent.node && parent.node.tag;
|
|
40
|
-
const isTopLevel = !parentNodeTag || parentNodeTag === 'html' || parentNodeTag === 'head';
|
|
41
|
-
const shouldTrim = (
|
|
42
|
-
collapseType === 'all' ||
|
|
43
|
-
isTopLevel ||
|
|
44
|
-
/*
|
|
45
|
-
* When collapseType is set to 'aggressive', and the tag is not inside 'noTrimWhitespacesInsideElements'.
|
|
46
|
-
* the first & last space inside the tag will be trimmed
|
|
47
|
-
*/
|
|
48
|
-
collapseType === 'aggressive'
|
|
49
|
-
);
|
|
50
|
-
|
|
51
|
-
node = collapseRedundantWhitespaces(node, collapseType, shouldTrim, parent, prevNode, nextNode);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const isAllowCollapseWhitespace = !noWhitespaceCollapseElements.has(node.tag);
|
|
55
|
-
if (node.content && node.content.length && isAllowCollapseWhitespace) {
|
|
56
|
-
node.content = collapseWhitespace(node.content, options, collapseType, {
|
|
57
|
-
node,
|
|
58
|
-
prevNode,
|
|
59
|
-
nextNode
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
tree[index] = node;
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
return tree;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
function collapseRedundantWhitespaces(text, collapseType, shouldTrim = false, parent, prevNode, nextNode) {
|
|
71
|
-
if (!text || text.length === 0) {
|
|
72
|
-
return NONE;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if (!isComment(text)) {
|
|
76
|
-
text = text.replace(multipleWhitespacePattern, SINGLE_SPACE);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (shouldTrim) {
|
|
80
|
-
if (collapseType === 'aggressive') {
|
|
81
|
-
if (!noTrimWhitespacesInsideElements.has(parent && parent.node && parent.node.tag)) {
|
|
82
|
-
if (
|
|
83
|
-
// It is the first child node of the parent
|
|
84
|
-
!prevNode
|
|
85
|
-
// It is not the first child node, and prevNode not a text node, and prevNode is safe to trim around
|
|
86
|
-
|| prevNode && prevNode.tag && !noTrimWhitespacesArroundElements.has(prevNode.tag)
|
|
87
|
-
) {
|
|
88
|
-
text = text.trimStart();
|
|
89
|
-
} else {
|
|
90
|
-
// previous node is a "no trim whitespaces arround element"
|
|
91
|
-
if (
|
|
92
|
-
// but previous node ends with a whitespace
|
|
93
|
-
prevNode && prevNode.content && prevNode.content.length
|
|
94
|
-
&& endsWithWhitespacePattern.test(prevNode.content[prevNode.content.length - 1])
|
|
95
|
-
&& (
|
|
96
|
-
!nextNode // either the current node is the last child of the parent
|
|
97
|
-
|| (
|
|
98
|
-
// or the next node starts with a white space
|
|
99
|
-
nextNode && nextNode.content && nextNode.content.length
|
|
100
|
-
&& !startsWithWhitespacePattern.test(nextNode.content[0])
|
|
101
|
-
)
|
|
102
|
-
)
|
|
103
|
-
) {
|
|
104
|
-
text = text.trimStart();
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (
|
|
109
|
-
!nextNode
|
|
110
|
-
|| nextNode && nextNode.tag && !noTrimWhitespacesArroundElements.has(nextNode.tag)
|
|
111
|
-
) {
|
|
112
|
-
text = text.trimEnd();
|
|
113
|
-
}
|
|
114
|
-
} else {
|
|
115
|
-
// now it is a textNode inside a "no trim whitespaces inside elements" node
|
|
116
|
-
if (
|
|
117
|
-
!prevNode // it the textnode is the first child of the node
|
|
118
|
-
&& startsWithWhitespacePattern.test(text[0]) // it starts with white space
|
|
119
|
-
&& typeof parent.prevNode === 'string' // the prev of the node is a textNode as well
|
|
120
|
-
&& endsWithWhitespacePattern.test(parent.prevNode[parent.prevNode.length - 1]) // that prev is ends with a white
|
|
121
|
-
) {
|
|
122
|
-
text = text.trimStart();
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
} else {
|
|
126
|
-
// collapseType is 'all', trim spaces
|
|
127
|
-
text = text.trim();
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
return text;
|
|
132
|
-
}
|
package/lib/modules/custom.cjs
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = custom;
|
|
7
|
-
/** Meta-module that runs custom modules */
|
|
8
|
-
function custom(tree, options, customModules) {
|
|
9
|
-
if (!customModules) {
|
|
10
|
-
return tree;
|
|
11
|
-
}
|
|
12
|
-
if (!Array.isArray(customModules)) {
|
|
13
|
-
customModules = [customModules];
|
|
14
|
-
}
|
|
15
|
-
customModules.forEach(customModule => {
|
|
16
|
-
tree = customModule(tree, options);
|
|
17
|
-
});
|
|
18
|
-
return tree;
|
|
19
|
-
}
|
package/lib/modules/custom.mjs
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/** Meta-module that runs custom modules */
|
|
2
|
-
export default function custom(tree, options, customModules) {
|
|
3
|
-
if (! customModules) {
|
|
4
|
-
return tree;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
if (! Array.isArray(customModules)) {
|
|
8
|
-
customModules = [customModules];
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
customModules.forEach(customModule => {
|
|
12
|
-
tree = customModule(tree, options);
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
return tree;
|
|
16
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.onAttrs = onAttrs;
|
|
7
|
-
var _collapseAttributeWhitespace = require("./collapseAttributeWhitespace.cjs");
|
|
8
|
-
/** Deduplicate values inside list-like attributes (e.g. class, rel) */
|
|
9
|
-
function onAttrs() {
|
|
10
|
-
return attrs => {
|
|
11
|
-
const newAttrs = attrs;
|
|
12
|
-
Object.keys(attrs).forEach(attrName => {
|
|
13
|
-
if (!_collapseAttributeWhitespace.attributesWithLists.has(attrName)) {
|
|
14
|
-
return;
|
|
15
|
-
}
|
|
16
|
-
if (typeof attrs[attrName] !== 'string') {
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
const attrValues = attrs[attrName].split(/\s/);
|
|
20
|
-
const uniqeAttrValues = new Set();
|
|
21
|
-
const deduplicatedAttrValues = [];
|
|
22
|
-
attrValues.forEach(attrValue => {
|
|
23
|
-
if (!attrValue) {
|
|
24
|
-
// Keep whitespaces
|
|
25
|
-
deduplicatedAttrValues.push('');
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
if (uniqeAttrValues.has(attrValue)) {
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
deduplicatedAttrValues.push(attrValue);
|
|
32
|
-
uniqeAttrValues.add(attrValue);
|
|
33
|
-
});
|
|
34
|
-
newAttrs[attrName] = deduplicatedAttrValues.join(' ');
|
|
35
|
-
});
|
|
36
|
-
return newAttrs;
|
|
37
|
-
};
|
|
38
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { attributesWithLists } from './collapseAttributeWhitespace.mjs';
|
|
2
|
-
|
|
3
|
-
/** Deduplicate values inside list-like attributes (e.g. class, rel) */
|
|
4
|
-
export function onAttrs() {
|
|
5
|
-
return (attrs) => {
|
|
6
|
-
const newAttrs = attrs;
|
|
7
|
-
Object.keys(attrs).forEach(attrName => {
|
|
8
|
-
if (! attributesWithLists.has(attrName)) {
|
|
9
|
-
return;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
if (typeof attrs[attrName] !== 'string') {
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const attrValues = attrs[attrName].split(/\s/);
|
|
17
|
-
const uniqeAttrValues = new Set();
|
|
18
|
-
const deduplicatedAttrValues = [];
|
|
19
|
-
|
|
20
|
-
attrValues.forEach((attrValue) => {
|
|
21
|
-
if (! attrValue) {
|
|
22
|
-
// Keep whitespaces
|
|
23
|
-
deduplicatedAttrValues.push('');
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
if (uniqeAttrValues.has(attrValue)) {
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
deduplicatedAttrValues.push(attrValue);
|
|
32
|
-
uniqeAttrValues.add(attrValue);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
newAttrs[attrName] = deduplicatedAttrValues.join(' ');
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
return newAttrs;
|
|
39
|
-
};
|
|
40
|
-
}
|
package/lib/modules/example.cjs
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = example;
|
|
7
|
-
exports.onAttrs = onAttrs;
|
|
8
|
-
exports.onContent = onContent;
|
|
9
|
-
exports.onNode = onNode;
|
|
10
|
-
/**
|
|
11
|
-
* It is an example htmlnano module.
|
|
12
|
-
*
|
|
13
|
-
* A htmlnano module can be modify the attributes of every node (through a "onAttrs" named export),
|
|
14
|
-
* modify the content of every node (through an optional "onContent" named export), modify the node
|
|
15
|
-
* itself (through an optional "onNode" named export), or modify the entire tree (through an optional
|
|
16
|
-
* default export).
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Modify attributes of node. Optional.
|
|
21
|
-
*
|
|
22
|
-
* @param {object} options - Options that were passed to htmlnano
|
|
23
|
-
* @param moduleOptions — Module options. For most modules this is just "true" (indication that the module was enabled)
|
|
24
|
-
* @return {Function} - Return a function that takes attribute object and the node (for the context), and returns the modified attribute object
|
|
25
|
-
*/
|
|
26
|
-
function onAttrs(options, moduleOptions) {
|
|
27
|
-
return (attrs, node) => {
|
|
28
|
-
// You can modify "attrs" based on "node"
|
|
29
|
-
const newAttrs = {
|
|
30
|
-
...attrs
|
|
31
|
-
};
|
|
32
|
-
return newAttrs; // ... then return the modified attrs
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Modify content of node. Optional.
|
|
38
|
-
*
|
|
39
|
-
* @param {object} options - Options that were passed to htmlnano
|
|
40
|
-
* @param moduleOptions — Module options. For most modules this is just "true" (indication that the module was enabled)
|
|
41
|
-
* @return {Function} - Return a function that takes contents (an array of node and string) and the node (for the context), and returns the modified content array.
|
|
42
|
-
*/
|
|
43
|
-
function onContent(options, moduleOptions) {
|
|
44
|
-
return (content, node) => {
|
|
45
|
-
// Same goes the "content"
|
|
46
|
-
|
|
47
|
-
return content; // ... return modified content here
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* It is possible to modify entire ndde as well. Optional.
|
|
53
|
-
* @param {object} options - Options that were passed to htmlnano
|
|
54
|
-
* @param moduleOptions — Module options. For most modules this is just "true" (indication that the module was enabled)
|
|
55
|
-
* @return {Function} - Return a function that takes the node, and returns the new, modified node.
|
|
56
|
-
*/
|
|
57
|
-
function onNode(options, moduleOptions) {
|
|
58
|
-
return node => {
|
|
59
|
-
return node; // ... return new node here
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Modify the entire tree. Optional.
|
|
65
|
-
*
|
|
66
|
-
* @param {object} tree - PostHTML tree (https://github.com/posthtml/posthtml/blob/master/README.md)
|
|
67
|
-
* @param {object} options - Options that were passed to htmlnano
|
|
68
|
-
* @param moduleOptions — Module options. For most modules this is just "true" (indication that the module was enabled)
|
|
69
|
-
* @return {object | Proimse} - Return the modified tree.
|
|
70
|
-
*/
|
|
71
|
-
function example(tree, options, moduleOptions) {
|
|
72
|
-
// Module filename (example.es6), exported default function name (example),
|
|
73
|
-
// and test filename (example.js) must be the same.
|
|
74
|
-
|
|
75
|
-
// You can traverse the tree...
|
|
76
|
-
tree.walk(node => {
|
|
77
|
-
// ...and make some minification
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
// At the end you must return the tree
|
|
81
|
-
return tree;
|
|
82
|
-
|
|
83
|
-
// Or a promise with the tree
|
|
84
|
-
return somePromise.then(() => tree);
|
|
85
|
-
}
|
package/lib/modules/example.mjs
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* It is an example htmlnano module.
|
|
3
|
-
*
|
|
4
|
-
* A htmlnano module can be modify the attributes of every node (through a "onAttrs" named export),
|
|
5
|
-
* modify the content of every node (through an optional "onContent" named export), modify the node
|
|
6
|
-
* itself (through an optional "onNode" named export), or modify the entire tree (through an optional
|
|
7
|
-
* default export).
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Modify attributes of node. Optional.
|
|
12
|
-
*
|
|
13
|
-
* @param {object} options - Options that were passed to htmlnano
|
|
14
|
-
* @param moduleOptions — Module options. For most modules this is just "true" (indication that the module was enabled)
|
|
15
|
-
* @return {Function} - Return a function that takes attribute object and the node (for the context), and returns the modified attribute object
|
|
16
|
-
*/
|
|
17
|
-
export function onAttrs(options, moduleOptions) {
|
|
18
|
-
return (attrs, node) => {
|
|
19
|
-
// You can modify "attrs" based on "node"
|
|
20
|
-
const newAttrs = { ...attrs };
|
|
21
|
-
|
|
22
|
-
return newAttrs; // ... then return the modified attrs
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Modify content of node. Optional.
|
|
28
|
-
*
|
|
29
|
-
* @param {object} options - Options that were passed to htmlnano
|
|
30
|
-
* @param moduleOptions — Module options. For most modules this is just "true" (indication that the module was enabled)
|
|
31
|
-
* @return {Function} - Return a function that takes contents (an array of node and string) and the node (for the context), and returns the modified content array.
|
|
32
|
-
*/
|
|
33
|
-
export function onContent(options, moduleOptions) {
|
|
34
|
-
return (content, node) => {
|
|
35
|
-
// Same goes the "content"
|
|
36
|
-
|
|
37
|
-
return content; // ... return modified content here
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* It is possible to modify entire ndde as well. Optional.
|
|
43
|
-
* @param {object} options - Options that were passed to htmlnano
|
|
44
|
-
* @param moduleOptions — Module options. For most modules this is just "true" (indication that the module was enabled)
|
|
45
|
-
* @return {Function} - Return a function that takes the node, and returns the new, modified node.
|
|
46
|
-
*/
|
|
47
|
-
export function onNode(options, moduleOptions) {
|
|
48
|
-
return (node) => {
|
|
49
|
-
return node; // ... return new node here
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Modify the entire tree. Optional.
|
|
55
|
-
*
|
|
56
|
-
* @param {object} tree - PostHTML tree (https://github.com/posthtml/posthtml/blob/master/README.md)
|
|
57
|
-
* @param {object} options - Options that were passed to htmlnano
|
|
58
|
-
* @param moduleOptions — Module options. For most modules this is just "true" (indication that the module was enabled)
|
|
59
|
-
* @return {object | Proimse} - Return the modified tree.
|
|
60
|
-
*/
|
|
61
|
-
export default function example(tree, options, moduleOptions) {
|
|
62
|
-
// Module filename (example.es6), exported default function name (example),
|
|
63
|
-
// and test filename (example.js) must be the same.
|
|
64
|
-
|
|
65
|
-
// You can traverse the tree...
|
|
66
|
-
tree.walk(node => {
|
|
67
|
-
// ...and make some minification
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
// At the end you must return the tree
|
|
71
|
-
return tree;
|
|
72
|
-
|
|
73
|
-
// Or a promise with the tree
|
|
74
|
-
return somePromise.then(() => tree);
|
|
75
|
-
}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = mergeScripts;
|
|
7
|
-
/* Merge multiple <script> into one */
|
|
8
|
-
function mergeScripts(tree) {
|
|
9
|
-
let scriptNodesIndex = {};
|
|
10
|
-
let scriptSrcIndex = 1;
|
|
11
|
-
tree.match({
|
|
12
|
-
tag: 'script'
|
|
13
|
-
}, node => {
|
|
14
|
-
const nodeAttrs = node.attrs || {};
|
|
15
|
-
if ('src' in nodeAttrs
|
|
16
|
-
// Skip SRI, reasons are documented in "minifyJs" module
|
|
17
|
-
|| 'integrity' in nodeAttrs) {
|
|
18
|
-
scriptSrcIndex++;
|
|
19
|
-
return node;
|
|
20
|
-
}
|
|
21
|
-
const scriptType = nodeAttrs.type || 'text/javascript';
|
|
22
|
-
if (scriptType !== 'text/javascript' && scriptType !== 'application/javascript') {
|
|
23
|
-
return node;
|
|
24
|
-
}
|
|
25
|
-
const scriptKey = JSON.stringify({
|
|
26
|
-
id: nodeAttrs.id,
|
|
27
|
-
class: nodeAttrs.class,
|
|
28
|
-
type: scriptType,
|
|
29
|
-
defer: nodeAttrs.defer !== undefined,
|
|
30
|
-
async: nodeAttrs.async !== undefined,
|
|
31
|
-
index: scriptSrcIndex
|
|
32
|
-
});
|
|
33
|
-
if (!scriptNodesIndex[scriptKey]) {
|
|
34
|
-
scriptNodesIndex[scriptKey] = [];
|
|
35
|
-
}
|
|
36
|
-
scriptNodesIndex[scriptKey].push(node);
|
|
37
|
-
return node;
|
|
38
|
-
});
|
|
39
|
-
for (const scriptNodes of Object.values(scriptNodesIndex)) {
|
|
40
|
-
let lastScriptNode = scriptNodes.pop();
|
|
41
|
-
scriptNodes.reverse().forEach(scriptNode => {
|
|
42
|
-
let scriptContent = (scriptNode.content || []).join(' ');
|
|
43
|
-
scriptContent = scriptContent.trim();
|
|
44
|
-
if (scriptContent.slice(-1) !== ';') {
|
|
45
|
-
scriptContent += ';';
|
|
46
|
-
}
|
|
47
|
-
lastScriptNode.content = lastScriptNode.content || [];
|
|
48
|
-
lastScriptNode.content.unshift(scriptContent);
|
|
49
|
-
scriptNode.tag = false;
|
|
50
|
-
scriptNode.content = [];
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
return tree;
|
|
54
|
-
}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
/* Merge multiple <script> into one */
|
|
2
|
-
export default function mergeScripts (tree) {
|
|
3
|
-
let scriptNodesIndex = {};
|
|
4
|
-
let scriptSrcIndex = 1;
|
|
5
|
-
|
|
6
|
-
tree.match({ tag: 'script' }, node => {
|
|
7
|
-
const nodeAttrs = node.attrs || {};
|
|
8
|
-
if (
|
|
9
|
-
'src' in nodeAttrs
|
|
10
|
-
// Skip SRI, reasons are documented in "minifyJs" module
|
|
11
|
-
|| 'integrity' in nodeAttrs
|
|
12
|
-
) {
|
|
13
|
-
scriptSrcIndex++;
|
|
14
|
-
return node;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const scriptType = nodeAttrs.type || 'text/javascript';
|
|
18
|
-
if (scriptType !== 'text/javascript' && scriptType !== 'application/javascript') {
|
|
19
|
-
return node;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const scriptKey = JSON.stringify({
|
|
23
|
-
id: nodeAttrs.id,
|
|
24
|
-
class: nodeAttrs.class,
|
|
25
|
-
type: scriptType,
|
|
26
|
-
defer: nodeAttrs.defer !== undefined,
|
|
27
|
-
async: nodeAttrs.async !== undefined,
|
|
28
|
-
index: scriptSrcIndex,
|
|
29
|
-
});
|
|
30
|
-
if (!scriptNodesIndex[scriptKey]) {
|
|
31
|
-
scriptNodesIndex[scriptKey] = [];
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
scriptNodesIndex[scriptKey].push(node);
|
|
35
|
-
return node;
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
for (const scriptNodes of Object.values(scriptNodesIndex)) {
|
|
39
|
-
let lastScriptNode = scriptNodes.pop();
|
|
40
|
-
scriptNodes.reverse().forEach(scriptNode => {
|
|
41
|
-
let scriptContent = (scriptNode.content || []).join(' ');
|
|
42
|
-
scriptContent = scriptContent.trim();
|
|
43
|
-
if (scriptContent.slice(-1) !== ';') {
|
|
44
|
-
scriptContent += ';';
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
lastScriptNode.content = lastScriptNode.content || [];
|
|
48
|
-
lastScriptNode.content.unshift(scriptContent);
|
|
49
|
-
|
|
50
|
-
scriptNode.tag = false;
|
|
51
|
-
scriptNode.content = [];
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return tree;
|
|
56
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = mergeStyles;
|
|
7
|
-
var _helpers = require("../helpers.cjs");
|
|
8
|
-
/* Merge multiple <style> into one */
|
|
9
|
-
function mergeStyles(tree) {
|
|
10
|
-
const styleNodes = {};
|
|
11
|
-
tree.match({
|
|
12
|
-
tag: 'style'
|
|
13
|
-
}, node => {
|
|
14
|
-
const nodeAttrs = node.attrs || {};
|
|
15
|
-
// Skip <style scoped></style>
|
|
16
|
-
// https://developer.mozilla.org/en/docs/Web/HTML/Element/style
|
|
17
|
-
//
|
|
18
|
-
// Also skip SRI, reasons are documented in "minifyJs" module
|
|
19
|
-
if ('scoped' in nodeAttrs || 'integrity' in nodeAttrs) {
|
|
20
|
-
return node;
|
|
21
|
-
}
|
|
22
|
-
if ((0, _helpers.isAmpBoilerplate)(node)) {
|
|
23
|
-
return node;
|
|
24
|
-
}
|
|
25
|
-
const styleType = nodeAttrs.type || 'text/css';
|
|
26
|
-
const styleMedia = nodeAttrs.media || 'all';
|
|
27
|
-
const styleKey = styleType + '_' + styleMedia;
|
|
28
|
-
if (styleNodes[styleKey]) {
|
|
29
|
-
const styleContent = (node.content || []).join(' ');
|
|
30
|
-
styleNodes[styleKey].content.push(' ' + styleContent);
|
|
31
|
-
return '';
|
|
32
|
-
}
|
|
33
|
-
node.content = node.content || [];
|
|
34
|
-
styleNodes[styleKey] = node;
|
|
35
|
-
return node;
|
|
36
|
-
});
|
|
37
|
-
return tree;
|
|
38
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { isAmpBoilerplate } from '../helpers.mjs';
|
|
2
|
-
|
|
3
|
-
/* Merge multiple <style> into one */
|
|
4
|
-
export default function mergeStyles(tree) {
|
|
5
|
-
const styleNodes = {};
|
|
6
|
-
|
|
7
|
-
tree.match({tag: 'style'}, node => {
|
|
8
|
-
const nodeAttrs = node.attrs || {};
|
|
9
|
-
// Skip <style scoped></style>
|
|
10
|
-
// https://developer.mozilla.org/en/docs/Web/HTML/Element/style
|
|
11
|
-
//
|
|
12
|
-
// Also skip SRI, reasons are documented in "minifyJs" module
|
|
13
|
-
if ('scoped' in nodeAttrs || 'integrity' in nodeAttrs) {
|
|
14
|
-
return node;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
if (isAmpBoilerplate(node)) {
|
|
18
|
-
return node;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const styleType = nodeAttrs.type || 'text/css';
|
|
22
|
-
const styleMedia = nodeAttrs.media || 'all';
|
|
23
|
-
const styleKey = styleType + '_' + styleMedia;
|
|
24
|
-
if (styleNodes[styleKey]) {
|
|
25
|
-
const styleContent = (node.content || []).join(' ');
|
|
26
|
-
styleNodes[styleKey].content.push(' ' + styleContent);
|
|
27
|
-
return '';
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
node.content = node.content || [];
|
|
31
|
-
styleNodes[styleKey] = node;
|
|
32
|
-
return node;
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
return tree;
|
|
36
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = minifyConditionalComments;
|
|
7
|
-
var _htmlnano = _interopRequireDefault(require("../htmlnano.cjs"));
|
|
8
|
-
var _helpers = require("../helpers.cjs");
|
|
9
|
-
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
|
-
// Spec: https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/compatibility/ms537512(v=vs.85)
|
|
11
|
-
const CONDITIONAL_COMMENT_REGEXP = /(<!--\[if\s+?[^<>[\]]+?]>)([\s\S]+?)(<!\[endif\]-->)/gm;
|
|
12
|
-
|
|
13
|
-
/** Minify content inside conditional comments */
|
|
14
|
-
async function minifyConditionalComments(tree, htmlnanoOptions) {
|
|
15
|
-
// forEach, tree.walk, tree.match just don't support Promise.
|
|
16
|
-
for (let i = 0, len = tree.length; i < len; i++) {
|
|
17
|
-
const node = tree[i];
|
|
18
|
-
if (typeof node === 'string' && (0, _helpers.isConditionalComment)(node)) {
|
|
19
|
-
tree[i] = await minifycontentInsideConditionalComments(node, htmlnanoOptions);
|
|
20
|
-
}
|
|
21
|
-
if (node.content && node.content.length) {
|
|
22
|
-
tree[i].content = await minifyConditionalComments(node.content, htmlnanoOptions);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
return tree;
|
|
26
|
-
}
|
|
27
|
-
async function minifycontentInsideConditionalComments(text, htmlnanoOptions) {
|
|
28
|
-
let match;
|
|
29
|
-
const matches = [];
|
|
30
|
-
|
|
31
|
-
// FIXME!
|
|
32
|
-
// String#matchAll is supported since Node.js 12
|
|
33
|
-
while ((match = CONDITIONAL_COMMENT_REGEXP.exec(text)) !== null) {
|
|
34
|
-
matches.push([match[1], match[2], match[3]]);
|
|
35
|
-
}
|
|
36
|
-
if (!matches.length) {
|
|
37
|
-
return Promise.resolve(text);
|
|
38
|
-
}
|
|
39
|
-
return Promise.all(matches.map(async match => {
|
|
40
|
-
const result = await _htmlnano.default.process(match[1], htmlnanoOptions, {}, {});
|
|
41
|
-
let minified = result.html;
|
|
42
|
-
if (match[1].includes('<html') && minified.includes('</html>')) {
|
|
43
|
-
minified = minified.replace('</html>', '');
|
|
44
|
-
}
|
|
45
|
-
return match[0] + minified + match[2];
|
|
46
|
-
}));
|
|
47
|
-
}
|