html-minifier 1.3.1 → 1.4.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 +6 -7
- package/cli.js +72 -76
- package/dist/htmlminifier.js +32448 -1587
- package/dist/htmlminifier.min.js +14 -2
- package/package.json +4 -9
- package/sample-cli-config-file.conf +6 -4
- package/src/htmllint.js +139 -142
- package/src/htmlminifier.js +933 -1004
- package/src/htmlparser.js +414 -425
- package/src/utils.js +18 -0
package/README.md
CHANGED
|
@@ -21,24 +21,23 @@ How does HTMLMinifier compare to other solutions — [HTML Minifier from Will Pe
|
|
|
21
21
|
| Site | Original size *(KB)* | HTMLMinifier | minimize | Will Peavy | htmlcompressor.com |
|
|
22
22
|
| --------------------------------------------------------------------------- |:--------------------:| ------------:| --------:| ----------:| ------------------:|
|
|
23
23
|
| [HTMLMinifier page](https://github.com/kangax/html-minifier) | 49 | **37** | 42 | 44 | 43 |
|
|
24
|
-
| [NBC](http://www.nbc.com/) | 91 | **74** | 84 |
|
|
25
|
-
| [ES6 table](http://kangax.github.io/es5-compat-table/es6/) | 118 | **80** | 93 |
|
|
24
|
+
| [NBC](http://www.nbc.com/) | 91 | **74** | 84 | 85 | 85 |
|
|
25
|
+
| [ES6 table](http://kangax.github.io/es5-compat-table/es6/) | 118 | **80** | 93 | 93 | 94 |
|
|
26
26
|
| [New York Times](http://www.nytimes.com/) | 131 | **101** | 122 | 125 | 120 |
|
|
27
27
|
| [Google](https://www.google.com/) | 133 | **128** | 132 | 135 | 131 |
|
|
28
28
|
| [MSN](http://www.msn.com/) | 157 | **130** | 138 | 145 | 138 |
|
|
29
|
-
| [Stackoverflow](http://stackoverflow.com/) | 200 | **159** | 165 |
|
|
30
|
-
| [Amazon](http://www.amazon.com/) | 246 | **
|
|
29
|
+
| [Stackoverflow](http://stackoverflow.com/) | 200 | **159** | 165 | 173 | 166 |
|
|
30
|
+
| [Amazon](http://www.amazon.com/) | 246 | **203** | 234 | 230 | 219 |
|
|
31
|
+
| [Bootstrap CSS](http://getbootstrap.com/css/) | 277 | **268** | 274 | 232 | 277 |
|
|
31
32
|
| [Wikipedia](https://en.wikipedia.org/wiki/President_of_the_United_States) | 401 | **367** | 388 | 400 | n/a |
|
|
32
33
|
| [Eloquent Javascript](http://eloquentjavascript.net/1st_edition/print.html) | 870 | **827** | 840 | 864 | n/a |
|
|
33
|
-
| [ES6 draft](https://tc39.github.io/ecma262/) | 3678 | **
|
|
34
|
+
| [ES6 draft](https://tc39.github.io/ecma262/) | 3678 | **2991** | 3079 | 3183 | n/a |
|
|
34
35
|
|
|
35
36
|
## Options Quick Reference
|
|
36
37
|
|
|
37
38
|
| Option | Description | Default |
|
|
38
39
|
|--------------------------------|-----------------|---------|
|
|
39
40
|
| `removeComments` | [Strip HTML comments](http://perfectionkills.com/experimenting-with-html-minifier/#remove_comments) | `false` |
|
|
40
|
-
| `removeCommentsFromCDATA` | [Strip HTML comments from scripts and styles](http://perfectionkills.com/experimenting-with-html-minifier/#remove_comments_from_scripts_and_styles) | `false` |
|
|
41
|
-
| `removeCDATASectionsFromCDATA` | [Remove CDATA sections from script and style elements](http://perfectionkills.com/experimenting-with-html-minifier/#remove_cdata_sections) | `false` |
|
|
42
41
|
| `collapseWhitespace` | [Collapse white space that contributes to text nodes in a document tree.](http://perfectionkills.com/experimenting-with-html-minifier/#collapse_whitespace) | `false` |
|
|
43
42
|
| `conservativeCollapse` | Always collapse to 1 space (never remove it entirely). Must be used in conjunction with `collapseWhitespace=true` | `false` |
|
|
44
43
|
| `collapseInlineTagWhitespace` | Don't leave any spaces between `display:inline;` elements when collapsing. Must be used in conjunction with `collapseWhitespace=true` | `false` |
|
package/cli.js
CHANGED
|
@@ -34,11 +34,10 @@ var path = require('path');
|
|
|
34
34
|
var fs = require('fs');
|
|
35
35
|
var appName = require('./package.json').name;
|
|
36
36
|
var appVersion = require('./package.json').version;
|
|
37
|
-
var minify = require('
|
|
38
|
-
var HTMLLint = require('./
|
|
37
|
+
var minify = require('.').minify;
|
|
38
|
+
var HTMLLint = require('./src/htmllint').HTMLLint;
|
|
39
39
|
var minifyOptions = {};
|
|
40
|
-
var
|
|
41
|
-
var output = null;
|
|
40
|
+
var output;
|
|
42
41
|
|
|
43
42
|
cli.width = 100;
|
|
44
43
|
cli.option_width = 40;
|
|
@@ -55,38 +54,40 @@ usage += ' on the command line you must escape those such as --ignore-custom-
|
|
|
55
54
|
cli.setUsage(usage);
|
|
56
55
|
|
|
57
56
|
var mainOptions = {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
caseSensitive: [[false, 'Treat attributes in case sensitive manner (useful for SVG; e.g. viewBox)']],
|
|
58
|
+
collapseBooleanAttributes: [[false, 'Omit attribute values from boolean attributes']],
|
|
59
|
+
collapseInlineTagWhitespace: [[false, 'Collapse white space around inline tag']],
|
|
61
60
|
collapseWhitespace: [[false, 'Collapse white space that contributes to text nodes in a document tree.']],
|
|
62
61
|
conservativeCollapse: [[false, 'Always collapse to 1 space (never remove it entirely)']],
|
|
62
|
+
customAttrAssign: [[false, 'Arrays of regex\'es that allow to support custom attribute assign expressions (e.g. \'<div flex?="{{mode != cover}}"></div>\')', 'string'], 'json-regex'],
|
|
63
|
+
customAttrCollapse: [[false, 'Regex that specifies custom attribute to strip newlines from (e.g. /ng\-class/)', 'string'], 'string-regex'],
|
|
64
|
+
customAttrSurround: [[false, 'Arrays of regex\'es that allow to support custom attribute surround expressions (e.g. <input {{#if value}}checked="checked"{{/if}}>)', 'string'], 'json-regex'],
|
|
65
|
+
customEventAttributes: [[false, 'Arrays of regex\'es that allow to support custom event attributes for minifyJS (e.g. ng-click)', 'string'], 'json-regex'],
|
|
66
|
+
html5: [[false, 'Parse input according to HTML5 specifications']],
|
|
67
|
+
ignoreCustomComments: [[false, 'Array of regex\'es that allow to ignore certain comments, when matched', 'string'], 'json-regex'],
|
|
68
|
+
ignoreCustomFragments: [[false, 'Array of regex\'es that allow to ignore certain fragments, when matched (e.g. <?php ... ?>, {{ ... }})', 'string'], 'json-regex'],
|
|
69
|
+
includeAutoGeneratedTags: [[false, 'Insert tags generated by HTML parser'], true],
|
|
70
|
+
keepClosingSlash: [[false, 'Keep the trailing slash on singleton elements']],
|
|
71
|
+
lint: [[false, 'Toggle linting']],
|
|
72
|
+
maxLineLength: [[false, 'Max line length', 'number'], true],
|
|
73
|
+
minifyCSS: [[false, 'Minify CSS in style elements and style attributes (uses clean-css)']],
|
|
74
|
+
minifyJS: [[false, 'Minify Javascript in script elements and on* attributes (uses UglifyJS)']],
|
|
75
|
+
minifyURLs: [[false, 'Minify URLs in various attributes (uses relateurl)', 'string'], 'site-url'],
|
|
63
76
|
preserveLineBreaks: [[false, 'Always collapse to 1 line break (never remove it entirely) when whitespace between tags include a line break.']],
|
|
64
|
-
collapseInlineTagWhitespace: [[false, 'Collapse white space around inline tag']],
|
|
65
|
-
collapseBooleanAttributes: [[false, 'Omit attribute values from boolean attributes']],
|
|
66
|
-
removeTagWhitespace: [[false, 'Remove space between attributes whenever possible.']],
|
|
67
|
-
removeAttributeQuotes: [[false, 'Remove quotes around attributes when possible.']],
|
|
68
|
-
removeRedundantAttributes: [[false, 'Remove attributes when value matches default.']],
|
|
69
77
|
preventAttributesEscaping: [[false, 'Prevents the escaping of the values of attributes.']],
|
|
70
|
-
|
|
78
|
+
processConditionalComments: [[false, 'Process contents of conditional comments through minifier']],
|
|
79
|
+
processScripts: [[false, 'Array of strings corresponding to types of script elements to process through minifier (e.g. "text/ng-template", "text/x-handlebars-template", etc.)', 'string'], 'json'],
|
|
80
|
+
quoteCharacter: [[false, 'Type of quote to use for attribute values (\' or ")', 'string'], true],
|
|
81
|
+
removeAttributeQuotes: [[false, 'Remove quotes around attributes when possible.']],
|
|
82
|
+
removeComments: [[false, 'Strip HTML comments']],
|
|
71
83
|
removeEmptyAttributes: [[false, 'Remove all attributes with whitespace-only values']],
|
|
84
|
+
removeEmptyElements: [[false, 'Remove all elements with empty contents']],
|
|
85
|
+
removeOptionalTags: [[false, 'Remove unrequired tags']],
|
|
86
|
+
removeRedundantAttributes: [[false, 'Remove attributes when value matches default.']],
|
|
72
87
|
removeScriptTypeAttributes: [[false, 'Remove type="text/javascript" from script tags. Other type attribute values are left intact.']],
|
|
73
88
|
removeStyleLinkTypeAttributes: [[false, 'Remove type="text/css" from style and link tags. Other type attribute values are left intact.']],
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
lint: [[false, 'Toggle linting']],
|
|
77
|
-
keepClosingSlash: [[false, 'Keep the trailing slash on singleton elements']],
|
|
78
|
-
caseSensitive: [[false, 'Treat attributes in case sensitive manner (useful for SVG; e.g. viewBox)']],
|
|
79
|
-
minifyJS: [[false, 'Minify Javascript in script elements and on* attributes (uses UglifyJS)']],
|
|
80
|
-
minifyCSS: [[false, 'Minify CSS in style elements and style attributes (uses clean-css)']],
|
|
81
|
-
minifyURLs: [[false, 'Minify URLs in various attributes (uses relateurl)', 'string'], 'site-url'],
|
|
82
|
-
ignoreCustomComments: [[false, 'Array of regex\'es that allow to ignore certain comments, when matched', 'string'], 'json-regex'],
|
|
83
|
-
ignoreCustomFragments: [[false, 'Array of regex\'es that allow to ignore certain fragments, when matched (e.g. <?php ... ?>, {{ ... }})', 'string'], 'json-regex'],
|
|
84
|
-
processScripts: [[false, 'Array of strings corresponding to types of script elements to process through minifier (e.g. "text/ng-template", "text/x-handlebars-template", etc.)', 'string'], 'json'],
|
|
85
|
-
maxLineLength: [[false, 'Max line length', 'number'], true],
|
|
86
|
-
customEventAttributes: [[false, 'Arrays of regex\'es that allow to support custom event attributes for minifyJS (e.g. ng-click)', 'string'], 'json-regex'],
|
|
87
|
-
customAttrAssign: [[false, 'Arrays of regex\'es that allow to support custom attribute assign expressions (e.g. \'<div flex?="{{mode != cover}}"></div>\')', 'string'], 'json-regex'],
|
|
88
|
-
customAttrSurround: [[false, 'Arrays of regex\'es that allow to support custom attribute surround expressions (e.g. <input {{#if value}}checked="checked"{{/if}}>)', 'string'], 'json-regex'],
|
|
89
|
-
customAttrCollapse: [[false, 'Regex that specifies custom attribute to strip newlines from (e.g. /ng\-class/)', 'string'], 'string-regex']
|
|
89
|
+
removeTagWhitespace: [[false, 'Remove space between attributes whenever possible.']],
|
|
90
|
+
useShortDoctype: [[false, 'Replaces the doctype with the short (HTML5) doctype']]
|
|
90
91
|
};
|
|
91
92
|
|
|
92
93
|
var cliOptions = {
|
|
@@ -133,27 +134,19 @@ cli.main(function(args, options) {
|
|
|
133
134
|
}
|
|
134
135
|
}
|
|
135
136
|
|
|
136
|
-
function parseJSONOption(value,
|
|
137
|
-
var opts = options || {};
|
|
137
|
+
function parseJSONOption(value, regexArray) {
|
|
138
138
|
if (value !== null) {
|
|
139
139
|
var jsonArray;
|
|
140
140
|
try {
|
|
141
141
|
jsonArray = JSON.parse(value);
|
|
142
|
-
if (
|
|
143
|
-
jsonArray = jsonArray.map(
|
|
144
|
-
return stringToRegExp(regexString);
|
|
145
|
-
});
|
|
142
|
+
if (regexArray) {
|
|
143
|
+
jsonArray = jsonArray.map(stringToRegExp);
|
|
146
144
|
}
|
|
147
145
|
}
|
|
148
146
|
catch (e) {
|
|
149
147
|
cli.fatal('Could not parse JSON value \'' + value + '\'');
|
|
150
148
|
}
|
|
151
|
-
|
|
152
|
-
return jsonArray;
|
|
153
|
-
}
|
|
154
|
-
else {
|
|
155
|
-
return [value];
|
|
156
|
-
}
|
|
149
|
+
return Array.isArray(jsonArray) ? jsonArray : [value];
|
|
157
150
|
}
|
|
158
151
|
}
|
|
159
152
|
|
|
@@ -175,19 +168,17 @@ cli.main(function(args, options) {
|
|
|
175
168
|
|
|
176
169
|
if (minified !== null) {
|
|
177
170
|
// Write the output
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
if (output != null) {
|
|
171
|
+
if (output) {
|
|
172
|
+
try {
|
|
181
173
|
fs.writeFileSync(path.resolve(output), minified);
|
|
182
174
|
}
|
|
183
|
-
|
|
184
|
-
|
|
175
|
+
catch (e) {
|
|
176
|
+
status = 4;
|
|
177
|
+
cli.error('Cannot write to ' + output);
|
|
185
178
|
}
|
|
186
179
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
console.log(output);
|
|
190
|
-
cli.error('Cannot write to output');
|
|
180
|
+
else {
|
|
181
|
+
process.stdout.write(minified);
|
|
191
182
|
}
|
|
192
183
|
}
|
|
193
184
|
|
|
@@ -235,40 +226,51 @@ cli.main(function(args, options) {
|
|
|
235
226
|
}
|
|
236
227
|
|
|
237
228
|
if (options['config-file']) {
|
|
238
|
-
var
|
|
239
|
-
var fileOptionsPath = path.resolve(options['config-file']);
|
|
229
|
+
var configPath = path.resolve(options['config-file']);
|
|
240
230
|
try {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
231
|
+
var configData;
|
|
232
|
+
try {
|
|
233
|
+
configData = fs.readFileSync(configPath, { encoding: 'utf8' });
|
|
234
|
+
}
|
|
235
|
+
catch (e) {
|
|
236
|
+
cli.fatal('The specified config file doesn’t exist or is unreadable:\n' + configPath);
|
|
237
|
+
}
|
|
238
|
+
configData = JSON.parse(configData);
|
|
239
|
+
mainOptionKeys.forEach(function(key) {
|
|
240
|
+
var value = configData[key];
|
|
241
|
+
if (value !== undefined) {
|
|
242
|
+
switch (mainOptions[key][1]) {
|
|
243
|
+
case 'json-regex':
|
|
244
|
+
minifyOptions[key] = value.map(stringToRegExp);
|
|
245
|
+
break;
|
|
246
|
+
case 'string-regex':
|
|
247
|
+
minifyOptions[key] = stringToRegExp(value);
|
|
248
|
+
break;
|
|
249
|
+
default:
|
|
250
|
+
minifyOptions[key] = value;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
});
|
|
248
254
|
}
|
|
249
255
|
catch (je) {
|
|
250
256
|
try {
|
|
251
|
-
|
|
257
|
+
minifyOptions = require(configPath);
|
|
252
258
|
}
|
|
253
259
|
catch (ne) {
|
|
254
|
-
cli.fatal('Cannot read the specified config file
|
|
260
|
+
cli.fatal('Cannot read the specified config file.\nAs JSON: ' + je.message + '\nAs module: ' + ne.message);
|
|
255
261
|
}
|
|
256
262
|
}
|
|
257
|
-
|
|
258
|
-
if (fileOptions && typeof fileOptions === 'object') {
|
|
259
|
-
minifyOptions = fileOptions;
|
|
260
|
-
}
|
|
261
263
|
}
|
|
262
264
|
mainOptionKeys.forEach(function(key) {
|
|
263
265
|
var paramKey = changeCase.paramCase(key);
|
|
264
266
|
var value = options[paramKey];
|
|
265
|
-
if (
|
|
267
|
+
if (value !== null) {
|
|
266
268
|
switch (mainOptions[key][1]) {
|
|
267
269
|
case 'json':
|
|
268
270
|
minifyOptions[key] = parseJSONOption(value);
|
|
269
271
|
break;
|
|
270
272
|
case 'json-regex':
|
|
271
|
-
minifyOptions[key] = parseJSONOption(value,
|
|
273
|
+
minifyOptions[key] = parseJSONOption(value, true);
|
|
272
274
|
break;
|
|
273
275
|
case 'string-regex':
|
|
274
276
|
minifyOptions[key] = stringToRegExp(value);
|
|
@@ -289,10 +291,6 @@ cli.main(function(args, options) {
|
|
|
289
291
|
minifyOptions.lint = new HTMLLint();
|
|
290
292
|
}
|
|
291
293
|
|
|
292
|
-
if (args.length) {
|
|
293
|
-
input = args;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
294
|
if (options['input-dir'] || options['output-dir']) {
|
|
297
295
|
var inputDir = options['input-dir'];
|
|
298
296
|
var outputDir = options['output-dir'];
|
|
@@ -330,11 +328,10 @@ cli.main(function(args, options) {
|
|
|
330
328
|
output = options.output;
|
|
331
329
|
}
|
|
332
330
|
|
|
333
|
-
if (
|
|
334
|
-
|
|
331
|
+
if (args.length) { // Minifying one or more files specified on the CMD line
|
|
335
332
|
var original = '';
|
|
336
333
|
|
|
337
|
-
|
|
334
|
+
args.forEach(function(afile) {
|
|
338
335
|
try {
|
|
339
336
|
original += fs.readFileSync(afile, 'utf8');
|
|
340
337
|
}
|
|
@@ -345,11 +342,10 @@ cli.main(function(args, options) {
|
|
|
345
342
|
});
|
|
346
343
|
|
|
347
344
|
cli.exit(runMinify(original, output));
|
|
348
|
-
|
|
349
345
|
}
|
|
350
346
|
else { // Minifying input coming from STDIN
|
|
351
347
|
process.stdin.pipe(concat({ encoding: 'string' }, function(content) {
|
|
352
|
-
runMinify(content, output);
|
|
348
|
+
cli.exit(runMinify(content, output));
|
|
353
349
|
}));
|
|
354
350
|
}
|
|
355
351
|
});
|