html-minifier 3.5.16 → 3.5.20
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 +14 -16
- package/cli.js +1 -1
- package/package.json +7 -7
- package/src/htmlminifier.js +67 -57
- package/src/htmlparser.js +2 -2
package/README.md
CHANGED
|
@@ -3,14 +3,12 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/html-minifier)
|
|
4
4
|
[](https://travis-ci.org/kangax/html-minifier)
|
|
5
5
|
[](https://david-dm.org/kangax/html-minifier)
|
|
6
|
-
[](https://david-dm.org/kangax/html-minifier?type=dev)
|
|
7
|
-
[](https://gitter.im/kangax/html-minifier)
|
|
8
6
|
|
|
9
|
-
[HTMLMinifier](
|
|
7
|
+
[HTMLMinifier](https://kangax.github.io/html-minifier/) is a highly **configurable**, **well-tested**, JavaScript-based HTML minifier.
|
|
10
8
|
|
|
11
9
|
See [corresponding blog post](http://perfectionkills.com/experimenting-with-html-minifier/) for all the gory details of [how it works](http://perfectionkills.com/experimenting-with-html-minifier/#how_it_works), [description of each option](http://perfectionkills.com/experimenting-with-html-minifier/#options), [testing results](http://perfectionkills.com/experimenting-with-html-minifier/#field_testing) and [conclusions](http://perfectionkills.com/experimenting-with-html-minifier/#cost_and_benefits).
|
|
12
10
|
|
|
13
|
-
[Test suite is available online](
|
|
11
|
+
[Test suite is available online](https://kangax.github.io/html-minifier/tests/).
|
|
14
12
|
|
|
15
13
|
Also see corresponding [Ruby wrapper](https://github.com/stereobooster/html_minifier), and for Node.js, [Grunt plugin](https://github.com/gruntjs/grunt-contrib-htmlmin), [Gulp module](https://github.com/jonschlinkert/gulp-htmlmin), [Koa middleware wrapper](https://github.com/koajs/html-minifier) and [Express middleware wrapper](https://github.com/melonmanchan/express-minify-html).
|
|
16
14
|
|
|
@@ -22,19 +20,19 @@ How does HTMLMinifier compare to other solutions — [HTML Minifier from Will Pe
|
|
|
22
20
|
|
|
23
21
|
| Site | Original size *(KB)* | HTMLMinifier | minimize | Will Peavy | htmlcompressor.com |
|
|
24
22
|
| ---------------------------------------------------------------------------- |:--------------------:| ------------:| --------:| ----------:| ------------------:|
|
|
25
|
-
| [Google](https://www.google.com/) |
|
|
26
|
-
| [Twitter](https://twitter.com/) |
|
|
27
|
-
| [HTMLMinifier](https://github.com/kangax/html-minifier) |
|
|
28
|
-
| [New York Times](https://www.nytimes.com/) |
|
|
29
|
-
| [Stack Overflow](https://stackoverflow.com/) |
|
|
30
|
-
| [Bootstrap CSS](https://getbootstrap.com/docs/3.3/css/) |
|
|
31
|
-
| [BBC](https://www.bbc.co.uk/) |
|
|
32
|
-
| [Amazon](https://www.amazon.co.uk/) |
|
|
33
|
-
| [Wikipedia](https://en.wikipedia.org/wiki/President_of_the_United_States) |
|
|
34
|
-
| [NBC](https://www.nbc.com/) |
|
|
23
|
+
| [Google](https://www.google.com/) | 47 | **43** | 47 | 49 | 47 |
|
|
24
|
+
| [Twitter](https://twitter.com/) | 146 | **115** | 138 | 155 | 138 |
|
|
25
|
+
| [HTMLMinifier](https://github.com/kangax/html-minifier) | 171 | **128** | 143 | 148 | 142 |
|
|
26
|
+
| [New York Times](https://www.nytimes.com/) | 207 | **139** | 158 | 155 | 144 |
|
|
27
|
+
| [Stack Overflow](https://stackoverflow.com/) | 256 | **199** | 209 | 217 | 206 |
|
|
28
|
+
| [Bootstrap CSS](https://getbootstrap.com/docs/3.3/css/) | 271 | **260** | 269 | 229 | 269 |
|
|
29
|
+
| [BBC](https://www.bbc.co.uk/) | 294 | **238** | 285 | 289 | 278 |
|
|
30
|
+
| [Amazon](https://www.amazon.co.uk/) | 377 | **328** | 368 | 379 | n/a |
|
|
31
|
+
| [Wikipedia](https://en.wikipedia.org/wiki/President_of_the_United_States) | 520 | **484** | 504 | 523 | 503 |
|
|
32
|
+
| [NBC](https://www.nbc.com/) | 669 | **633** | 668 | 669 | n/a |
|
|
35
33
|
| [Eloquent Javascript](https://eloquentjavascript.net/1st_edition/print.html) | 870 | **815** | 840 | 864 | n/a |
|
|
36
|
-
| [ES6 table](https://kangax.github.io/compat-table/es6/) |
|
|
37
|
-
| [ES6 draft](https://tc39.github.io/ecma262/) |
|
|
34
|
+
| [ES6 table](https://kangax.github.io/compat-table/es6/) | 5243 | **4472** | 4963 | n/a | n/a |
|
|
35
|
+
| [ES6 draft](https://tc39.github.io/ecma262/) | 6072 | **5449** | 5615 | n/a | n/a |
|
|
38
36
|
|
|
39
37
|
## Options Quick Reference
|
|
40
38
|
|
package/cli.js
CHANGED
|
@@ -140,7 +140,7 @@ var mainOptionKeys = Object.keys(mainOptions);
|
|
|
140
140
|
mainOptionKeys.forEach(function(key) {
|
|
141
141
|
var option = mainOptions[key];
|
|
142
142
|
if (Array.isArray(option)) {
|
|
143
|
-
key = '--' + paramCase(key);
|
|
143
|
+
key = key === 'minifyURLs' ? '--minify-urls' : '--' + paramCase(key);
|
|
144
144
|
key += option[1] === parseJSON ? ' [value]' : ' <value>';
|
|
145
145
|
program.option(key, option[0], option[1]);
|
|
146
146
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "html-minifier",
|
|
3
3
|
"description": "Highly configurable, well-tested, JavaScript-based HTML minifier.",
|
|
4
|
-
"version": "3.5.
|
|
4
|
+
"version": "3.5.20",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
7
7
|
"compress",
|
|
@@ -23,11 +23,11 @@
|
|
|
23
23
|
"uglifier",
|
|
24
24
|
"uglify"
|
|
25
25
|
],
|
|
26
|
-
"homepage": "
|
|
26
|
+
"homepage": "https://kangax.github.io/html-minifier/",
|
|
27
27
|
"author": "Juriy \"kangax\" Zaytsev",
|
|
28
28
|
"maintainers": [
|
|
29
29
|
"Alex Lam <alexlamsl@gmail.com>",
|
|
30
|
-
"Juriy Zaytsev <kangax@gmail.com> (http://perfectionkills.com)"
|
|
30
|
+
"Juriy Zaytsev <kangax@gmail.com> (http://perfectionkills.com/)"
|
|
31
31
|
],
|
|
32
32
|
"contributors": [
|
|
33
33
|
"Gilmore Davidson (https://github.com/gilmoreorless)",
|
|
@@ -55,17 +55,17 @@
|
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
57
|
"camel-case": "3.0.x",
|
|
58
|
-
"clean-css": "4.
|
|
59
|
-
"commander": "2.
|
|
58
|
+
"clean-css": "4.2.x",
|
|
59
|
+
"commander": "2.17.x",
|
|
60
60
|
"he": "1.1.x",
|
|
61
61
|
"param-case": "2.1.x",
|
|
62
62
|
"relateurl": "0.2.x",
|
|
63
|
-
"uglify-js": "3.
|
|
63
|
+
"uglify-js": "3.4.x"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
66
|
"grunt": "1.0.x",
|
|
67
67
|
"grunt-browserify": "5.3.x",
|
|
68
|
-
"grunt-contrib-uglify": "3.
|
|
68
|
+
"grunt-contrib-uglify": "3.4.x",
|
|
69
69
|
"gruntify-eslint": "4.0.x",
|
|
70
70
|
"phantomjs-prebuilt": "2.1.x",
|
|
71
71
|
"qunit": "2.x"
|
package/src/htmlminifier.js
CHANGED
|
@@ -109,7 +109,7 @@ function isEventAttribute(attrName, options) {
|
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
function canRemoveAttributeQuotes(value) {
|
|
112
|
-
//
|
|
112
|
+
// https://mathiasbynens.be/notes/unquoted-attribute-values
|
|
113
113
|
return /^[^ \t\n\f\r"'`=<>]+$/.test(value);
|
|
114
114
|
}
|
|
115
115
|
|
|
@@ -335,23 +335,33 @@ function isMetaViewport(tag, attrs) {
|
|
|
335
335
|
}
|
|
336
336
|
}
|
|
337
337
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
function wrapInlineCSS(text) {
|
|
341
|
-
return '*{' + text + '}';
|
|
338
|
+
function ignoreCSS(id) {
|
|
339
|
+
return '/* clean-css ignore:start */' + id + '/* clean-css ignore:end */';
|
|
342
340
|
}
|
|
343
341
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
342
|
+
// Wrap CSS declarations for CleanCSS > 3.x
|
|
343
|
+
// See https://github.com/jakubpawlowicz/clean-css/issues/418
|
|
344
|
+
function wrapCSS(text, type) {
|
|
345
|
+
switch (type) {
|
|
346
|
+
case 'inline':
|
|
347
|
+
return '*{' + text + '}';
|
|
348
|
+
case 'media':
|
|
349
|
+
return '@media ' + text + '{a{top:0}}';
|
|
350
|
+
default:
|
|
351
|
+
return text;
|
|
352
|
+
}
|
|
351
353
|
}
|
|
352
354
|
|
|
353
|
-
function
|
|
354
|
-
var matches
|
|
355
|
+
function unwrapCSS(text, type) {
|
|
356
|
+
var matches;
|
|
357
|
+
switch (type) {
|
|
358
|
+
case 'inline':
|
|
359
|
+
matches = text.match(/^\*\{([\s\S]*)\}$/);
|
|
360
|
+
break;
|
|
361
|
+
case 'media':
|
|
362
|
+
matches = text.match(/^@media ([\s\S]*?)\s*{[\s\S]*}$/);
|
|
363
|
+
break;
|
|
364
|
+
}
|
|
355
365
|
return matches ? matches[1] : text;
|
|
356
366
|
}
|
|
357
367
|
|
|
@@ -374,7 +384,7 @@ function processScript(text, options, currentAttrs) {
|
|
|
374
384
|
// Tag omission rules from https://html.spec.whatwg.org/multipage/syntax.html#optional-tags
|
|
375
385
|
// with the following deviations:
|
|
376
386
|
// - retain <body> if followed by <noscript>
|
|
377
|
-
// - </rb>, </rt>, </rtc>, </rp> & </tfoot> follow
|
|
387
|
+
// - </rb>, </rt>, </rtc>, </rp> & </tfoot> follow https://www.w3.org/TR/html5/syntax.html#optional-tags
|
|
378
388
|
// - retain all tags which are adjacent to non-standard HTML tags
|
|
379
389
|
var optionalStartTags = createMapFromString('html,head,body,colgroup,tbody');
|
|
380
390
|
var optionalEndTags = createMapFromString('html,head,body,li,dt,dd,p,rb,rt,rtc,rp,optgroup,option,colgroup,caption,thead,tbody,tfoot,tr,td,th');
|
|
@@ -655,20 +665,7 @@ function processOptions(values) {
|
|
|
655
665
|
return prefix + quote + options.minifyURLs(url) + quote + suffix;
|
|
656
666
|
});
|
|
657
667
|
try {
|
|
658
|
-
|
|
659
|
-
text = wrapInlineCSS(text);
|
|
660
|
-
}
|
|
661
|
-
else if (type === 'media') {
|
|
662
|
-
text = wrapMediaQuery(text);
|
|
663
|
-
}
|
|
664
|
-
text = new CleanCSS(value).minify(text).styles;
|
|
665
|
-
if (type === 'inline') {
|
|
666
|
-
text = unwrapInlineCSS(text);
|
|
667
|
-
}
|
|
668
|
-
else if (type === 'media') {
|
|
669
|
-
text = unwrapMediaQuery(text);
|
|
670
|
-
}
|
|
671
|
-
return text;
|
|
668
|
+
return unwrapCSS(new CleanCSS(value).minify(wrapCSS(text, type)).styles, type);
|
|
672
669
|
}
|
|
673
670
|
catch (err) {
|
|
674
671
|
options.log(err);
|
|
@@ -859,15 +856,6 @@ function minify(value, options, partialMarkup) {
|
|
|
859
856
|
return token;
|
|
860
857
|
});
|
|
861
858
|
|
|
862
|
-
function escapeFragments(fn) {
|
|
863
|
-
return function(text, type) {
|
|
864
|
-
return fn(text.replace(uidPattern, function(match, prefix, index) {
|
|
865
|
-
var chunks = ignoredCustomMarkupChunks[+index];
|
|
866
|
-
return chunks[1] + uidAttr + index + chunks[2];
|
|
867
|
-
}), type);
|
|
868
|
-
};
|
|
869
|
-
}
|
|
870
|
-
|
|
871
859
|
var customFragments = options.ignoreCustomFragments.map(function(re) {
|
|
872
860
|
return re.source;
|
|
873
861
|
});
|
|
@@ -879,10 +867,38 @@ function minify(value, options, partialMarkup) {
|
|
|
879
867
|
uidAttr = uniqueId(value);
|
|
880
868
|
uidPattern = new RegExp('(\\s*)' + uidAttr + '([0-9]+)(\\s*)', 'g');
|
|
881
869
|
if (options.minifyCSS) {
|
|
882
|
-
options.minifyCSS =
|
|
870
|
+
options.minifyCSS = (function(fn) {
|
|
871
|
+
return function(text, type) {
|
|
872
|
+
text = text.replace(uidPattern, function(match, prefix, index) {
|
|
873
|
+
var chunks = ignoredCustomMarkupChunks[+index];
|
|
874
|
+
return chunks[1] + uidAttr + index + chunks[2];
|
|
875
|
+
});
|
|
876
|
+
var ids = [];
|
|
877
|
+
new CleanCSS().minify(wrapCSS(text, type)).warnings.forEach(function(warning) {
|
|
878
|
+
var match = uidPattern.exec(warning);
|
|
879
|
+
if (match) {
|
|
880
|
+
var id = uidAttr + match[2];
|
|
881
|
+
text = text.replace(id, ignoreCSS(id));
|
|
882
|
+
ids.push(id);
|
|
883
|
+
}
|
|
884
|
+
});
|
|
885
|
+
text = fn(text, type);
|
|
886
|
+
ids.forEach(function(id) {
|
|
887
|
+
text = text.replace(ignoreCSS(id), id);
|
|
888
|
+
});
|
|
889
|
+
return text;
|
|
890
|
+
};
|
|
891
|
+
})(options.minifyCSS);
|
|
883
892
|
}
|
|
884
893
|
if (options.minifyJS) {
|
|
885
|
-
options.minifyJS =
|
|
894
|
+
options.minifyJS = (function(fn) {
|
|
895
|
+
return function(text, type) {
|
|
896
|
+
return fn(text.replace(uidPattern, function(match, prefix, index) {
|
|
897
|
+
var chunks = ignoredCustomMarkupChunks[+index];
|
|
898
|
+
return chunks[1] + uidAttr + index + chunks[2];
|
|
899
|
+
}), type);
|
|
900
|
+
};
|
|
901
|
+
})(options.minifyJS);
|
|
886
902
|
}
|
|
887
903
|
}
|
|
888
904
|
var token = uidAttr + ignoredCustomMarkupChunks.length;
|
|
@@ -1220,7 +1236,7 @@ function minify(value, options, partialMarkup) {
|
|
|
1220
1236
|
buffer.push(text);
|
|
1221
1237
|
},
|
|
1222
1238
|
doctype: function(doctype) {
|
|
1223
|
-
buffer.push(options.useShortDoctype ? '<!
|
|
1239
|
+
buffer.push(options.useShortDoctype ? '<!doctype html>' : collapseWhitespaceAll(doctype));
|
|
1224
1240
|
},
|
|
1225
1241
|
customAttrAssign: options.customAttrAssign,
|
|
1226
1242
|
customAttrSurround: options.customAttrSurround
|
|
@@ -1241,10 +1257,8 @@ function minify(value, options, partialMarkup) {
|
|
|
1241
1257
|
squashTrailingWhitespace('br');
|
|
1242
1258
|
}
|
|
1243
1259
|
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
if (uidPattern) {
|
|
1247
|
-
str = str.replace(uidPattern, function(match, prefix, index, suffix) {
|
|
1260
|
+
return joinResultSegments(buffer, options, uidPattern ? function(str) {
|
|
1261
|
+
return str.replace(uidPattern, function(match, prefix, index, suffix) {
|
|
1248
1262
|
var chunk = ignoredCustomMarkupChunks[+index][0];
|
|
1249
1263
|
if (options.collapseWhitespace) {
|
|
1250
1264
|
if (prefix !== '\t') {
|
|
@@ -1260,17 +1274,14 @@ function minify(value, options, partialMarkup) {
|
|
|
1260
1274
|
}
|
|
1261
1275
|
return chunk;
|
|
1262
1276
|
});
|
|
1263
|
-
}
|
|
1264
|
-
|
|
1265
|
-
str = str.replace(new RegExp('<!--' + uidIgnore + '([0-9]+)-->', 'g'), function(match, index) {
|
|
1277
|
+
} : identity, uidIgnore ? function(str) {
|
|
1278
|
+
return str.replace(new RegExp('<!--' + uidIgnore + '([0-9]+)-->', 'g'), function(match, index) {
|
|
1266
1279
|
return ignoredMarkupChunks[+index];
|
|
1267
1280
|
});
|
|
1268
|
-
}
|
|
1269
|
-
|
|
1270
|
-
return str;
|
|
1281
|
+
} : identity);
|
|
1271
1282
|
}
|
|
1272
1283
|
|
|
1273
|
-
function joinResultSegments(results, options) {
|
|
1284
|
+
function joinResultSegments(results, options, restoreCustom, restoreIgnore) {
|
|
1274
1285
|
var str;
|
|
1275
1286
|
var maxLineLength = options.maxLineLength;
|
|
1276
1287
|
if (maxLineLength) {
|
|
@@ -1279,13 +1290,13 @@ function joinResultSegments(results, options) {
|
|
|
1279
1290
|
var len = line.length;
|
|
1280
1291
|
var end = results[0].indexOf('\n');
|
|
1281
1292
|
if (end < 0) {
|
|
1282
|
-
line += results.shift();
|
|
1293
|
+
line += restoreIgnore(restoreCustom(results.shift()));
|
|
1283
1294
|
}
|
|
1284
1295
|
else {
|
|
1285
|
-
line += results[0].slice(0, end);
|
|
1296
|
+
line += restoreIgnore(restoreCustom(results[0].slice(0, end)));
|
|
1286
1297
|
results[0] = results[0].slice(end + 1);
|
|
1287
1298
|
}
|
|
1288
|
-
if (len > 0 && line.length
|
|
1299
|
+
if (len > 0 && line.length > maxLineLength) {
|
|
1289
1300
|
lines.push(line.slice(0, len));
|
|
1290
1301
|
line = line.slice(len);
|
|
1291
1302
|
}
|
|
@@ -1297,11 +1308,10 @@ function joinResultSegments(results, options) {
|
|
|
1297
1308
|
if (line) {
|
|
1298
1309
|
lines.push(line);
|
|
1299
1310
|
}
|
|
1300
|
-
|
|
1301
1311
|
str = lines.join('\n');
|
|
1302
1312
|
}
|
|
1303
1313
|
else {
|
|
1304
|
-
str = results.join('');
|
|
1314
|
+
str = restoreIgnore(restoreCustom(results.join('')));
|
|
1305
1315
|
}
|
|
1306
1316
|
return options.collapseWhitespace ? collapseWhitespace(str, options, true, true) : str;
|
|
1307
1317
|
}
|
package/src/htmlparser.js
CHANGED
|
@@ -60,7 +60,7 @@ var singleAttrIdentifier = /([^\s"'<>/=]+)/,
|
|
|
60
60
|
startTagOpen = new RegExp('^<' + qnameCapture),
|
|
61
61
|
startTagClose = /^\s*(\/?)>/,
|
|
62
62
|
endTag = new RegExp('^<\\/' + qnameCapture + '[^>]*>'),
|
|
63
|
-
doctype = /^<!DOCTYPE
|
|
63
|
+
doctype = /^<!DOCTYPE\s[^>]+>/i;
|
|
64
64
|
|
|
65
65
|
var IS_REGEX_CAPTURING_BROKEN = false;
|
|
66
66
|
'x'.replace(/x(.)?/g, function(m, g) {
|
|
@@ -140,7 +140,7 @@ function HTMLParser(html, handler) {
|
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
-
//
|
|
143
|
+
// https://en.wikipedia.org/wiki/Conditional_comment#Downlevel-revealed_conditional_comment
|
|
144
144
|
if (/^<!\[/.test(html)) {
|
|
145
145
|
var conditionalEnd = html.indexOf(']>');
|
|
146
146
|
|