htmlnano 2.0.4 → 2.1.1
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 +3 -2
- package/CHANGELOG.md +19 -0
- package/docs/docs/040-presets.md +4 -4
- package/docs/docs/050-modules.md +1 -1
- package/docs/docs/060-contribute.md +1 -1
- package/docs/docusaurus.config.js +5 -0
- package/docs/package-lock.json +563 -326
- package/docs/package.json +1 -0
- package/docs/versioned_docs/version-1.1.1/040-presets.md +4 -4
- package/docs/versioned_docs/version-1.1.1/050-modules.md +1 -2
- package/docs/versioned_docs/version-1.1.1/060-contribute.md +1 -1
- package/docs/versioned_docs/version-2.0.0/040-presets.md +4 -4
- package/docs/versioned_docs/version-2.0.0/050-modules.md +1 -1
- package/docs/versioned_docs/version-2.0.0/060-contribute.md +1 -1
- package/index.cjs +11 -0
- package/index.d.cts +3 -0
- package/index.d.mts +3 -0
- package/index.d.ts +3 -3
- package/index.mjs +2 -0
- package/lib/helpers.cjs +79 -0
- package/lib/helpers.mjs +53 -0
- package/lib/htmlnano.cjs +200 -0
- package/lib/htmlnano.mjs +196 -0
- package/lib/modules/{collapseAttributeWhitespace.js → collapseAttributeWhitespace.cjs} +2 -3
- package/lib/modules/collapseAttributeWhitespace.mjs +104 -0
- package/lib/modules/collapseBooleanAttributes.mjs +175 -0
- package/lib/modules/{collapseWhitespace.js → collapseWhitespace.cjs} +3 -2
- package/lib/modules/collapseWhitespace.mjs +132 -0
- package/lib/modules/custom.mjs +16 -0
- package/lib/modules/{deduplicateAttributeValues.js → deduplicateAttributeValues.cjs} +1 -1
- package/lib/modules/deduplicateAttributeValues.mjs +40 -0
- package/lib/modules/example.cjs +85 -0
- package/lib/modules/example.mjs +75 -0
- package/lib/modules/mergeScripts.mjs +56 -0
- package/lib/modules/{mergeStyles.js → mergeStyles.cjs} +1 -1
- package/lib/modules/mergeStyles.mjs +36 -0
- package/lib/modules/{minifyConditionalComments.js → minifyConditionalComments.cjs} +2 -2
- package/lib/modules/minifyConditionalComments.mjs +49 -0
- package/lib/modules/{minifyCss.js → minifyCss.cjs} +8 -8
- package/lib/modules/minifyCss.mjs +88 -0
- package/lib/modules/{minifyJs.js → minifyJs.cjs} +8 -9
- package/lib/modules/minifyJs.mjs +121 -0
- package/lib/modules/minifyJson.mjs +21 -0
- package/lib/modules/{minifySvg.js → minifySvg.cjs} +3 -4
- package/lib/modules/minifySvg.mjs +30 -0
- package/lib/modules/{minifyUrls.js → minifyUrls.cjs} +11 -12
- package/lib/modules/minifyUrls.mjs +229 -0
- package/lib/modules/normalizeAttributeValues.mjs +140 -0
- package/lib/modules/removeAttributeQuotes.mjs +12 -0
- package/lib/modules/{removeComments.js → removeComments.cjs} +1 -1
- package/lib/modules/removeComments.mjs +92 -0
- package/lib/modules/{removeEmptyAttributes.js → removeEmptyAttributes.cjs} +1 -1
- package/lib/modules/removeEmptyAttributes.mjs +121 -0
- package/lib/modules/{removeOptionalTags.js → removeOptionalTags.cjs} +1 -1
- package/lib/modules/removeOptionalTags.mjs +225 -0
- package/lib/modules/{removeRedundantAttributes.js → removeRedundantAttributes.cjs} +1 -2
- package/lib/modules/removeRedundantAttributes.mjs +141 -0
- package/lib/modules/{removeUnusedCss.js → removeUnusedCss.cjs} +12 -13
- package/lib/modules/removeUnusedCss.mjs +122 -0
- package/lib/modules/{sortAttributes.js → sortAttributes.cjs} +0 -1
- package/lib/modules/sortAttributes.mjs +121 -0
- package/lib/modules/{sortAttributesWithLists.js → sortAttributesWithLists.cjs} +1 -2
- package/lib/modules/sortAttributesWithLists.mjs +135 -0
- package/lib/presets/{ampSafe.js → ampSafe.cjs} +4 -9
- package/lib/presets/ampSafe.mjs +11 -0
- package/lib/presets/{max.js → max.cjs} +4 -9
- package/lib/presets/max.mjs +20 -0
- package/lib/presets/{safe.js → safe.cjs} +2 -3
- package/lib/presets/safe.mjs +65 -0
- package/package.json +40 -12
- package/index.js +0 -1
- package/lib/helpers.js +0 -53
- package/lib/htmlnano.js +0 -150
- /package/lib/modules/{collapseBooleanAttributes.js → collapseBooleanAttributes.cjs} +0 -0
- /package/lib/modules/{custom.js → custom.cjs} +0 -0
- /package/lib/modules/{mergeScripts.js → mergeScripts.cjs} +0 -0
- /package/lib/modules/{minifyJson.js → minifyJson.cjs} +0 -0
- /package/lib/modules/{normalizeAttributeValues.js → normalizeAttributeValues.cjs} +0 -0
- /package/lib/modules/{removeAttributeQuotes.js → removeAttributeQuotes.cjs} +0 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { isStyleNode, extractCssFromStyleNode, optionalImport } from '../helpers.mjs';
|
|
2
|
+
|
|
3
|
+
// These options must be set and shouldn't be overriden to ensure uncss doesn't look at linked stylesheets.
|
|
4
|
+
const uncssOptions = {
|
|
5
|
+
ignoreSheets: [/\s*/],
|
|
6
|
+
stylesheets: [],
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
function processStyleNodeUnCSS(html, styleNode, uncssOptions, uncss) {
|
|
10
|
+
const css = extractCssFromStyleNode(styleNode);
|
|
11
|
+
|
|
12
|
+
return runUncss(html, css, uncssOptions, uncss).then(css => {
|
|
13
|
+
// uncss may have left some style tags empty
|
|
14
|
+
if (css.trim().length === 0) {
|
|
15
|
+
styleNode.tag = false;
|
|
16
|
+
styleNode.content = [];
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
styleNode.content = [css];
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function runUncss(html, css, userOptions, uncss) {
|
|
24
|
+
if (typeof userOptions !== 'object') {
|
|
25
|
+
userOptions = {};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const options = { ...userOptions, ...uncssOptions };
|
|
29
|
+
return new Promise((resolve, reject) => {
|
|
30
|
+
options.raw = css;
|
|
31
|
+
uncss(html, options, (error, output) => {
|
|
32
|
+
if (error) {
|
|
33
|
+
reject(error);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
resolve(output);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const purgeFromHtml = function (tree) {
|
|
42
|
+
// content is not used as we can directly used the parsed HTML,
|
|
43
|
+
// making the process faster
|
|
44
|
+
const selectors = [];
|
|
45
|
+
|
|
46
|
+
tree.walk(node => {
|
|
47
|
+
const classes = node.attrs && node.attrs.class && node.attrs.class.split(' ') || [];
|
|
48
|
+
const ids = node.attrs && node.attrs.id && node.attrs.id.split(' ') || [];
|
|
49
|
+
selectors.push(...classes, ...ids);
|
|
50
|
+
node.tag && selectors.push(node.tag);
|
|
51
|
+
return node;
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
return () => selectors;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
function processStyleNodePurgeCSS(tree, styleNode, purgecssOptions, purgecss) {
|
|
58
|
+
const css = extractCssFromStyleNode(styleNode);
|
|
59
|
+
return runPurgecss(tree, css, purgecssOptions, purgecss)
|
|
60
|
+
.then(css => {
|
|
61
|
+
if (css.trim().length === 0) {
|
|
62
|
+
styleNode.tag = false;
|
|
63
|
+
styleNode.content = [];
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
styleNode.content = [css];
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function runPurgecss(tree, css, userOptions, purgecss) {
|
|
71
|
+
if (typeof userOptions !== 'object') {
|
|
72
|
+
userOptions = {};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const options = {
|
|
76
|
+
...userOptions,
|
|
77
|
+
content: [{
|
|
78
|
+
raw: tree,
|
|
79
|
+
extension: 'html'
|
|
80
|
+
}],
|
|
81
|
+
css: [{
|
|
82
|
+
raw: css,
|
|
83
|
+
extension: 'css'
|
|
84
|
+
}],
|
|
85
|
+
extractors: [{
|
|
86
|
+
extractor: purgeFromHtml(tree),
|
|
87
|
+
extensions: ['html']
|
|
88
|
+
}]
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
return new purgecss.PurgeCSS()
|
|
92
|
+
.purge(options)
|
|
93
|
+
.then((result) => {
|
|
94
|
+
return result[0].css;
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** Remove unused CSS */
|
|
99
|
+
export default async function removeUnusedCss(tree, options, userOptions) {
|
|
100
|
+
const promises = [];
|
|
101
|
+
const html = userOptions.tool !== 'purgeCSS' && tree.render(tree);
|
|
102
|
+
|
|
103
|
+
const purgecss = await optionalImport('purgecss');
|
|
104
|
+
const uncss = await optionalImport('uncss');
|
|
105
|
+
|
|
106
|
+
tree.walk(node => {
|
|
107
|
+
if (isStyleNode(node)) {
|
|
108
|
+
if (userOptions.tool === 'purgeCSS') {
|
|
109
|
+
if (purgecss) {
|
|
110
|
+
promises.push(processStyleNodePurgeCSS(tree, node, userOptions, purgecss));
|
|
111
|
+
}
|
|
112
|
+
} else {
|
|
113
|
+
if (uncss) {
|
|
114
|
+
promises.push(processStyleNodeUnCSS(html, node, userOptions, uncss));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return node;
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
return Promise.all(promises).then(() => tree);
|
|
122
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { sort as timSort } from 'timsort';
|
|
2
|
+
|
|
3
|
+
const validOptions = new Set(['frequency', 'alphabetical']);
|
|
4
|
+
|
|
5
|
+
const processModuleOptions = options => {
|
|
6
|
+
if (options === true) return 'alphabetical';
|
|
7
|
+
|
|
8
|
+
return validOptions.has(options) ? options : false;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
class AttributeTokenChain {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.freqData = new Map(); // <attr, frequency>[]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
addFromNodeAttrs(nodeAttrs) {
|
|
17
|
+
Object.keys(nodeAttrs).forEach(attrName => {
|
|
18
|
+
const attrNameLower = attrName.toLowerCase();
|
|
19
|
+
|
|
20
|
+
if (this.freqData.has(attrNameLower)) {
|
|
21
|
+
this.freqData.set(attrNameLower, this.freqData.get(attrNameLower) + 1);
|
|
22
|
+
} else {
|
|
23
|
+
this.freqData.set(attrNameLower, 1);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
createSortOrder() {
|
|
29
|
+
let _sortOrder = [...this.freqData.entries()];
|
|
30
|
+
timSort(_sortOrder, (a, b) => b[1] - a[1]);
|
|
31
|
+
|
|
32
|
+
this.sortOrder = _sortOrder.map(i => i[0]);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
sortFromNodeAttrs(nodeAttrs) {
|
|
36
|
+
const newAttrs = {};
|
|
37
|
+
|
|
38
|
+
// Convert node.attrs attrName into lower case.
|
|
39
|
+
const loweredNodeAttrs = {};
|
|
40
|
+
Object.entries(nodeAttrs).forEach(([attrName, attrValue]) => {
|
|
41
|
+
loweredNodeAttrs[attrName.toLowerCase()] = attrValue;
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
if (!this.sortOrder) {
|
|
45
|
+
this.createSortOrder();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
this.sortOrder.forEach(attrNameLower => {
|
|
49
|
+
// The attrName inside "sortOrder" has been lowered
|
|
50
|
+
if (loweredNodeAttrs[attrNameLower] != null) {
|
|
51
|
+
newAttrs[attrNameLower] = loweredNodeAttrs[attrNameLower];
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return newAttrs;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Sort attibutes */
|
|
60
|
+
export default function sortAttributes(tree, options, moduleOptions) {
|
|
61
|
+
const sortType = processModuleOptions(moduleOptions);
|
|
62
|
+
|
|
63
|
+
if (sortType === 'alphabetical') {
|
|
64
|
+
return sortAttributesInAlphabeticalOrder(tree);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (sortType === 'frequency') {
|
|
68
|
+
return sortAttributesByFrequency(tree);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Invalid configuration
|
|
72
|
+
return tree;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function sortAttributesInAlphabeticalOrder(tree) {
|
|
76
|
+
tree.walk(node => {
|
|
77
|
+
if (!node.attrs) {
|
|
78
|
+
return node;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const newAttrs = {};
|
|
82
|
+
|
|
83
|
+
Object.keys(node.attrs)
|
|
84
|
+
.sort((a, b) => typeof a.localeCompare === 'function' ? a.localeCompare(b) : a - b)
|
|
85
|
+
.forEach(attr => newAttrs[attr] = node.attrs[attr]);
|
|
86
|
+
|
|
87
|
+
node.attrs = newAttrs;
|
|
88
|
+
|
|
89
|
+
return node;
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
return tree;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function sortAttributesByFrequency(tree) {
|
|
96
|
+
const tokenchain = new AttributeTokenChain();
|
|
97
|
+
|
|
98
|
+
// Traverse through tree to get frequency
|
|
99
|
+
tree.walk(node => {
|
|
100
|
+
if (!node.attrs) {
|
|
101
|
+
return node;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
tokenchain.addFromNodeAttrs(node.attrs);
|
|
105
|
+
|
|
106
|
+
return node;
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// Traverse through tree again, this time sort the attributes
|
|
110
|
+
tree.walk(node => {
|
|
111
|
+
if (!node.attrs) {
|
|
112
|
+
return node;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
node.attrs = tokenchain.sortFromNodeAttrs(node.attrs);
|
|
116
|
+
|
|
117
|
+
return node;
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
return tree;
|
|
121
|
+
}
|
|
@@ -5,7 +5,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.default = collapseAttributeWhitespace;
|
|
7
7
|
var _timsort = require("timsort");
|
|
8
|
-
var _collapseAttributeWhitespace = require("./collapseAttributeWhitespace");
|
|
8
|
+
var _collapseAttributeWhitespace = require("./collapseAttributeWhitespace.cjs");
|
|
9
9
|
// class, rel, ping
|
|
10
10
|
|
|
11
11
|
const validOptions = new Set(['frequency', 'alphabetical']);
|
|
@@ -17,7 +17,6 @@ class AttributeTokenChain {
|
|
|
17
17
|
constructor() {
|
|
18
18
|
this.freqData = new Map(); // <attrValue, frequency>[]
|
|
19
19
|
}
|
|
20
|
-
|
|
21
20
|
addFromNodeAttrsArray(attrValuesArray) {
|
|
22
21
|
attrValuesArray.forEach(attrValue => {
|
|
23
22
|
if (this.freqData.has(attrValue)) {
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// class, rel, ping
|
|
2
|
+
import { sort as timSort } from 'timsort';
|
|
3
|
+
import { attributesWithLists } from './collapseAttributeWhitespace.mjs';
|
|
4
|
+
|
|
5
|
+
const validOptions = new Set(['frequency', 'alphabetical']);
|
|
6
|
+
const processModuleOptions = options => {
|
|
7
|
+
if (options === true) return 'alphabetical';
|
|
8
|
+
|
|
9
|
+
return validOptions.has(options) ? options : false;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
class AttributeTokenChain {
|
|
13
|
+
constructor() {
|
|
14
|
+
this.freqData = new Map(); // <attrValue, frequency>[]
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
addFromNodeAttrsArray(attrValuesArray) {
|
|
18
|
+
attrValuesArray.forEach(attrValue => {
|
|
19
|
+
if (this.freqData.has(attrValue)) {
|
|
20
|
+
this.freqData.set(attrValue, this.freqData.get(attrValue) + 1);
|
|
21
|
+
} else {
|
|
22
|
+
this.freqData.set(attrValue, 1);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
createSortOrder() {
|
|
28
|
+
let _sortOrder = [...this.freqData.entries()];
|
|
29
|
+
timSort(_sortOrder, (a, b) => b[1] - a[1]);
|
|
30
|
+
|
|
31
|
+
this.sortOrder = _sortOrder.map(i => i[0]);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
sortFromNodeAttrsArray(attrValuesArray) {
|
|
35
|
+
const resultArray = [];
|
|
36
|
+
|
|
37
|
+
if (!this.sortOrder) {
|
|
38
|
+
this.createSortOrder();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
this.sortOrder.forEach(k => {
|
|
42
|
+
if (attrValuesArray.includes(k)) {
|
|
43
|
+
resultArray.push(k);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
return resultArray;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Sort values inside list-like attributes (e.g. class, rel) */
|
|
52
|
+
export default function collapseAttributeWhitespace(tree, options, moduleOptions) {
|
|
53
|
+
const sortType = processModuleOptions(moduleOptions);
|
|
54
|
+
|
|
55
|
+
if (sortType === 'alphabetical') {
|
|
56
|
+
return sortAttributesWithListsInAlphabeticalOrder(tree);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (sortType === 'frequency') {
|
|
60
|
+
return sortAttributesWithListsByFrequency(tree);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Invalid configuration
|
|
64
|
+
return tree;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function sortAttributesWithListsInAlphabeticalOrder(tree) {
|
|
68
|
+
tree.walk(node => {
|
|
69
|
+
if (!node.attrs) {
|
|
70
|
+
return node;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
Object.keys(node.attrs).forEach(attrName => {
|
|
74
|
+
const attrNameLower = attrName.toLowerCase();
|
|
75
|
+
if (!attributesWithLists.has(attrNameLower)) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const attrValues = node.attrs[attrName].split(/\s/);
|
|
80
|
+
|
|
81
|
+
node.attrs[attrName] = attrValues.sort((a, b) => {
|
|
82
|
+
return typeof a.localeCompare === 'function' ? a.localeCompare(b) : a - b;
|
|
83
|
+
}).join(' ');
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
return node;
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
return tree;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function sortAttributesWithListsByFrequency(tree) {
|
|
93
|
+
const tokenChainObj = {}; // <attrNameLower: AttributeTokenChain>[]
|
|
94
|
+
|
|
95
|
+
// Traverse through tree to get frequency
|
|
96
|
+
tree.walk(node => {
|
|
97
|
+
if (!node.attrs) {
|
|
98
|
+
return node;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
Object.entries(node.attrs).forEach(([attrName, attrValues]) => {
|
|
102
|
+
const attrNameLower = attrName.toLowerCase();
|
|
103
|
+
|
|
104
|
+
if (!attributesWithLists.has(attrNameLower)) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
tokenChainObj[attrNameLower] = tokenChainObj[attrNameLower] || new AttributeTokenChain();
|
|
109
|
+
tokenChainObj[attrNameLower].addFromNodeAttrsArray(attrValues.split(/\s/));
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
return node;
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// Traverse through tree again, this time sort the attribute values
|
|
116
|
+
tree.walk(node => {
|
|
117
|
+
if (!node.attrs) {
|
|
118
|
+
return node;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
Object.entries(node.attrs).forEach(([attrName, attrValues]) => {
|
|
122
|
+
const attrNameLower = attrName.toLowerCase();
|
|
123
|
+
|
|
124
|
+
if (!attributesWithLists.has(attrNameLower)) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (tokenChainObj[attrNameLower]) {
|
|
129
|
+
node.attrs[attrName] = tokenChainObj[attrNameLower].sortFromNodeAttrsArray(attrValues.split(/\s/)).join(' ');
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
return node;
|
|
134
|
+
});
|
|
135
|
+
}
|
|
@@ -4,20 +4,15 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
|
-
var _safe = _interopRequireDefault(require("./safe"));
|
|
8
|
-
function _interopRequireDefault(obj) {
|
|
9
|
-
return obj && obj.__esModule ? obj : {
|
|
10
|
-
default: obj
|
|
11
|
-
};
|
|
12
|
-
}
|
|
7
|
+
var _safe = _interopRequireDefault(require("./safe.cjs"));
|
|
8
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
13
9
|
/**
|
|
14
10
|
* A safe preset for AMP pages (https://www.ampproject.org)
|
|
15
11
|
*/
|
|
16
|
-
var _default = {
|
|
12
|
+
var _default = exports.default = {
|
|
17
13
|
..._safe.default,
|
|
18
14
|
collapseBooleanAttributes: {
|
|
19
15
|
amphtml: true
|
|
20
16
|
},
|
|
21
17
|
minifyJs: false
|
|
22
|
-
};
|
|
23
|
-
exports.default = _default;
|
|
18
|
+
};
|
|
@@ -4,16 +4,12 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
|
-
var _safe = _interopRequireDefault(require("./safe"));
|
|
8
|
-
function _interopRequireDefault(obj) {
|
|
9
|
-
return obj && obj.__esModule ? obj : {
|
|
10
|
-
default: obj
|
|
11
|
-
};
|
|
12
|
-
}
|
|
7
|
+
var _safe = _interopRequireDefault(require("./safe.cjs"));
|
|
8
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
13
9
|
/**
|
|
14
10
|
* Maximal minification (might break some pages)
|
|
15
11
|
*/
|
|
16
|
-
var _default = {
|
|
12
|
+
var _default = exports.default = {
|
|
17
13
|
..._safe.default,
|
|
18
14
|
collapseWhitespace: 'all',
|
|
19
15
|
removeComments: 'all',
|
|
@@ -28,5 +24,4 @@ var _default = {
|
|
|
28
24
|
minifySvg: {},
|
|
29
25
|
minifyConditionalComments: true,
|
|
30
26
|
removeOptionalTags: true
|
|
31
|
-
};
|
|
32
|
-
exports.default = _default;
|
|
27
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import safePreset from './safe.mjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Maximal minification (might break some pages)
|
|
5
|
+
*/
|
|
6
|
+
export default { ...safePreset,
|
|
7
|
+
collapseWhitespace: 'all',
|
|
8
|
+
removeComments: 'all',
|
|
9
|
+
removeAttributeQuotes: true,
|
|
10
|
+
removeRedundantAttributes: true,
|
|
11
|
+
mergeScripts: true,
|
|
12
|
+
mergeStyles: true,
|
|
13
|
+
removeUnusedCss: {},
|
|
14
|
+
minifyCss: {
|
|
15
|
+
preset: 'default',
|
|
16
|
+
},
|
|
17
|
+
minifySvg: {},
|
|
18
|
+
minifyConditionalComments: true,
|
|
19
|
+
removeOptionalTags: true,
|
|
20
|
+
};
|
|
@@ -7,7 +7,7 @@ exports.default = void 0;
|
|
|
7
7
|
/**
|
|
8
8
|
* Minify HTML in a safe way without breaking anything.
|
|
9
9
|
*/
|
|
10
|
-
var _default = {
|
|
10
|
+
var _default = exports.default = {
|
|
11
11
|
/* ----------------------------------------
|
|
12
12
|
* Attributes
|
|
13
13
|
* ---------------------------------------- */
|
|
@@ -62,5 +62,4 @@ var _default = {
|
|
|
62
62
|
* Miscellaneous
|
|
63
63
|
* ---------------------------------------- */
|
|
64
64
|
custom: []
|
|
65
|
-
};
|
|
66
|
-
exports.default = _default;
|
|
65
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minify HTML in a safe way without breaking anything.
|
|
3
|
+
*/
|
|
4
|
+
export default {
|
|
5
|
+
/* ----------------------------------------
|
|
6
|
+
* Attributes
|
|
7
|
+
* ---------------------------------------- */
|
|
8
|
+
// normalize the case of attribute names and values
|
|
9
|
+
// normalizeAttributeValues will also normalize property value with invalid value default
|
|
10
|
+
// See https://html.spec.whatwg.org/#invalid-value-default
|
|
11
|
+
normalizeAttributeValues: true,
|
|
12
|
+
removeEmptyAttributes: true,
|
|
13
|
+
collapseAttributeWhitespace: true,
|
|
14
|
+
// removeRedundantAttributes will remove attributes when missing value default matches the attribute's value
|
|
15
|
+
// See https://html.spec.whatwg.org/#missing-value-default
|
|
16
|
+
removeRedundantAttributes: false,
|
|
17
|
+
// collapseBooleanAttributes will also collapse those default state can be omitted
|
|
18
|
+
collapseBooleanAttributes: {
|
|
19
|
+
amphtml: false,
|
|
20
|
+
},
|
|
21
|
+
deduplicateAttributeValues: true,
|
|
22
|
+
|
|
23
|
+
minifyUrls: false,
|
|
24
|
+
|
|
25
|
+
sortAttributes: false,
|
|
26
|
+
sortAttributesWithLists: 'alphabetical',
|
|
27
|
+
|
|
28
|
+
/* ----------------------------------------
|
|
29
|
+
* Minify HTML content
|
|
30
|
+
* ---------------------------------------- */
|
|
31
|
+
collapseWhitespace: 'conservative',
|
|
32
|
+
removeComments: 'safe',
|
|
33
|
+
minifyConditionalComments: false,
|
|
34
|
+
removeOptionalTags: false,
|
|
35
|
+
removeAttributeQuotes: false,
|
|
36
|
+
/* ----------------------------------------
|
|
37
|
+
* Minify inline <style>, <script> and <svg> tag
|
|
38
|
+
* ---------------------------------------- */
|
|
39
|
+
mergeStyles: false,
|
|
40
|
+
mergeScripts: false,
|
|
41
|
+
minifyCss: {
|
|
42
|
+
preset: 'default',
|
|
43
|
+
},
|
|
44
|
+
minifyJs: {},
|
|
45
|
+
minifyJson: {},
|
|
46
|
+
minifySvg: {
|
|
47
|
+
plugins: [
|
|
48
|
+
{
|
|
49
|
+
name: 'preset-default',
|
|
50
|
+
params: {
|
|
51
|
+
overrides: {
|
|
52
|
+
collapseGroups: false,
|
|
53
|
+
convertShapeToPath: false,
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
removeUnusedCss: false,
|
|
60
|
+
|
|
61
|
+
/* ----------------------------------------
|
|
62
|
+
* Miscellaneous
|
|
63
|
+
* ---------------------------------------- */
|
|
64
|
+
custom: []
|
|
65
|
+
};
|
package/package.json
CHANGED
|
@@ -1,14 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "htmlnano",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "Modular HTML minifier, built on top of the PostHTML",
|
|
5
|
-
"main": "index.
|
|
5
|
+
"main": "index.cjs",
|
|
6
|
+
"module": "index.mjs",
|
|
7
|
+
"source": "index.mjs",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"require": "./index.cjs",
|
|
11
|
+
"import": "./index.mjs"
|
|
12
|
+
},
|
|
13
|
+
"./index.mjs": {
|
|
14
|
+
"import": "./index.mjs"
|
|
15
|
+
},
|
|
16
|
+
"./index.cjs": {
|
|
17
|
+
"require": "./index.cjs"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
6
20
|
"types": "index.d.ts",
|
|
7
21
|
"author": "Kirill Maltsev <maltsevkirill@gmail.com>",
|
|
8
22
|
"license": "MIT",
|
|
9
23
|
"scripts": {
|
|
10
|
-
"
|
|
11
|
-
"
|
|
24
|
+
"clean": "rimraf lib/*.cjs lib/**/*.cjs",
|
|
25
|
+
"compile": "npm run clean && babel -d lib/ lib/ --out-file-extension .cjs",
|
|
26
|
+
"lint": "eslint --fix *.mjs lib/*.mjs lib/**/*.mjs test/*.mjs test/**/*.mjs",
|
|
12
27
|
"pretest": "npm run lint && npm run compile",
|
|
13
28
|
"test": ":",
|
|
14
29
|
"posttest": "mocha --timeout 5000 --require @babel/register --recursive --check-leaks --globals addresses",
|
|
@@ -31,10 +46,20 @@
|
|
|
31
46
|
}
|
|
32
47
|
}
|
|
33
48
|
]
|
|
49
|
+
],
|
|
50
|
+
"plugins": [
|
|
51
|
+
[
|
|
52
|
+
"@aminya/babel-plugin-replace-import-extension",
|
|
53
|
+
{
|
|
54
|
+
"extMapping": {
|
|
55
|
+
".mjs": ".cjs"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
]
|
|
34
59
|
]
|
|
35
60
|
},
|
|
36
61
|
"dependencies": {
|
|
37
|
-
"cosmiconfig": "^
|
|
62
|
+
"cosmiconfig": "^9.0.0",
|
|
38
63
|
"posthtml": "^0.16.5",
|
|
39
64
|
"timsort": "^0.3.0"
|
|
40
65
|
},
|
|
@@ -44,25 +69,28 @@
|
|
|
44
69
|
"@babel/eslint-parser": "^7.17.0",
|
|
45
70
|
"@babel/preset-env": "^7.15.6",
|
|
46
71
|
"@babel/register": "^7.15.3",
|
|
47
|
-
"
|
|
72
|
+
"@aminya/babel-plugin-replace-import-extension": "1.2.0",
|
|
73
|
+
"cssnano": "^7.0.0",
|
|
48
74
|
"eslint": "^8.12.0",
|
|
75
|
+
"eslint-plugin-import": "^2.28.1",
|
|
76
|
+
"eslint-plugin-path-import-extension": "^0.9.0",
|
|
49
77
|
"expect": "^29.0.0",
|
|
50
78
|
"mocha": "^10.1.0",
|
|
51
79
|
"postcss": "^8.3.11",
|
|
52
|
-
"purgecss": "^
|
|
80
|
+
"purgecss": "^6.0.0",
|
|
53
81
|
"relateurl": "^0.2.7",
|
|
54
82
|
"rimraf": "^5.0.0",
|
|
55
|
-
"srcset": "
|
|
83
|
+
"srcset": "5.0.1",
|
|
56
84
|
"svgo": "^3.0.2",
|
|
57
|
-
"terser": "^5.
|
|
85
|
+
"terser": "^5.21.0",
|
|
58
86
|
"uncss": "^0.17.3"
|
|
59
87
|
},
|
|
60
88
|
"peerDependencies": {
|
|
61
|
-
"cssnano": "^
|
|
89
|
+
"cssnano": "^7.0.0",
|
|
62
90
|
"postcss": "^8.3.11",
|
|
63
|
-
"purgecss": "^
|
|
91
|
+
"purgecss": "^6.0.0",
|
|
64
92
|
"relateurl": "^0.2.7",
|
|
65
|
-
"srcset": "
|
|
93
|
+
"srcset": "5.0.1",
|
|
66
94
|
"svgo": "^3.0.2",
|
|
67
95
|
"terser": "^5.10.0",
|
|
68
96
|
"uncss": "^0.17.3"
|
package/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
module.exports = require('./lib/htmlnano').default;
|