htmlnano 3.0.0 → 3.2.0
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 +40 -25
- package/dist/_modules/collapseAttributeWhitespace.d.mts +41 -5
- package/dist/_modules/collapseAttributeWhitespace.d.ts +41 -5
- package/dist/_modules/collapseAttributeWhitespace.js +69 -16
- package/dist/_modules/collapseAttributeWhitespace.mjs +67 -17
- package/dist/_modules/collapseBooleanAttributes.d.mts +36 -3
- package/dist/_modules/collapseBooleanAttributes.d.ts +36 -3
- package/dist/_modules/collapseBooleanAttributes.js +18 -11
- package/dist/_modules/collapseBooleanAttributes.mjs +18 -11
- package/dist/_modules/collapseWhitespace.d.mts +36 -3
- package/dist/_modules/collapseWhitespace.d.ts +36 -3
- package/dist/_modules/collapseWhitespace.js +25 -2
- package/dist/_modules/collapseWhitespace.mjs +25 -2
- package/dist/_modules/custom.d.mts +36 -3
- package/dist/_modules/custom.d.ts +36 -3
- package/dist/_modules/deduplicateAttributeValues.d.mts +36 -3
- package/dist/_modules/deduplicateAttributeValues.d.ts +36 -3
- package/dist/_modules/deduplicateAttributeValues.js +20 -5
- package/dist/_modules/deduplicateAttributeValues.mjs +21 -6
- package/dist/_modules/example.d.mts +36 -3
- package/dist/_modules/example.d.ts +36 -3
- package/dist/_modules/mergeScripts.d.mts +36 -3
- package/dist/_modules/mergeScripts.d.ts +36 -3
- package/dist/_modules/mergeScripts.js +111 -24
- package/dist/_modules/mergeScripts.mjs +111 -24
- package/dist/_modules/mergeStyles.d.mts +36 -3
- package/dist/_modules/mergeStyles.d.ts +36 -3
- package/dist/_modules/mergeStyles.js +66 -4
- package/dist/_modules/mergeStyles.mjs +66 -4
- package/dist/_modules/minifyAttributes.d.mts +95 -0
- package/dist/_modules/minifyAttributes.d.ts +95 -0
- package/dist/_modules/minifyAttributes.js +159 -0
- package/dist/_modules/minifyAttributes.mjs +157 -0
- package/dist/_modules/minifyConditionalComments.d.mts +36 -3
- package/dist/_modules/minifyConditionalComments.d.ts +36 -3
- package/dist/_modules/minifyConditionalComments.js +37 -19
- package/dist/_modules/minifyConditionalComments.mjs +37 -19
- package/dist/_modules/minifyCss.d.mts +36 -3
- package/dist/_modules/minifyCss.d.ts +36 -3
- package/dist/_modules/minifyCss.js +13 -27
- package/dist/_modules/minifyCss.mjs +14 -28
- package/dist/_modules/minifyHtmlTemplate.d.mts +91 -0
- package/dist/_modules/minifyHtmlTemplate.d.ts +91 -0
- package/dist/_modules/minifyHtmlTemplate.js +231 -0
- package/dist/_modules/minifyHtmlTemplate.mjs +228 -0
- package/dist/_modules/minifyJs.d.mts +36 -3
- package/dist/_modules/minifyJs.d.ts +36 -3
- package/dist/_modules/minifyJs.js +106 -5
- package/dist/_modules/minifyJs.mjs +107 -6
- package/dist/_modules/minifyJson.d.mts +36 -3
- package/dist/_modules/minifyJson.d.ts +36 -3
- package/dist/_modules/minifyJson.js +8 -11
- package/dist/_modules/minifyJson.mjs +8 -11
- package/dist/_modules/minifySvg.d.mts +36 -3
- package/dist/_modules/minifySvg.d.ts +36 -3
- package/dist/_modules/minifySvg.js +35 -4
- package/dist/_modules/minifySvg.mjs +35 -4
- package/dist/_modules/minifyUrls.d.mts +37 -4
- package/dist/_modules/minifyUrls.d.ts +37 -4
- package/dist/_modules/minifyUrls.js +52 -27
- package/dist/_modules/minifyUrls.mjs +52 -27
- package/dist/_modules/normalizeAttributeValues.d.mts +36 -3
- package/dist/_modules/normalizeAttributeValues.d.ts +36 -3
- package/dist/_modules/normalizeAttributeValues.js +10 -8
- package/dist/_modules/normalizeAttributeValues.mjs +10 -8
- package/dist/_modules/removeAttributeQuotes.d.mts +40 -4
- package/dist/_modules/removeAttributeQuotes.d.ts +40 -4
- package/dist/_modules/removeAttributeQuotes.js +9 -4
- package/dist/_modules/removeAttributeQuotes.mjs +9 -4
- package/dist/_modules/removeComments.d.mts +37 -4
- package/dist/_modules/removeComments.d.ts +37 -4
- package/dist/_modules/removeComments.js +44 -12
- package/dist/_modules/removeComments.mjs +44 -12
- package/dist/_modules/removeEmptyAttributes.d.mts +36 -3
- package/dist/_modules/removeEmptyAttributes.d.ts +36 -3
- package/dist/_modules/removeEmptyAttributes.js +37 -16
- package/dist/_modules/removeEmptyAttributes.mjs +37 -16
- package/dist/_modules/removeEmptyElements.d.mts +95 -0
- package/dist/_modules/removeEmptyElements.d.ts +95 -0
- package/dist/_modules/removeEmptyElements.js +90 -0
- package/dist/_modules/removeEmptyElements.mjs +88 -0
- package/dist/_modules/removeOptionalTags.d.mts +36 -3
- package/dist/_modules/removeOptionalTags.d.ts +36 -3
- package/dist/_modules/removeOptionalTags.js +39 -28
- package/dist/_modules/removeOptionalTags.mjs +39 -28
- package/dist/_modules/removeRedundantAttributes.d.mts +36 -3
- package/dist/_modules/removeRedundantAttributes.d.ts +36 -3
- package/dist/_modules/removeRedundantAttributes.js +43 -28
- package/dist/_modules/removeRedundantAttributes.mjs +43 -28
- package/dist/_modules/removeUnusedCss.d.mts +37 -3
- package/dist/_modules/removeUnusedCss.d.ts +37 -3
- package/dist/_modules/removeUnusedCss.js +40 -14
- package/dist/_modules/removeUnusedCss.mjs +41 -15
- package/dist/_modules/sortAttributes.d.mts +39 -5
- package/dist/_modules/sortAttributes.d.ts +39 -5
- package/dist/_modules/sortAttributes.js +27 -8
- package/dist/_modules/sortAttributes.mjs +27 -8
- package/dist/_modules/sortAttributesWithLists.d.mts +39 -4
- package/dist/_modules/sortAttributesWithLists.d.ts +39 -4
- package/dist/_modules/sortAttributesWithLists.js +61 -52
- package/dist/_modules/sortAttributesWithLists.mjs +62 -53
- package/dist/helpers.d.ts +8 -1
- package/dist/helpers.js +48 -0
- package/dist/helpers.mjs +45 -1
- package/dist/index.d.ts +37 -4
- package/dist/index.js +13 -0
- package/dist/index.mjs +13 -0
- package/dist/presets/ampSafe.d.ts +36 -3
- package/dist/presets/max.d.ts +36 -3
- package/dist/presets/max.js +13 -5
- package/dist/presets/max.mjs +13 -5
- package/dist/presets/safe.d.ts +36 -3
- package/dist/presets/safe.js +6 -0
- package/dist/presets/safe.mjs +6 -0
- package/package.json +27 -15
|
@@ -26,20 +26,25 @@ var removeRedundantAttributes_js = require('./removeRedundantAttributes.js');
|
|
|
26
26
|
return node;
|
|
27
27
|
}
|
|
28
28
|
if (node.tag && node.tag === 'script') {
|
|
29
|
-
const
|
|
29
|
+
const rawMimeType = typeof nodeAttrs.type === 'string' ? helpers_js.normalizeMimeType(nodeAttrs.type) : undefined;
|
|
30
|
+
const mimeType = rawMimeType || 'text/javascript';
|
|
30
31
|
if (removeRedundantAttributes_js.redundantScriptTypes.has(mimeType) || mimeType === 'module') {
|
|
31
|
-
|
|
32
|
+
const scriptTerserOptions = resolveScriptTerserOptions(terserOptions, mimeType);
|
|
33
|
+
p = processScriptNode(node, scriptTerserOptions, terser);
|
|
32
34
|
if (p) {
|
|
33
35
|
promises.push(p);
|
|
34
36
|
}
|
|
35
37
|
}
|
|
36
38
|
}
|
|
37
39
|
if (node.attrs) {
|
|
38
|
-
promises.push
|
|
40
|
+
promises.push(...processNodeWithOnAttrs(node, terserOptions, terser));
|
|
39
41
|
}
|
|
40
42
|
return node;
|
|
41
43
|
});
|
|
42
|
-
return Promise.all(promises).then(()=>
|
|
44
|
+
return Promise.all(promises).then(()=>{
|
|
45
|
+
applySmartQuoteOptions(tree);
|
|
46
|
+
return tree;
|
|
47
|
+
});
|
|
43
48
|
}
|
|
44
49
|
};
|
|
45
50
|
function stripCdata(js) {
|
|
@@ -50,6 +55,89 @@ function stripCdata(js) {
|
|
|
50
55
|
const strippedJs = leftStrippedJs.replace(/\/\/\s*\]\]>/, '').replace(/\/\*\s*\]\]>\s*\*\//, '');
|
|
51
56
|
return leftStrippedJs === strippedJs ? js : strippedJs;
|
|
52
57
|
}
|
|
58
|
+
function resolveScriptTerserOptions(terserOptions, mimeType) {
|
|
59
|
+
var _terserOptions_toplevel, _terserOptions_compress, _terserOptions_mangle;
|
|
60
|
+
if (mimeType !== 'module' || terserOptions.module !== undefined) {
|
|
61
|
+
return terserOptions;
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
...terserOptions,
|
|
65
|
+
module: true,
|
|
66
|
+
toplevel: (_terserOptions_toplevel = terserOptions.toplevel) != null ? _terserOptions_toplevel : false,
|
|
67
|
+
compress: (_terserOptions_compress = terserOptions.compress) != null ? _terserOptions_compress : false,
|
|
68
|
+
mangle: (_terserOptions_mangle = terserOptions.mangle) != null ? _terserOptions_mangle : false
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function resolveOnAttrTerserOptions(terserOptions) {
|
|
72
|
+
const output = terserOptions.output;
|
|
73
|
+
const format = terserOptions.format;
|
|
74
|
+
const outputHasQuoteStyle = !!(output && typeof output === 'object' && 'quote_style' in output);
|
|
75
|
+
const formatHasQuoteStyle = !!(format && typeof format === 'object' && 'quote_style' in format);
|
|
76
|
+
if (outputHasQuoteStyle || formatHasQuoteStyle) {
|
|
77
|
+
return terserOptions;
|
|
78
|
+
}
|
|
79
|
+
const resolved = {
|
|
80
|
+
...terserOptions
|
|
81
|
+
};
|
|
82
|
+
if (format && typeof format === 'object') {
|
|
83
|
+
resolved.format = {
|
|
84
|
+
...format,
|
|
85
|
+
['quote_style']: 3
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
if (output && typeof output === 'object') {
|
|
89
|
+
resolved.output = {
|
|
90
|
+
...output,
|
|
91
|
+
['quote_style']: 3
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
if (!format && !output) {
|
|
95
|
+
resolved.output = {
|
|
96
|
+
['quote_style']: 3
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
return resolved;
|
|
100
|
+
}
|
|
101
|
+
function applySmartQuoteOptions(tree) {
|
|
102
|
+
var _tree, _options, _tree_options, _quoteStyle, _tree_options1, _replaceQuote;
|
|
103
|
+
const quoteState = analyzeTreeQuotes(tree);
|
|
104
|
+
if (!quoteState.needsSmartQuotes || quoteState.hasMixedQuotes) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
(_options = (_tree = tree).options) != null ? _options : _tree.options = {};
|
|
108
|
+
(_quoteStyle = (_tree_options = tree.options).quoteStyle) != null ? _quoteStyle : _tree_options.quoteStyle = 0;
|
|
109
|
+
(_replaceQuote = (_tree_options1 = tree.options).replaceQuote) != null ? _replaceQuote : _tree_options1.replaceQuote = false;
|
|
110
|
+
}
|
|
111
|
+
function analyzeTreeQuotes(tree) {
|
|
112
|
+
let needsSmartQuotes = false;
|
|
113
|
+
let hasMixedQuotes = false;
|
|
114
|
+
tree.walk((node)=>{
|
|
115
|
+
if (!node || !node.attrs) {
|
|
116
|
+
return node;
|
|
117
|
+
}
|
|
118
|
+
for (const [attrName, attrValue] of Object.entries(node.attrs)){
|
|
119
|
+
if (typeof attrValue !== 'string') {
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
const hasDoubleQuote = attrValue.includes('"');
|
|
123
|
+
const hasSingleQuote = attrValue.includes('\'');
|
|
124
|
+
if (hasDoubleQuote && helpers_js.isEventHandler(attrName)) {
|
|
125
|
+
needsSmartQuotes = true;
|
|
126
|
+
}
|
|
127
|
+
if (hasDoubleQuote && hasSingleQuote) {
|
|
128
|
+
hasMixedQuotes = true;
|
|
129
|
+
}
|
|
130
|
+
if (needsSmartQuotes && hasMixedQuotes) {
|
|
131
|
+
return node;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return node;
|
|
135
|
+
});
|
|
136
|
+
return {
|
|
137
|
+
needsSmartQuotes,
|
|
138
|
+
hasMixedQuotes
|
|
139
|
+
};
|
|
140
|
+
}
|
|
53
141
|
function processScriptNode(scriptNode, terserOptions, terser) {
|
|
54
142
|
let js = helpers_js.extractTextContentFromNode(scriptNode).trim();
|
|
55
143
|
if (!js.length) {
|
|
@@ -81,6 +169,7 @@ function processScriptNode(scriptNode, terserOptions, terser) {
|
|
|
81
169
|
function processNodeWithOnAttrs(node, terserOptions, terser) {
|
|
82
170
|
const jsWrapperStart = 'a=function(){';
|
|
83
171
|
const jsWrapperEnd = '};a();';
|
|
172
|
+
const onAttrTerserOptions = resolveOnAttrTerserOptions(terserOptions);
|
|
84
173
|
const promises = [];
|
|
85
174
|
if (!node.attrs) {
|
|
86
175
|
return promises;
|
|
@@ -98,15 +187,27 @@ function processNodeWithOnAttrs(node, terserOptions, terser) {
|
|
|
98
187
|
// Therefore the attribute's code should be wrapped inside function:
|
|
99
188
|
// "function _(){return false;}"
|
|
100
189
|
const wrappedJs = jsWrapperStart + node.attrs[attrName] + jsWrapperEnd;
|
|
101
|
-
const promise = terser.minify(wrappedJs,
|
|
190
|
+
const promise = terser.minify(wrappedJs, onAttrTerserOptions).then(({ code })=>{
|
|
102
191
|
if (code) {
|
|
103
192
|
const minifiedJs = code.substring(jsWrapperStart.length, code.length - jsWrapperEnd.length);
|
|
104
193
|
node.attrs[attrName] = minifiedJs;
|
|
105
194
|
}
|
|
195
|
+
}).catch((error)=>{
|
|
196
|
+
// Skip invalid inline handler code and preserve the original value.
|
|
197
|
+
if (isTerserParseError(error)) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
throw error;
|
|
106
201
|
});
|
|
107
202
|
promises.push(promise);
|
|
108
203
|
}
|
|
109
204
|
return promises;
|
|
110
205
|
}
|
|
206
|
+
function isTerserParseError(error) {
|
|
207
|
+
if (!(error instanceof Error)) {
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
return error.name === 'SyntaxError' || error.message.includes('JS_Parse_Error');
|
|
211
|
+
}
|
|
111
212
|
|
|
112
213
|
exports.default = mod;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { optionalImport,
|
|
1
|
+
import { optionalImport, normalizeMimeType, isEventHandler, extractTextContentFromNode } from '../helpers.mjs';
|
|
2
2
|
import { redundantScriptTypes } from './removeRedundantAttributes.mjs';
|
|
3
3
|
|
|
4
4
|
/** Minify JS with Terser */ const mod = {
|
|
@@ -24,20 +24,25 @@ import { redundantScriptTypes } from './removeRedundantAttributes.mjs';
|
|
|
24
24
|
return node;
|
|
25
25
|
}
|
|
26
26
|
if (node.tag && node.tag === 'script') {
|
|
27
|
-
const
|
|
27
|
+
const rawMimeType = typeof nodeAttrs.type === 'string' ? normalizeMimeType(nodeAttrs.type) : undefined;
|
|
28
|
+
const mimeType = rawMimeType || 'text/javascript';
|
|
28
29
|
if (redundantScriptTypes.has(mimeType) || mimeType === 'module') {
|
|
29
|
-
|
|
30
|
+
const scriptTerserOptions = resolveScriptTerserOptions(terserOptions, mimeType);
|
|
31
|
+
p = processScriptNode(node, scriptTerserOptions, terser);
|
|
30
32
|
if (p) {
|
|
31
33
|
promises.push(p);
|
|
32
34
|
}
|
|
33
35
|
}
|
|
34
36
|
}
|
|
35
37
|
if (node.attrs) {
|
|
36
|
-
promises.push
|
|
38
|
+
promises.push(...processNodeWithOnAttrs(node, terserOptions, terser));
|
|
37
39
|
}
|
|
38
40
|
return node;
|
|
39
41
|
});
|
|
40
|
-
return Promise.all(promises).then(()=>
|
|
42
|
+
return Promise.all(promises).then(()=>{
|
|
43
|
+
applySmartQuoteOptions(tree);
|
|
44
|
+
return tree;
|
|
45
|
+
});
|
|
41
46
|
}
|
|
42
47
|
};
|
|
43
48
|
function stripCdata(js) {
|
|
@@ -48,6 +53,89 @@ function stripCdata(js) {
|
|
|
48
53
|
const strippedJs = leftStrippedJs.replace(/\/\/\s*\]\]>/, '').replace(/\/\*\s*\]\]>\s*\*\//, '');
|
|
49
54
|
return leftStrippedJs === strippedJs ? js : strippedJs;
|
|
50
55
|
}
|
|
56
|
+
function resolveScriptTerserOptions(terserOptions, mimeType) {
|
|
57
|
+
var _terserOptions_toplevel, _terserOptions_compress, _terserOptions_mangle;
|
|
58
|
+
if (mimeType !== 'module' || terserOptions.module !== undefined) {
|
|
59
|
+
return terserOptions;
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
...terserOptions,
|
|
63
|
+
module: true,
|
|
64
|
+
toplevel: (_terserOptions_toplevel = terserOptions.toplevel) != null ? _terserOptions_toplevel : false,
|
|
65
|
+
compress: (_terserOptions_compress = terserOptions.compress) != null ? _terserOptions_compress : false,
|
|
66
|
+
mangle: (_terserOptions_mangle = terserOptions.mangle) != null ? _terserOptions_mangle : false
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function resolveOnAttrTerserOptions(terserOptions) {
|
|
70
|
+
const output = terserOptions.output;
|
|
71
|
+
const format = terserOptions.format;
|
|
72
|
+
const outputHasQuoteStyle = !!(output && typeof output === 'object' && 'quote_style' in output);
|
|
73
|
+
const formatHasQuoteStyle = !!(format && typeof format === 'object' && 'quote_style' in format);
|
|
74
|
+
if (outputHasQuoteStyle || formatHasQuoteStyle) {
|
|
75
|
+
return terserOptions;
|
|
76
|
+
}
|
|
77
|
+
const resolved = {
|
|
78
|
+
...terserOptions
|
|
79
|
+
};
|
|
80
|
+
if (format && typeof format === 'object') {
|
|
81
|
+
resolved.format = {
|
|
82
|
+
...format,
|
|
83
|
+
['quote_style']: 3
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
if (output && typeof output === 'object') {
|
|
87
|
+
resolved.output = {
|
|
88
|
+
...output,
|
|
89
|
+
['quote_style']: 3
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
if (!format && !output) {
|
|
93
|
+
resolved.output = {
|
|
94
|
+
['quote_style']: 3
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
return resolved;
|
|
98
|
+
}
|
|
99
|
+
function applySmartQuoteOptions(tree) {
|
|
100
|
+
var _tree, _options, _tree_options, _quoteStyle, _tree_options1, _replaceQuote;
|
|
101
|
+
const quoteState = analyzeTreeQuotes(tree);
|
|
102
|
+
if (!quoteState.needsSmartQuotes || quoteState.hasMixedQuotes) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
(_options = (_tree = tree).options) != null ? _options : _tree.options = {};
|
|
106
|
+
(_quoteStyle = (_tree_options = tree.options).quoteStyle) != null ? _quoteStyle : _tree_options.quoteStyle = 0;
|
|
107
|
+
(_replaceQuote = (_tree_options1 = tree.options).replaceQuote) != null ? _replaceQuote : _tree_options1.replaceQuote = false;
|
|
108
|
+
}
|
|
109
|
+
function analyzeTreeQuotes(tree) {
|
|
110
|
+
let needsSmartQuotes = false;
|
|
111
|
+
let hasMixedQuotes = false;
|
|
112
|
+
tree.walk((node)=>{
|
|
113
|
+
if (!node || !node.attrs) {
|
|
114
|
+
return node;
|
|
115
|
+
}
|
|
116
|
+
for (const [attrName, attrValue] of Object.entries(node.attrs)){
|
|
117
|
+
if (typeof attrValue !== 'string') {
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
const hasDoubleQuote = attrValue.includes('"');
|
|
121
|
+
const hasSingleQuote = attrValue.includes('\'');
|
|
122
|
+
if (hasDoubleQuote && isEventHandler(attrName)) {
|
|
123
|
+
needsSmartQuotes = true;
|
|
124
|
+
}
|
|
125
|
+
if (hasDoubleQuote && hasSingleQuote) {
|
|
126
|
+
hasMixedQuotes = true;
|
|
127
|
+
}
|
|
128
|
+
if (needsSmartQuotes && hasMixedQuotes) {
|
|
129
|
+
return node;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return node;
|
|
133
|
+
});
|
|
134
|
+
return {
|
|
135
|
+
needsSmartQuotes,
|
|
136
|
+
hasMixedQuotes
|
|
137
|
+
};
|
|
138
|
+
}
|
|
51
139
|
function processScriptNode(scriptNode, terserOptions, terser) {
|
|
52
140
|
let js = extractTextContentFromNode(scriptNode).trim();
|
|
53
141
|
if (!js.length) {
|
|
@@ -79,6 +167,7 @@ function processScriptNode(scriptNode, terserOptions, terser) {
|
|
|
79
167
|
function processNodeWithOnAttrs(node, terserOptions, terser) {
|
|
80
168
|
const jsWrapperStart = 'a=function(){';
|
|
81
169
|
const jsWrapperEnd = '};a();';
|
|
170
|
+
const onAttrTerserOptions = resolveOnAttrTerserOptions(terserOptions);
|
|
82
171
|
const promises = [];
|
|
83
172
|
if (!node.attrs) {
|
|
84
173
|
return promises;
|
|
@@ -96,15 +185,27 @@ function processNodeWithOnAttrs(node, terserOptions, terser) {
|
|
|
96
185
|
// Therefore the attribute's code should be wrapped inside function:
|
|
97
186
|
// "function _(){return false;}"
|
|
98
187
|
const wrappedJs = jsWrapperStart + node.attrs[attrName] + jsWrapperEnd;
|
|
99
|
-
const promise = terser.minify(wrappedJs,
|
|
188
|
+
const promise = terser.minify(wrappedJs, onAttrTerserOptions).then(({ code })=>{
|
|
100
189
|
if (code) {
|
|
101
190
|
const minifiedJs = code.substring(jsWrapperStart.length, code.length - jsWrapperEnd.length);
|
|
102
191
|
node.attrs[attrName] = minifiedJs;
|
|
103
192
|
}
|
|
193
|
+
}).catch((error)=>{
|
|
194
|
+
// Skip invalid inline handler code and preserve the original value.
|
|
195
|
+
if (isTerserParseError(error)) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
throw error;
|
|
104
199
|
});
|
|
105
200
|
promises.push(promise);
|
|
106
201
|
}
|
|
107
202
|
return promises;
|
|
108
203
|
}
|
|
204
|
+
function isTerserParseError(error) {
|
|
205
|
+
if (!(error instanceof Error)) {
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
return error.name === 'SyntaxError' || error.message.includes('JS_Parse_Error');
|
|
209
|
+
}
|
|
109
210
|
|
|
110
211
|
export { mod as default };
|
|
@@ -2,16 +2,24 @@ import PostHTML from 'posthtml';
|
|
|
2
2
|
import { MinifyOptions } from 'terser';
|
|
3
3
|
import { Options } from 'cssnano';
|
|
4
4
|
import { Config } from 'svgo';
|
|
5
|
+
import { UserDefinedOptions } from 'purgecss';
|
|
5
6
|
|
|
6
7
|
type PostHTMLTreeLike = [PostHTML.Node] & PostHTML.NodeAPI & {
|
|
7
8
|
options?: {
|
|
8
9
|
quoteAllAttributes?: boolean | undefined;
|
|
10
|
+
quoteStyle?: 0 | 1 | 2 | undefined;
|
|
11
|
+
replaceQuote?: boolean | undefined;
|
|
9
12
|
} | undefined;
|
|
10
13
|
render(): string;
|
|
11
14
|
render(node: PostHTML.Node | PostHTMLTreeLike, renderOptions?: any): string;
|
|
12
15
|
};
|
|
13
16
|
type MaybeArray<T> = T | Array<T>;
|
|
14
17
|
type PostHTMLNodeLike = PostHTML.Node | string;
|
|
18
|
+
type HtmlnanoTemplateRule = {
|
|
19
|
+
tag: string;
|
|
20
|
+
attrs?: Record<string, string | boolean | void>;
|
|
21
|
+
};
|
|
22
|
+
type MinifyHtmlTemplateOptions = boolean | HtmlnanoTemplateRule[];
|
|
15
23
|
interface HtmlnanoOptions {
|
|
16
24
|
skipConfigLoading?: boolean;
|
|
17
25
|
configPath?: string;
|
|
@@ -27,17 +35,42 @@ interface HtmlnanoOptions {
|
|
|
27
35
|
mergeStyles?: boolean;
|
|
28
36
|
mergeScripts?: boolean;
|
|
29
37
|
minifyCss?: Options | boolean;
|
|
38
|
+
minifyHtmlTemplate?: MinifyHtmlTemplateOptions;
|
|
30
39
|
minifyConditionalComments?: boolean;
|
|
31
40
|
minifyJs?: MinifyOptions | boolean;
|
|
32
41
|
minifyJson?: boolean;
|
|
42
|
+
minifyAttributes?: boolean | {
|
|
43
|
+
metaContent?: boolean;
|
|
44
|
+
redundantWhitespaces?: 'safe' | 'agressive' | false;
|
|
45
|
+
};
|
|
33
46
|
minifySvg?: Config | boolean;
|
|
34
47
|
normalizeAttributeValues?: boolean;
|
|
35
|
-
removeAttributeQuotes?: boolean
|
|
36
|
-
|
|
48
|
+
removeAttributeQuotes?: boolean | {
|
|
49
|
+
force?: boolean;
|
|
50
|
+
};
|
|
51
|
+
removeComments?: boolean | RegExp | ((comment: string) => boolean) | string;
|
|
37
52
|
removeEmptyAttributes?: boolean;
|
|
53
|
+
removeEmptyElements?: boolean | {
|
|
54
|
+
removeWithAttributes?: boolean;
|
|
55
|
+
};
|
|
38
56
|
removeRedundantAttributes?: boolean;
|
|
39
57
|
removeOptionalTags?: boolean;
|
|
40
|
-
removeUnusedCss?: boolean
|
|
58
|
+
removeUnusedCss?: boolean | ({
|
|
59
|
+
tool: 'purgeCSS';
|
|
60
|
+
} & Omit<UserDefinedOptions, 'content' | 'css' | 'extractors'>) | {
|
|
61
|
+
banner?: boolean;
|
|
62
|
+
csspath?: string;
|
|
63
|
+
htmlroot?: string;
|
|
64
|
+
ignore?: (string | RegExp)[];
|
|
65
|
+
inject?: string;
|
|
66
|
+
jsdom?: object;
|
|
67
|
+
media?: string[];
|
|
68
|
+
report?: boolean;
|
|
69
|
+
strictSSL?: boolean;
|
|
70
|
+
timeout?: number;
|
|
71
|
+
uncssrc?: string;
|
|
72
|
+
userAgent?: string;
|
|
73
|
+
};
|
|
41
74
|
sortAttributes?: boolean | 'alphabetical' | 'frequency';
|
|
42
75
|
sortAttributesWithLists?: boolean | 'alphabetical' | 'frequency';
|
|
43
76
|
}
|
|
@@ -2,16 +2,24 @@ import PostHTML from 'posthtml';
|
|
|
2
2
|
import { MinifyOptions } from 'terser';
|
|
3
3
|
import { Options } from 'cssnano';
|
|
4
4
|
import { Config } from 'svgo';
|
|
5
|
+
import { UserDefinedOptions } from 'purgecss';
|
|
5
6
|
|
|
6
7
|
type PostHTMLTreeLike = [PostHTML.Node] & PostHTML.NodeAPI & {
|
|
7
8
|
options?: {
|
|
8
9
|
quoteAllAttributes?: boolean | undefined;
|
|
10
|
+
quoteStyle?: 0 | 1 | 2 | undefined;
|
|
11
|
+
replaceQuote?: boolean | undefined;
|
|
9
12
|
} | undefined;
|
|
10
13
|
render(): string;
|
|
11
14
|
render(node: PostHTML.Node | PostHTMLTreeLike, renderOptions?: any): string;
|
|
12
15
|
};
|
|
13
16
|
type MaybeArray<T> = T | Array<T>;
|
|
14
17
|
type PostHTMLNodeLike = PostHTML.Node | string;
|
|
18
|
+
type HtmlnanoTemplateRule = {
|
|
19
|
+
tag: string;
|
|
20
|
+
attrs?: Record<string, string | boolean | void>;
|
|
21
|
+
};
|
|
22
|
+
type MinifyHtmlTemplateOptions = boolean | HtmlnanoTemplateRule[];
|
|
15
23
|
interface HtmlnanoOptions {
|
|
16
24
|
skipConfigLoading?: boolean;
|
|
17
25
|
configPath?: string;
|
|
@@ -27,17 +35,42 @@ interface HtmlnanoOptions {
|
|
|
27
35
|
mergeStyles?: boolean;
|
|
28
36
|
mergeScripts?: boolean;
|
|
29
37
|
minifyCss?: Options | boolean;
|
|
38
|
+
minifyHtmlTemplate?: MinifyHtmlTemplateOptions;
|
|
30
39
|
minifyConditionalComments?: boolean;
|
|
31
40
|
minifyJs?: MinifyOptions | boolean;
|
|
32
41
|
minifyJson?: boolean;
|
|
42
|
+
minifyAttributes?: boolean | {
|
|
43
|
+
metaContent?: boolean;
|
|
44
|
+
redundantWhitespaces?: 'safe' | 'agressive' | false;
|
|
45
|
+
};
|
|
33
46
|
minifySvg?: Config | boolean;
|
|
34
47
|
normalizeAttributeValues?: boolean;
|
|
35
|
-
removeAttributeQuotes?: boolean
|
|
36
|
-
|
|
48
|
+
removeAttributeQuotes?: boolean | {
|
|
49
|
+
force?: boolean;
|
|
50
|
+
};
|
|
51
|
+
removeComments?: boolean | RegExp | ((comment: string) => boolean) | string;
|
|
37
52
|
removeEmptyAttributes?: boolean;
|
|
53
|
+
removeEmptyElements?: boolean | {
|
|
54
|
+
removeWithAttributes?: boolean;
|
|
55
|
+
};
|
|
38
56
|
removeRedundantAttributes?: boolean;
|
|
39
57
|
removeOptionalTags?: boolean;
|
|
40
|
-
removeUnusedCss?: boolean
|
|
58
|
+
removeUnusedCss?: boolean | ({
|
|
59
|
+
tool: 'purgeCSS';
|
|
60
|
+
} & Omit<UserDefinedOptions, 'content' | 'css' | 'extractors'>) | {
|
|
61
|
+
banner?: boolean;
|
|
62
|
+
csspath?: string;
|
|
63
|
+
htmlroot?: string;
|
|
64
|
+
ignore?: (string | RegExp)[];
|
|
65
|
+
inject?: string;
|
|
66
|
+
jsdom?: object;
|
|
67
|
+
media?: string[];
|
|
68
|
+
report?: boolean;
|
|
69
|
+
strictSSL?: boolean;
|
|
70
|
+
timeout?: number;
|
|
71
|
+
uncssrc?: string;
|
|
72
|
+
userAgent?: string;
|
|
73
|
+
};
|
|
41
74
|
sortAttributes?: boolean | 'alphabetical' | 'frequency';
|
|
42
75
|
sortAttributesWithLists?: boolean | 'alphabetical' | 'frequency';
|
|
43
76
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
var helpers_js = require('../helpers.js');
|
|
4
|
+
|
|
5
|
+
const rNodeAttrsTypeJson = /(?:\/|\+)json$/i;
|
|
4
6
|
const mod = {
|
|
5
7
|
onContent () {
|
|
6
8
|
return (content, node)=>{
|
|
@@ -8,17 +10,12 @@ const mod = {
|
|
|
8
10
|
if (node.attrs && 'integrity' in node.attrs) {
|
|
9
11
|
return content;
|
|
10
12
|
}
|
|
11
|
-
|
|
13
|
+
const nodeType = node.attrs && typeof node.attrs.type === 'string' ? helpers_js.normalizeMimeType(node.attrs.type) : undefined;
|
|
14
|
+
if (nodeType && rNodeAttrsTypeJson.test(nodeType)) {
|
|
12
15
|
try {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const item = content[i];
|
|
17
|
-
if (typeof item === 'string') {
|
|
18
|
-
jsonContent += item;
|
|
19
|
-
} else {
|
|
20
|
-
return content; // If any item is not a string, return original contents
|
|
21
|
-
}
|
|
16
|
+
const jsonContent = typeof content === 'string' ? content : Array.isArray(content) && content.every((item)=>typeof item === 'string') ? content.join('') : null;
|
|
17
|
+
if (jsonContent === null) {
|
|
18
|
+
return content;
|
|
22
19
|
}
|
|
23
20
|
return [
|
|
24
21
|
JSON.stringify(JSON.parse(jsonContent))
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import { normalizeMimeType } from '../helpers.mjs';
|
|
2
|
+
|
|
3
|
+
const rNodeAttrsTypeJson = /(?:\/|\+)json$/i;
|
|
2
4
|
const mod = {
|
|
3
5
|
onContent () {
|
|
4
6
|
return (content, node)=>{
|
|
@@ -6,17 +8,12 @@ const mod = {
|
|
|
6
8
|
if (node.attrs && 'integrity' in node.attrs) {
|
|
7
9
|
return content;
|
|
8
10
|
}
|
|
9
|
-
|
|
11
|
+
const nodeType = node.attrs && typeof node.attrs.type === 'string' ? normalizeMimeType(node.attrs.type) : undefined;
|
|
12
|
+
if (nodeType && rNodeAttrsTypeJson.test(nodeType)) {
|
|
10
13
|
try {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const item = content[i];
|
|
15
|
-
if (typeof item === 'string') {
|
|
16
|
-
jsonContent += item;
|
|
17
|
-
} else {
|
|
18
|
-
return content; // If any item is not a string, return original contents
|
|
19
|
-
}
|
|
14
|
+
const jsonContent = typeof content === 'string' ? content : Array.isArray(content) && content.every((item)=>typeof item === 'string') ? content.join('') : null;
|
|
15
|
+
if (jsonContent === null) {
|
|
16
|
+
return content;
|
|
20
17
|
}
|
|
21
18
|
return [
|
|
22
19
|
JSON.stringify(JSON.parse(jsonContent))
|
|
@@ -2,16 +2,24 @@ import PostHTML from 'posthtml';
|
|
|
2
2
|
import { MinifyOptions } from 'terser';
|
|
3
3
|
import { Options } from 'cssnano';
|
|
4
4
|
import { Config } from 'svgo';
|
|
5
|
+
import { UserDefinedOptions } from 'purgecss';
|
|
5
6
|
|
|
6
7
|
type PostHTMLTreeLike = [PostHTML.Node] & PostHTML.NodeAPI & {
|
|
7
8
|
options?: {
|
|
8
9
|
quoteAllAttributes?: boolean | undefined;
|
|
10
|
+
quoteStyle?: 0 | 1 | 2 | undefined;
|
|
11
|
+
replaceQuote?: boolean | undefined;
|
|
9
12
|
} | undefined;
|
|
10
13
|
render(): string;
|
|
11
14
|
render(node: PostHTML.Node | PostHTMLTreeLike, renderOptions?: any): string;
|
|
12
15
|
};
|
|
13
16
|
type MaybeArray<T> = T | Array<T>;
|
|
14
17
|
type PostHTMLNodeLike = PostHTML.Node | string;
|
|
18
|
+
type HtmlnanoTemplateRule = {
|
|
19
|
+
tag: string;
|
|
20
|
+
attrs?: Record<string, string | boolean | void>;
|
|
21
|
+
};
|
|
22
|
+
type MinifyHtmlTemplateOptions = boolean | HtmlnanoTemplateRule[];
|
|
15
23
|
interface HtmlnanoOptions {
|
|
16
24
|
skipConfigLoading?: boolean;
|
|
17
25
|
configPath?: string;
|
|
@@ -27,17 +35,42 @@ interface HtmlnanoOptions {
|
|
|
27
35
|
mergeStyles?: boolean;
|
|
28
36
|
mergeScripts?: boolean;
|
|
29
37
|
minifyCss?: Options | boolean;
|
|
38
|
+
minifyHtmlTemplate?: MinifyHtmlTemplateOptions;
|
|
30
39
|
minifyConditionalComments?: boolean;
|
|
31
40
|
minifyJs?: MinifyOptions | boolean;
|
|
32
41
|
minifyJson?: boolean;
|
|
42
|
+
minifyAttributes?: boolean | {
|
|
43
|
+
metaContent?: boolean;
|
|
44
|
+
redundantWhitespaces?: 'safe' | 'agressive' | false;
|
|
45
|
+
};
|
|
33
46
|
minifySvg?: Config | boolean;
|
|
34
47
|
normalizeAttributeValues?: boolean;
|
|
35
|
-
removeAttributeQuotes?: boolean
|
|
36
|
-
|
|
48
|
+
removeAttributeQuotes?: boolean | {
|
|
49
|
+
force?: boolean;
|
|
50
|
+
};
|
|
51
|
+
removeComments?: boolean | RegExp | ((comment: string) => boolean) | string;
|
|
37
52
|
removeEmptyAttributes?: boolean;
|
|
53
|
+
removeEmptyElements?: boolean | {
|
|
54
|
+
removeWithAttributes?: boolean;
|
|
55
|
+
};
|
|
38
56
|
removeRedundantAttributes?: boolean;
|
|
39
57
|
removeOptionalTags?: boolean;
|
|
40
|
-
removeUnusedCss?: boolean
|
|
58
|
+
removeUnusedCss?: boolean | ({
|
|
59
|
+
tool: 'purgeCSS';
|
|
60
|
+
} & Omit<UserDefinedOptions, 'content' | 'css' | 'extractors'>) | {
|
|
61
|
+
banner?: boolean;
|
|
62
|
+
csspath?: string;
|
|
63
|
+
htmlroot?: string;
|
|
64
|
+
ignore?: (string | RegExp)[];
|
|
65
|
+
inject?: string;
|
|
66
|
+
jsdom?: object;
|
|
67
|
+
media?: string[];
|
|
68
|
+
report?: boolean;
|
|
69
|
+
strictSSL?: boolean;
|
|
70
|
+
timeout?: number;
|
|
71
|
+
uncssrc?: string;
|
|
72
|
+
userAgent?: string;
|
|
73
|
+
};
|
|
41
74
|
sortAttributes?: boolean | 'alphabetical' | 'frequency';
|
|
42
75
|
sortAttributesWithLists?: boolean | 'alphabetical' | 'frequency';
|
|
43
76
|
}
|
|
@@ -2,16 +2,24 @@ import PostHTML from 'posthtml';
|
|
|
2
2
|
import { MinifyOptions } from 'terser';
|
|
3
3
|
import { Options } from 'cssnano';
|
|
4
4
|
import { Config } from 'svgo';
|
|
5
|
+
import { UserDefinedOptions } from 'purgecss';
|
|
5
6
|
|
|
6
7
|
type PostHTMLTreeLike = [PostHTML.Node] & PostHTML.NodeAPI & {
|
|
7
8
|
options?: {
|
|
8
9
|
quoteAllAttributes?: boolean | undefined;
|
|
10
|
+
quoteStyle?: 0 | 1 | 2 | undefined;
|
|
11
|
+
replaceQuote?: boolean | undefined;
|
|
9
12
|
} | undefined;
|
|
10
13
|
render(): string;
|
|
11
14
|
render(node: PostHTML.Node | PostHTMLTreeLike, renderOptions?: any): string;
|
|
12
15
|
};
|
|
13
16
|
type MaybeArray<T> = T | Array<T>;
|
|
14
17
|
type PostHTMLNodeLike = PostHTML.Node | string;
|
|
18
|
+
type HtmlnanoTemplateRule = {
|
|
19
|
+
tag: string;
|
|
20
|
+
attrs?: Record<string, string | boolean | void>;
|
|
21
|
+
};
|
|
22
|
+
type MinifyHtmlTemplateOptions = boolean | HtmlnanoTemplateRule[];
|
|
15
23
|
interface HtmlnanoOptions {
|
|
16
24
|
skipConfigLoading?: boolean;
|
|
17
25
|
configPath?: string;
|
|
@@ -27,17 +35,42 @@ interface HtmlnanoOptions {
|
|
|
27
35
|
mergeStyles?: boolean;
|
|
28
36
|
mergeScripts?: boolean;
|
|
29
37
|
minifyCss?: Options | boolean;
|
|
38
|
+
minifyHtmlTemplate?: MinifyHtmlTemplateOptions;
|
|
30
39
|
minifyConditionalComments?: boolean;
|
|
31
40
|
minifyJs?: MinifyOptions | boolean;
|
|
32
41
|
minifyJson?: boolean;
|
|
42
|
+
minifyAttributes?: boolean | {
|
|
43
|
+
metaContent?: boolean;
|
|
44
|
+
redundantWhitespaces?: 'safe' | 'agressive' | false;
|
|
45
|
+
};
|
|
33
46
|
minifySvg?: Config | boolean;
|
|
34
47
|
normalizeAttributeValues?: boolean;
|
|
35
|
-
removeAttributeQuotes?: boolean
|
|
36
|
-
|
|
48
|
+
removeAttributeQuotes?: boolean | {
|
|
49
|
+
force?: boolean;
|
|
50
|
+
};
|
|
51
|
+
removeComments?: boolean | RegExp | ((comment: string) => boolean) | string;
|
|
37
52
|
removeEmptyAttributes?: boolean;
|
|
53
|
+
removeEmptyElements?: boolean | {
|
|
54
|
+
removeWithAttributes?: boolean;
|
|
55
|
+
};
|
|
38
56
|
removeRedundantAttributes?: boolean;
|
|
39
57
|
removeOptionalTags?: boolean;
|
|
40
|
-
removeUnusedCss?: boolean
|
|
58
|
+
removeUnusedCss?: boolean | ({
|
|
59
|
+
tool: 'purgeCSS';
|
|
60
|
+
} & Omit<UserDefinedOptions, 'content' | 'css' | 'extractors'>) | {
|
|
61
|
+
banner?: boolean;
|
|
62
|
+
csspath?: string;
|
|
63
|
+
htmlroot?: string;
|
|
64
|
+
ignore?: (string | RegExp)[];
|
|
65
|
+
inject?: string;
|
|
66
|
+
jsdom?: object;
|
|
67
|
+
media?: string[];
|
|
68
|
+
report?: boolean;
|
|
69
|
+
strictSSL?: boolean;
|
|
70
|
+
timeout?: number;
|
|
71
|
+
uncssrc?: string;
|
|
72
|
+
userAgent?: string;
|
|
73
|
+
};
|
|
41
74
|
sortAttributes?: boolean | 'alphabetical' | 'frequency';
|
|
42
75
|
sortAttributesWithLists?: boolean | 'alphabetical' | 'frequency';
|
|
43
76
|
}
|