From ada82fa7e10878cdbd1dacfa797267205fe6f418 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20M=C3=A9tais?= Date: Sun, 27 Mar 2016 17:09:23 +0300 Subject: [PATCH 01/22] Should fix uglify infinite loop on already uglyfied files that crashes YLT --- lib/tools/weightChecker/fileMinifier.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/tools/weightChecker/fileMinifier.js b/lib/tools/weightChecker/fileMinifier.js index 3e3f0b0..45dc14e 100644 --- a/lib/tools/weightChecker/fileMinifier.js +++ b/lib/tools/weightChecker/fileMinifier.js @@ -146,7 +146,16 @@ var FileMinifier = function() { .delay(1) .then(splittedUglifyStep2) .delay(1) - .then(splittedUglifyStep3) + .then(function(ast) { + // Only do the compression step for smaller files + // otherwise it can take a very long time compared to the gain + if (body.length < 200*1024) { + return splittedUglifyStep3(ast); + } else { + debug('Skipping step 3 because the file is too big (%d bytes)!', body.length); + return ast; + } + }) .delay(1) .then(splittedUglifyStep4) .delay(1) @@ -311,9 +320,9 @@ var FileMinifier = function() { return result; } - // Avoid loosing tome trying to compress JS files if they alreay look minified + // Avoid loosing some trying to compress JS files if they alreay look minified // by counting the number of lines compared to the total size. - // Less than 1000kb per line is suspicious + // Less than 1KB per line is suspicious function looksAlreadyMinified(code) { var linesCount = code.split(/\r\n|\r|\n/).length; var linesRatio = code.length / linesCount; From 3ff23e1c476b1e9edddf5549d15ac9b0174b67d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20M=C3=A9tais?= Date: Sun, 27 Mar 2016 17:18:28 +0300 Subject: [PATCH 02/22] Ignore 1x1 images in hiddenImages rule --- .../custom_modules/modules/domHiddenYLT/domHiddenYLT.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/tools/phantomas/custom_modules/modules/domHiddenYLT/domHiddenYLT.js b/lib/tools/phantomas/custom_modules/modules/domHiddenYLT/domHiddenYLT.js index 097aef7..a90e2bf 100644 --- a/lib/tools/phantomas/custom_modules/modules/domHiddenYLT/domHiddenYLT.js +++ b/lib/tools/phantomas/custom_modules/modules/domHiddenYLT/domHiddenYLT.js @@ -52,6 +52,8 @@ exports.module = function(phantomas) { if (src === '' || src.indexOf('data:image') === 0) continue; + if (images[i].width === 1 && images[i].height === 1) continue; + if (!lazyLoadableImages[src]) { path = phantomas.getDOMPath(images[i]); From 326bfc035f4479b1f262c82d6da79b1b03bd7f2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20M=C3=A9tais?= Date: Sun, 27 Mar 2016 17:35:01 +0300 Subject: [PATCH 03/22] Update rule explaination --- lib/metadata/policies.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/metadata/policies.js b/lib/metadata/policies.js index 9c7b9e2..40a1b38 100644 --- a/lib/metadata/policies.js +++ b/lib/metadata/policies.js @@ -1075,7 +1075,7 @@ var policies = { "hiddenImages": { "tool": "phantomas", "label": "Hidden images", - "message": "

List of all images that have a display:none property, or one of their parents. These images are loaded by the browser even if they're not visible. You might be able to find a way to lazy-load them, only when they get visible.

Trackers are an exception, you'd better hide them.

", + "message": "

List of all images that have a display:none property, or one of their parents. These images are loaded by the browser even if they're not visible. You might be able to find a way to lazy-load them, only when they get visible.

As images displayed in 1x1 pixels tend to be trackers, they are excluded from this rule.

", "isOkThreshold": 1, "isBadThreshold": 12, "isAbnormalThreshold": 30, From aee81cb8243dad6f9f0e8123c4ea8da7448e1853 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20M=C3=A9tais?= Date: Sun, 27 Mar 2016 21:24:27 +0300 Subject: [PATCH 04/22] Change the way offenders are displayed for some CSS related rules --- front/src/views/rule.html | 90 +++++++----- lib/metadata/policies.js | 301 +++++++++++++++++--------------------- lib/offendersHelpers.js | 21 +++ 3 files changed, 213 insertions(+), 199 deletions(-) diff --git a/front/src/views/rule.html b/front/src/views/rule.html index d6a83e8..eb14e77 100644 --- a/front/src/views/rule.html +++ b/front/src/views/rule.html @@ -30,7 +30,7 @@

This rule reached the abnormality threshold, which means there is a real problem you should care about.

-

+

@@ -106,20 +106,14 @@
{{offender.color1}}
{{offender.color2}}
-
- {{offender.query}} for - -
-
{{offender.error}} (Check on the W3C validator)
-
- - {{offender.css}} +
+ {{offender.css}}
@@ -127,32 +121,6 @@ {{offender.rule}} (x{{offender.occurrences}})
-
- Property {{offender.property}} duplicated in {{offender.rule}} { } - -
- -
- {{offender.css}} { } - -
- -
- {{offender.rule}} {{ '{' + offender.property}}: expression({{offender.expression}})} - -
- -
- {{offender.rule}} {{ '{' + offender.property}}: {{offender.value}} !important} - -
- -
- {{offender.browser}} fix: - - -
-
{{offender.property}} {{offender.message}}
@@ -195,7 +163,57 @@
-
+
+

+ + in + + inline CSS +

+ +
+
+
+ + {{offender.css}} + @ {{offender.line}}:{{offender.column}} +
+ +
+ {{offender.query}} for + @ {{offender.line}}:{{offender.column}} +
+ +
+ Property {{offender.property}} duplicated in {{offender.rule}} { } + @ {{offender.line}}:{{offender.column}} +
+ +
+ {{offender.css}} { } + @ {{offender.line}}:{{offender.column}} +
+ +
+ {{offender.rule}} {{ '{' + offender.property}}: expression({{offender.expression}})} + @ {{offender.line}}:{{offender.column}} +
+ +
+ {{offender.rule}} {{ '{' + offender.property}}: {{offender.value}} !important} + @ {{offender.line}}:{{offender.column}} +
+ +
+ {{offender.browser}} fix: + + @ {{offender.line}}:{{offender.column}} +
+
+
+
+ +
diff --git a/lib/metadata/policies.js b/lib/metadata/policies.js index 40a1b38..fdd0881 100644 --- a/lib/metadata/policies.js +++ b/lib/metadata/policies.js @@ -462,19 +462,18 @@ var policies = { "cssComplexSelectors": { "tool": "phantomas", "label": "Complex selectors", - "message": "

Complex selectors are CSS selectors with 4 or more expressions, like \"#header ul li .foo\".

They are adding more work for the browser, and this could be avoided by simplifying selectors.

", + "message": "

Complex selectors are CSS selectors with 4 or more expressions, like \"#header ul li .foo\".

They are adding more work for the browser, and this could be avoided by simplifying selectors. The B.E.M. methodology is an useful way to simplify your CSS.

", "isOkThreshold": 0, "isBadThreshold": 600, "isAbnormalThreshold": 2000, "hasOffenders": true, "offendersTransformFn": function(offenders) { - return { - count: offenders.length, - list: offenders.map(function(offender) { - var splittedOffender = offendersHelpers.cssOffenderPattern(offender); - return splittedOffender; - }) - }; + var parsedOffenders = offenders.map(function(offender) { + var splittedOffender = offendersHelpers.cssOffenderPattern(offender); + return splittedOffender; + }); + + return offendersHelpers.orderByFile(parsedOffenders); } }, "cssComplexSelectorsByAttribute": { @@ -486,16 +485,13 @@ var policies = { "isAbnormalThreshold": 150, "hasOffenders": true, "offendersTransformFn": function(offenders) { - return { - count: offenders.length, - list: offenders.map(function(offender) { - var splittedOffender = offendersHelpers.cssOffenderPattern(offender); + var parsedOffenders = offenders.map(function(offender) { + var splittedOffender = offendersHelpers.cssOffenderPattern(offender); + splittedOffender.bolded = splittedOffender.css.replace(/(\[[^ ]+[~\|\^\$\*]=["']?[^"'\]]+["']?\])/g, '$1'); + return splittedOffender; + }); - splittedOffender.bolded = splittedOffender.css.replace(/(\[[^ ]+[~\|\^\$\*]="[^"]+"\])/g, '$1'); - - return splittedOffender; - }) - }; + return offendersHelpers.orderByFile(parsedOffenders); } }, "cssColors": { @@ -590,10 +586,7 @@ var policies = { "isAbnormalThreshold": 1000, "hasOffenders": true, "offendersTransformFn": function(offenders) { - return { - count: offenders.length, - list: offenders - }; + return offendersHelpers.orderByFile(offenders); } }, "cssImports": { @@ -652,29 +645,28 @@ var policies = { "isAbnormalThreshold": 120, "hasOffenders": true, "offendersTransformFn": function(offenders) { - return { - count: offenders.length, - list: offenders.map(function(offender) { - var splittedOffender = offendersHelpers.cssOffenderPattern(offender); + var parsedOffenders = offenders.map(function(offender) { + var splittedOffender = offendersHelpers.cssOffenderPattern(offender); - var parts = /^([^{]+) {([^ ]+): (.+)}$/.exec(splittedOffender.css); - - if (!parts) { - debug('cssDuplicatedProperties offenders transform function error with "%s"', offender); - return { - parseError: offender - }; - } + var parts = /^([^{]+) {([^ ]+): (.+)}$/.exec(splittedOffender.css); + if (!parts) { + debug('cssDuplicatedProperties offenders transform function error with "%s"', offender); return { - property: parts[2], - rule: parts[1], - file: splittedOffender.file, - line: splittedOffender.line, - column: splittedOffender.column + parseError: offender }; - }) - }; + } + + return { + property: parts[2], + rule: parts[1], + file: splittedOffender.file, + line: splittedOffender.line, + column: splittedOffender.column + }; + }); + + return offendersHelpers.orderByFile(parsedOffenders); } }, "cssEmptyRules": { @@ -686,14 +678,8 @@ var policies = { "isAbnormalThreshold": 100, "hasOffenders": true, "offendersTransformFn": function(offenders) { - return { - count: offenders.length, - list: offenders.map(function(offender) { - var splittedOffender = offendersHelpers.cssOffenderPattern(offender); - - return splittedOffender; - }) - }; + var parsedOffenders = offenders.map(offendersHelpers.cssOffenderPattern); + return offendersHelpers.orderByFile(parsedOffenders); } }, "cssExpressions": { @@ -705,30 +691,29 @@ var policies = { "isAbnormalThreshold": 20, "hasOffenders": true, "offendersTransformFn": function(offenders) { - return { - count: offenders.length, - list: offenders.map(function(offender) { - var splittedOffender = offendersHelpers.cssOffenderPattern(offender); + var parsedOffenders = offenders.map(function(offender) { + var splittedOffender = offendersHelpers.cssOffenderPattern(offender); - var parts = /^(.*) {([^ ]+): expression\((.*)\)}$/.exec(splittedOffender.css); - - if (!parts) { - debug('cssExpressions offenders transform function error with "%s"', offender); - return { - parseError: offender - }; - } + var parts = /^(.*) {([^ ]+): expression\((.*)\)}$/.exec(splittedOffender.css); + if (!parts) { + debug('cssExpressions offenders transform function error with "%s"', offender); return { - rule: parts[1], - property: parts[2], - expression: parts[3], - file: splittedOffender.file, - line: splittedOffender.line, - column: splittedOffender.column + parseError: offender }; - }) - }; + } + + return { + rule: parts[1], + property: parts[2], + expression: parts[3], + file: splittedOffender.file, + line: splittedOffender.line, + column: splittedOffender.column + }; + }); + + return offendersHelpers.orderByFile(parsedOffenders); } }, "cssImportants": { @@ -740,30 +725,29 @@ var policies = { "isAbnormalThreshold": 200, "hasOffenders": true, "offendersTransformFn": function(offenders) { - return { - count: offenders.length, - list: offenders.map(function(offender) { - var splittedOffender = offendersHelpers.cssOffenderPattern(offender); + var parsedOffenders = offenders.map(function(offender) { + var splittedOffender = offendersHelpers.cssOffenderPattern(offender); - var parts = /^(.*) {([^ ]+): (.*) ?\!important}$/.exec(splittedOffender.css); - - if (!parts) { - debug('cssImportants offenders transform function error with "%s"', offender); - return { - parseError: offender - }; - } + var parts = /^(.*) {([^ ]+): (.*) ?\!important}$/.exec(splittedOffender.css); + if (!parts) { + debug('cssImportants offenders transform function error with "%s"', offender); return { - rule: parts[1], - property: parts[2], - value: parts[3], - file: splittedOffender.file, - line: splittedOffender.line, - column: splittedOffender.column + parseError: offender }; - }) - }; + } + + return { + rule: parts[1], + property: parts[2], + value: parts[3], + file: splittedOffender.file, + line: splittedOffender.line, + column: splittedOffender.column + }; + }); + + return offendersHelpers.orderByFile(parsedOffenders); } }, "cssOldIEFixes": { @@ -775,52 +759,51 @@ var policies = { "isAbnormalThreshold": 300, "hasOffenders": true, "offendersTransformFn": function(offenders) { - return { - count: offenders.length, - list: offenders.map(function(offender) { - var splittedOffender = offendersHelpers.cssOffenderPattern(offender); + var parsedOffenders = offenders.map(function(offender) { + var splittedOffender = offendersHelpers.cssOffenderPattern(offender); - var parts = /^([^{]*)( {([^ ]+): (.*)})?$/.exec(splittedOffender.css); + var parts = /^([^{]*)( {([^ ]+): (.*)})?$/.exec(splittedOffender.css); - if (!parts) { - debug('cssOldIEFixes offenders transform function error with "%s"', offender); - return { - parseError: offender - }; - } + if (!parts) { + debug('cssOldIEFixes offenders transform function error with "%s"', offender); + return { + parseError: offender + }; + } - var rule = parts[1]; - var property = parts[3]; - var value = parts[4]; - var browser = null; + var rule = parts[1]; + var property = parts[3]; + var value = parts[4]; + var browser = null; - if (rule.indexOf('* html') === 0) { - rule = rule.replace(/^\* html/, '* html'); - browser = 'IE6'; - } else if (rule.indexOf('html>body') === 0) { - rule = rule.replace(/^html>body/, 'html>body'); - browser = 'IE6'; - } else if (property.indexOf('*') === 0) { - property = '' + property + ''; - browser = 'IE7'; - } else if (value.match(/\!ie$/)) { - value = value.replace(/\!ie$/, '!ie'); - browser = 'IE7'; - } else if (property === '-ms-filter') { - property = '-ms-filter'; - browser = 'IE9'; - } else if (value.indexOf('progid:DXImageTransform.Microsoft') >= 0) { - value = value.replace(/progid:DXImageTransform\.Microsoft/, 'progid:DXImageTransform.Microsoft'); - browser = 'IE9'; - } + if (rule.indexOf('* html') === 0) { + rule = rule.replace(/^\* html/, '* html'); + browser = 'IE6'; + } else if (rule.indexOf('html>body') === 0) { + rule = rule.replace(/^html>body/, 'html>body'); + browser = 'IE6'; + } else if (property.indexOf('*') === 0) { + property = '' + property + ''; + browser = 'IE7'; + } else if (value.match(/\!ie$/)) { + value = value.replace(/\!ie$/, '!ie'); + browser = 'IE7'; + } else if (property === '-ms-filter') { + property = '-ms-filter'; + browser = 'IE9'; + } else if (value.indexOf('progid:DXImageTransform.Microsoft') >= 0) { + value = value.replace(/progid:DXImageTransform\.Microsoft/, 'progid:DXImageTransform.Microsoft'); + browser = 'IE9'; + } - var propertyAndValue = (property && value) ? ' {' + property + ': ' + value + '}' : ''; - splittedOffender.bolded = rule + propertyAndValue; - splittedOffender.browser = browser; + var propertyAndValue = (property && value) ? ' {' + property + ': ' + value + '}' : ''; + splittedOffender.bolded = rule + propertyAndValue; + splittedOffender.browser = browser; - return splittedOffender; - }) - }; + return splittedOffender; + }); + + return offendersHelpers.orderByFile(parsedOffenders); } }, "cssOldPropertyPrefixes": { @@ -885,13 +868,9 @@ var policies = { "isAbnormalThreshold": 150, "hasOffenders": true, "offendersTransformFn": function(offenders) { - return { - count: offenders.length, - list: offenders.map(function(offender) { - var splittedOffender = offendersHelpers.cssOffenderPattern(offender); - return splittedOffender; - }) - }; + var parsedOffenders = offenders.map(offendersHelpers.cssOffenderPattern); + + return offendersHelpers.orderByFile(parsedOffenders); } }, "cssRedundantBodySelectors": { @@ -903,16 +882,13 @@ var policies = { "isAbnormalThreshold": 200, "hasOffenders": true, "offendersTransformFn": function(offenders) { - return { - count: offenders.length, - list: offenders.map(function(offender) { - var splittedOffender = offendersHelpers.cssOffenderPattern(offender); + var parsedOffenders = offenders.map(function(offender) { + var splittedOffender = offendersHelpers.cssOffenderPattern(offender); + splittedOffender.bolded = splittedOffender.css.replace(/body/, 'body'); + return splittedOffender; + }); - splittedOffender.bolded = splittedOffender.css.replace(/body/, 'body'); - - return splittedOffender; - }) - }; + return offendersHelpers.orderByFile(parsedOffenders); } }, "cssRedundantChildNodesSelectors": { @@ -924,29 +900,28 @@ var policies = { "isAbnormalThreshold": 200, "hasOffenders": true, "offendersTransformFn": function(offenders) { - return { - count: offenders.length, - list: offenders.map(function(offender) { - var splittedOffender = offendersHelpers.cssOffenderPattern(offender); + var parsedOffenders = offenders.map(function(offender) { + var splittedOffender = offendersHelpers.cssOffenderPattern(offender); - var rule = splittedOffender.css || ''; - var redundanters = [ - ['ul', 'li'], - ['ol', 'li'], - ['select', 'option'], - ['table', 'tr'], - ['table', 'th'], - ]; + var rule = splittedOffender.css || ''; + var redundanters = [ + ['ul', 'li'], + ['ol', 'li'], + ['select', 'option'], + ['table', 'tr'], + ['table', 'th'], + ]; - redundanters.forEach(function(couple) { - rule = rule.replace(new RegExp('(^| |>)' + couple[0] + '([^ >]*)?([ >]| > )' + couple[1] + '([^\\w-]|$)', 'g'), '$1' + couple[0] + '$2$3' + couple[1] + '$4'); - }); + redundanters.forEach(function(couple) { + rule = rule.replace(new RegExp('(^| |>)' + couple[0] + '([^ >]*)?([ >]| > )' + couple[1] + '([^\\w-]|$)', 'g'), '$1' + couple[0] + '$2$3' + couple[1] + '$4'); + }); - splittedOffender.bolded = rule; + splittedOffender.bolded = rule; - return splittedOffender; - }) - }; + return splittedOffender; + }); + + return offendersHelpers.orderByFile(parsedOffenders); } }, "totalWeight": { diff --git a/lib/offendersHelpers.js b/lib/offendersHelpers.js index 24fc5dc..69e7b1b 100644 --- a/lib/offendersHelpers.js +++ b/lib/offendersHelpers.js @@ -185,6 +185,27 @@ var OffendersHelpers = function() { } }; + this.orderByFile = function(offenders) { + var byFile = {}; + + offenders.forEach(function(offender) { + var file = offender.file || 'Inline CSS'; + delete offender.file; + + if (!byFile[file]) { + byFile[file] = { + count: 0, + offenders: [] + }; + } + + byFile[file].count ++; + byFile[file].offenders.push(offender); + }); + + return {byFile: byFile}; + }; + }; module.exports = new OffendersHelpers(); \ No newline at end of file From 8e72efdd968b14755567bb3a22411bef9097e85a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20M=C3=A9tais?= Date: Sat, 21 May 2016 09:23:13 +0200 Subject: [PATCH 05/22] v1.10.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 29302be..40c381d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "yellowlabtools", - "version": "1.10.1", + "version": "1.10.2", "description": "Online tool to audit a webpage for performance and front-end quality issues", "license": "GPL-2.0", "author": { From 0d7178107128543d87769eeea24b387de6e5f949 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20M=C3=A9tais?= Date: Wed, 15 Jun 2016 16:03:49 +0200 Subject: [PATCH 06/22] Should fix some 254 errors with self-signed certificates --- lib/tools/phantomas/phantomasWrapper.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/tools/phantomas/phantomasWrapper.js b/lib/tools/phantomas/phantomasWrapper.js index 520013e..e6a0bc8 100644 --- a/lib/tools/phantomas/phantomasWrapper.js +++ b/lib/tools/phantomas/phantomasWrapper.js @@ -37,6 +37,7 @@ var PhantomasWrapper = function() { // Mandatory 'reporter': 'json:pretty', 'analyze-css': true, + 'ignore-ssl-errors': true, 'skip-modules': [ 'domHiddenContent', // overriden 'domMutations', // not compatible with webkit From 07028ad3cd1c7f753feceded7c5cfd29c031fd75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20M=C3=A9tais?= Date: Wed, 15 Jun 2016 23:27:35 +0200 Subject: [PATCH 07/22] Redundant tags selectors description mistake --- lib/metadata/policies.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/metadata/policies.js b/lib/metadata/policies.js index fdd0881..44c2fcf 100644 --- a/lib/metadata/policies.js +++ b/lib/metadata/policies.js @@ -894,7 +894,7 @@ var policies = { "cssRedundantChildNodesSelectors": { "tool": "phantomas", "label": "Redundant tags selectors", - "message": "

Some tags included inside other tags are obvious. For example, when \"ul li\" is specified in a rule, \"ul\" can be removed because the \"li\" element is always inside a \"ul\". Same thing for \"tr td\", \"select option\", ...

Lowering compexity in CSS selectors can make the page load a little faster.

", + "message": "

Some tags included inside other tags are obvious. For example, when \"ul li\" is specified in a rule, \"ul\" can be removed because the \"li\" tag is nearly always inside an \"ul\" container (the \"ol\" container is quite rare). Same thing for \"tr td\", \"select option\", ...

Lowering compexity in CSS selectors can make the page load a little faster.

", "isOkThreshold": 0, "isBadThreshold": 60, "isAbnormalThreshold": 200, From 189ce3db642c2230707c7b124b9e936f2b0991a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20M=C3=A9tais?= Date: Sat, 2 Jul 2016 14:44:58 +0800 Subject: [PATCH 08/22] jQuery 3.0 --- lib/metadata/policies.js | 35 +++++++++++++++------------------ test/core/customPoliciesTest.js | 26 +++++++++++++----------- 2 files changed, 30 insertions(+), 31 deletions(-) diff --git a/lib/metadata/policies.js b/lib/metadata/policies.js index 44c2fcf..dd51fdf 100644 --- a/lib/metadata/policies.js +++ b/lib/metadata/policies.js @@ -267,7 +267,7 @@ var policies = { }, "jQueryVersion": { "label": "jQuery version", - "message": "

Current latest versions of jQuery are 1.12 (with support for old IE versions) and 2.2 (without).

Each new version of jQuery optimizes performances. Do not keep an old version of jQuery. Updating can sometimes break a few things, but it is generally quite easy to fix them up. So don't hesitate.

", + "message": "

The current latest version of jQuery is 3.0

Each new version of jQuery optimizes performances. Do not keep an old version of jQuery. Updating can sometimes break a few things, but it is generally quite easy to fix them up. So don't hesitate.

", "hasOffenders": false, "scoreFn": function(data) { var differentVersions = data.toolsResults.phantomas.metrics.jQueryVersionsLoaded; @@ -279,34 +279,31 @@ var policies = { var value = data.toolsResults.phantomas.metrics.jQueryVersion; var score; - if (value.indexOf('1.12.') === 0 || - value.indexOf('2.2.') === 0 || - value.indexOf('1.13.') === 0 || - value.indexOf('2.3.') === 0 || - value.indexOf('3.0.') === 0 || - value.indexOf('3.1.') === 0) { + if (value.indexOf('3.0.') === 0 || + value.indexOf('3.1.') === 0 || + value.indexOf('3.2.') === 0) { score = 100; + } else if (value.indexOf('1.12.') === 0 || + value.indexOf('2.2.') === 0) { + score = 90; } else if (value.indexOf('1.11.') === 0 || value.indexOf('2.1.') === 0) { - score = 90; + score = 70; } else if (value.indexOf('1.10.') === 0 || value.indexOf('2.0.') === 0) { - score = 70; - } else if (value.indexOf('1.9.') === 0) { score = 50; - } else if (value.indexOf('1.8.') === 0) { + } else if (value.indexOf('1.9.') === 0) { score = 40; - } else if (value.indexOf('1.7') === 0) { + } else if (value.indexOf('1.8.') === 0) { score = 30; - } else if (value.indexOf('1.6') === 0) { + } else if (value.indexOf('1.7') === 0) { score = 20; - } else if (value.indexOf('1.5') === 0) { + } else if (value.indexOf('1.6') === 0) { score = 10; - } else if (value.indexOf('1.4') === 0) { - score = 0; - } else if (value.indexOf('1.3') === 0) { - score = 0; - } else if (value.indexOf('1.2') === 0) { + } else if (value.indexOf('1.5') === 0 || + value.indexOf('1.4') === 0 || + value.indexOf('1.3') === 0 || + value.indexOf('1.2') === 0) { score = 0; } else { debug('Unknown jQuery version "%s"', value); diff --git a/test/core/customPoliciesTest.js b/test/core/customPoliciesTest.js index 2f517cd..a506781 100644 --- a/test/core/customPoliciesTest.js +++ b/test/core/customPoliciesTest.js @@ -184,18 +184,20 @@ describe('customPolicies', function() { var versions = { '1.2.9': 0, '1.4.4': 0, - '1.5.0': 10, - '1.6.3': 20, - '1.7.0': 30, - '1.8.3a': 40, - '1.9.2': 50, - '1.10.1': 70, - '2.0.0-rc1': 70, - '1.11.1': 90, - '2.1.1-beta1': 90, - '1.12.1': 100, - '2.3.1': 100, - '3.1.0': 100 + '1.5.0': 0, + '1.6.3': 10, + '1.7.0': 20, + '1.8.3a': 30, + '1.9.2': 40, + '1.10.1': 50, + '2.0.0-rc1': 50, + '1.11.1': 70, + '2.1.1-beta1': 70, + '1.12.1': 90, + '2.2.1': 90, + '3.0.1': 100, + '3.1.0': 100, + '3.2.1': 100 }; for (var version in versions) { From 594267b9362ab96ff920bd9e1e7f97ecf32e7672 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20M=C3=A9tais?= Date: Fri, 8 Jul 2016 13:06:51 +0800 Subject: [PATCH 09/22] Update dependencies --- .travis.yml | 2 +- front/src/css/icons.css | 4 +- front/src/css/main.css | 4 +- front/src/less/icons.less | 4 +- lib/tools/weightChecker/imageOptimizer.js | 57 +++++++++++------------ package.json | 55 +++++++++++----------- test/core/imageOptimizerTest.js | 12 ++--- 7 files changed, 69 insertions(+), 69 deletions(-) diff --git a/.travis.yml b/.travis.yml index 80a5f98..d3027b9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: node_js sudo: false node_js: - "6.2" - - "0.12" + - "4.0" env: - CXX=g++-4.8 addons: diff --git a/front/src/css/icons.css b/front/src/css/icons.css index 8a7c99f..778eca8 100644 --- a/front/src/css/icons.css +++ b/front/src/css/icons.css @@ -1,6 +1,6 @@ @font-face { font-family: "icons"; - src: url("data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAAA7wAA4AAAAAGUAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABPUy8yAAABRAAAAEMAAABWQLtM2mNtYXAAAAGIAAAAOgAAAUriHBC2Y3Z0IAAAAcQAAAAUAAAAIv+YA5pmcGdtAAAB2AAABacAAAuX2BTb8Gdhc3AAAAeAAAAACAAAAAgAAAAQZ2x5ZgAAB4gAAATFAAAHKo/0IxloZWFkAAAMUAAAADMAAAA2BCiQNmhoZWEAAAyEAAAAIAAAACQD/QHAaG10eAAADKQAAAAPAAAALBYAAABsb2NhAAAMtAAAABgAAAAYCMwKe21heHAAAAzMAAAAIAAAACABDAvxbmFtZQAADOwAAAEdAAAB8hTbwvhwb3N0AAAODAAAAGIAAAB/4g/aQ3ByZXAAAA5wAAAAfQAAAIqMht7EeJxjYGRiYJzAwMrAwejCmMbAwOAOpb8ySDK0MDAwMbAyM2AFAWmuKQwOHxk/cjEe+H+AQY/xIIMDUJgRJAcAixQLGgB4nGNgYGBmgGAZBkYGEHAB8hjBfBYGDSDNBqQZGZgYGD5y/f8PUvCREUTzM0DVAwEjG8OIBwB5MwbBAAB4nGNgwAA8EMh48P8BEAYAFnAFM3icrVb5c9NGFJZ8JE5CjpKDFvVYsXGa2iuTUggGTAiSZRfcw7laCUorxU56H9Ayw9/gv+bJtDP0N/60fm9lm0CSdoZpJqP37e6nffeTyVCCjL3AD4VoPTNmtlo0tnMvoMsWrYbRoejtBZQpxn8XjILR6ch9y7bJCMnwZL1vmIYXuQ6ZikR06FBGia6g523Krdzrr5qTnt/xt+8HtrStXiCo3Q5s2gwtQVVG1TAUSUqKu7SKrcFK0BqfrzHzeTsQMKIXC5psBxF2BJ9NMlpntB5ZURiGFpnlMJRktIODMHQoqwTuyRVjGJT32gHlpUtj0oX5IZmRQzklYZfoJvl9V/BJqpyfOPc7lC3Z2PdET/Rwd7KWL8KtrSBqW/F2GMgQp5s7AY4sdmqg2aG8onGv3DcyaWjGsJSuRIilG1Nm/5DMDu6nfMmhcSXYyCmv8yxn7Au+gTajkClRXRtZUP3xKcPz3ZI9CvaEejn4k+ktZhkmePA4En5PxpwIHSnD4miSsGDk0ErKFmVcT1VMnfI6LeMtw3rh2tGXzijtUH9qMusHtiXtsGQ7NK2STManblx3aEaBKASd8e7y6wDSDWmaV9tYTWPl0CyumdMhEYhAB3ppxotELxI0g6A5NKdau0GS69bDZZo+kE8cekO1toLWTrpp2dif1/tnVWLMentBMjuL/MUuzZa5SFG6bnKGH9N4kLmETGSL7SDh4MFbt4f0stqSLfHaEFvpOb+C2uedEJ40YX8Tuy+n6pQEJoYxLxEtj4yNvmmaOlfzykiMjL8b0Kx0hU9TKMpJKI5cEUH9X3NzpjFjuG4vSs6Olelx2bqAMC3At/myQ4sqMVkuIc4sz6kky/JNleRYvqWSPMvzKhljaalknOXbKimwfEclEyw/UKJC5gOHSho8dKiswSOH3lUGTZdfw8b3YOO7uFvARpY2bGR5ATaylLCR5TJsZFmEjSxXYCPL92Ejy1XYyFIpUdOl5iionYuExyZ4Oh1oH8X1VlHklMlBJ11EETfFKZmQcVXyGPtXBkrJobVReswlulhK8uaiH2AMsYMfHo3M8eNLSlzR9n4EnukfV4IOO1E57xtLfxr8V9+Q1eSSuQiPLsN/GHyyvSjsuOrQFVU5V3No/b+oKMIO6FeREmOpKCqiyc2LUN7p9ZqyiW4PMNYxFtHR66a5uAD9VUyZJTQI/jWFJrzyQa8ihaj1cNe1F8eikt5BOdwJlqCI+31zK3iaEVlhPc2sZM+HLs/AAqap1GzZQPd5r7ZSxHMoHfYZL+pKynpxF8cZL7aAI55Br74TwyQMZtlADiU0NOAXhNaC+05QItNpl0ODI/Z5FFT+2K24kT0qaiPwbKdT7oUupPw6x0BgJ78yiIGsITQ39DYV0DxCNGSTlXG2ajpk7MAgosZuUBE1fBvZ4sGmYFuGIR8rYnXn6Nc3TdRJFTzIjOQyvjmwwBumJuLP86suDlO5oaSocNQaGMy1sJJUzAU04K3Rdvvo9ubL7BM5txVVyyde6iq6Vu5BMRcLrD3OQVoqVAHVG1XYMLpcXBKlXkGTpNfVMTQww1+jFJv/V/Wx+TxfahIj5Ei+7XBgo8/BGPrfYP9tOQjAwI+Ry024vJg2J77u6MP5Cl1GL358yv4dzFxzYZ6uAN9VdBWixVHzEVfRwKdsGKdPFJcjtQA/VX3MGYDPAEwGn6u+qXfaAHpnizk+wDZzGOwwh8EucxjsMec2wBfMYfAlcxgEzGEQMscDuMccBveZw+Ar5jB4wJwGwNfMYfANcxhEzGEQM8cF2GcOgw5zGHSZw+BA0fVRmA95QRtA32p0C+g7XU9YbGLxvaIbI/YPvNDsHzVi9k8aMfVnRbUR9RdeaOqvGjH1N42Y+lDRzRH1ES809XeNmPqHRkx9rJ5O5DLDH09umQoHlF1uPxl+U5x/ACtxTWMAAAEAAf//AA94nHWUz27bRhDGZ3bJXeofJVIUKUuyLEqJHUSGHUiWlSKBQxQN6khKG6BJ61QtKiNAcwhiqEaaa9lj0UP9BIEfwIcCSXtmgb5FgEKXPkR6oDtLWY6boAS5I5G75My3v/mAA5xGDDCCDHiwCXeDAWhc55o+BSmYkGwKOgipi0fAOYwNBMgNU8gYjgHRxFEui9C+unrJX6lWilbWy3lShwxm0sJpYx09E+UGru1gcQf79IP+1nGtv91xnTx2aRRt9GhsbuLqFsLTI86Pns7HveeMPd9LxlthulJMDV6atm2+HKSKlXSYwuh85tOjuLuYSuPfoZpxx67Zd9QyWks1wOmM6gyBg6Ra81CEG8F1MDTjEDShHQIVewgsJXUqk/F9oOrgAVB4CAh4t2hbZ0chLZbbPb/k97ul1uIqdq0WgxiCIJgszkYQTWazMMQgjuhFwJTW+Ia09mAZekGntlRATQccCNQpL51PNUaTEmVzQ9Lb5KNyubxcXna2Wt2mFEvty7zX7WxvrbaxKRz3Bpa4cD1/By/3e92Sh3+9KMhUSh6rofCieqmHQe9SHD4OHm+gfJIyU3Q+id9s7iDu/Hjy7NmJykucM/BWGw8+Dz4D5BpHbUoCcU0cgC4NqRtTMNLSSB9QPRyVUgIID7kPacik0hlSjggB9aWR55acC8JlSThLCUbiyXdiGEZKp+idiFE4CSZn10LDJNcC+PBpMMpJwRmu1MuOxjU2KCDseqh/DAw1ZCp1KoAfqM0cJ4kJ5Fwfg66b+si2ahW3ZPm2X7xM6npt3MAWAeoRqh3Xk90eNlfX+q1Sv45dukfw4m+tr3v3f1i+6X5z68rt6m50CkkYnt/G71tXcDzwrn+E9cpuFAdqHC7uKb21hINjqkEpXYMG3A4+VNoLLpWauib0R0AknHebpi26reQwaKzUl5fKTq1UI20LaQl5lk+6TeVuUcupXC3acMVlc3VL9Zro+5aP05lTRaw68/BnGAbUUDXbPjxVjEf0JJ7MZ+CxU/UK8a56WrMnGCzyPuMkT1mvw5fBF9mMwbmGA+AaaQ1TsgaKTFMYoADcT6Ouy3EGpSQqhDDGYBimMWr6VkHXrqz66831pXKhYTXMXDql5fW84sRtJ03VcZdRtnr9Hl1Nkzl11tlhWxts7YKvzIIgNG0C5HhydXhzZeXm8P48XL3gJZMAG7Y5oZZsBPfeTlHh2gUXmfOlfOI46YMPgm3VHxLEPkhDZ8gk7hNXnLMHFBh/CJzxuwB5M5elFZmE85TqU8tXpJd8Sp2T9MobZhOEyQzDOGwkAx0YnAIkHkzqKx7KxIP6qkYv1vgj4hTGIqFAXvBcq8CgVq0slZxC2SrPCTAUAf4ZAf6cAP6f3T+Ko7PNDZL4SqomTf0Uz7Dx3ubH1twtrpFlqr0//Yf2XuAfpJDK0oeff3eLlCIOhr869/aCDQOp08gwlFugcguho9APlPPq30pMHI30/YrANtmoGmz+/wJyw4P3VjwMylZB442VWnVeNoGX1/KkdqmN3Ocdr+gK6W9gv7jtddySbK1tbUvHVW7ZJAlPcO/Eyr3O2pX4k4qdfZ2zTDu9nrYtu2LTid/Fv2DkxiOvjlj38JUbETAT045y6rH9L7s+GfsAAAB4nGNgZGBgAOIZ7P+q4vltvjJwMzGAwMWWdU8g9IIr/3/9P8DExngQyOVgAEsDAHIyDgIAeJxjYGRgYDzw/wCDHhMDA8P/L0w8DEARFMANAHttBL94nGNiYGBgIhIDAAI8ABcAAAAAAAB0ALYBAgFYAboCFgKIAsIDFAOVAAEAAAALADAABgAAAAAAAgAYACgAdwAAAGsLlwAAAAB4nF2OvU7DMBSFT/qHaBACITGbpQtS+jP2AdqZDtnTxElbJXHkuJUqMTPzFMw8Bc/FiXslKmzp+jvnHl8bwAN+EKBbAYa+dquHG6oL90l3wgPyo/AQIZ6FR1QvwmO8YiIc4glvnBAMbumMkQn3cI9auE//XXhA/hAecvqn8Ij+l/AYMb6FQ0yC0T41dbvRxbFMrGdfYm3bvanVPJp5vda1tonTmdqeVXsqFs7lKremUitTO12WRjXWHHTqop1zzXI6zcWPUlNhjxSGf26xgUaBI0oksFf+H8VMWO90WmGOCLOr/pr92mcSOJ4ZM1ucWVucOHtB1yGnzpkxqEgrf7dLl9yGTuN7Bzop/Qg7f6vBElPu/F8+8q9XvzD1U2IAAAB4nG3BQQ7CMAwEQG+bpi15Cyde5CBTRTIxOEb9PgeuzNBEPwv9V4gwYUbCgowVG3ZcUAq723lVecQtVfYxK9ekbURSs1d+Wm0q2/sjI5r1PO4u0nNwVYn1ZO+tH0RflcgY/gAAeJxj8N7BcCIoYiMjY1/kBsadHAwcDMkFGxnYnDYxMDJogRibuZkYOSAsfgYwi91pFzMDUJoTyOZw2sXgAGEzM7hsVGHsCIzY4NARsZE5xWWjGoi3i6OBgZHFoSM5JAKkJBIINvMyMfJo7WD837qBpXcjE1Afa4oLAGWtJJsAAAA=") format("woff"); + src: url("data:application/x-font-woff;charset=utf-8;base64,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") format("woff"); font-weight: normal; font-style: normal; } @@ -15,7 +15,7 @@ speak: none; text-decoration: inherit; text-transform: none; - text-rendering: optimizeLegibility; + text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } diff --git a/front/src/css/main.css b/front/src/css/main.css index 1d698ba..c870840 100644 --- a/front/src/css/main.css +++ b/front/src/css/main.css @@ -1,6 +1,6 @@ @font-face { font-family: "icons"; - src: url("data:application/x-font-woff;charset=utf-8;base64,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") format("woff"); + src: url("data:application/x-font-woff;charset=utf-8;base64,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") format("woff"); font-weight: normal; font-style: normal; } @@ -15,7 +15,7 @@ speak: none; text-decoration: inherit; text-transform: none; - text-rendering: optimizeLegibility; + text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } diff --git a/front/src/less/icons.less b/front/src/less/icons.less index b1eb7fa..6d596a7 100644 --- a/front/src/less/icons.less +++ b/front/src/less/icons.less @@ -4,7 +4,7 @@ @font-face { font-family:"icons"; - src:url("data:application/x-font-woff;charset=utf-8;base64,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") format("woff"); + src:url("data:application/x-font-woff;charset=utf-8;base64,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") format("woff"); font-weight:normal; font-style:normal; } @@ -22,7 +22,7 @@ speak:none; text-decoration:inherit; text-transform:none; - text-rendering:optimizeLegibility; + text-rendering:auto; -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale; } diff --git a/lib/tools/weightChecker/imageOptimizer.js b/lib/tools/weightChecker/imageOptimizer.js index 1625200..4009a59 100644 --- a/lib/tools/weightChecker/imageOptimizer.js +++ b/lib/tools/weightChecker/imageOptimizer.js @@ -1,8 +1,10 @@ -var debug = require('debug')('ylt:imageOptimizer'); - -var Q = require('q'); -var Imagemin = require('imagemin'); -var jpegoptim = require('imagemin-jpegoptim'); +var debug = require('debug')('ylt:imageOptimizer'); +var Q = require('q'); +var imagemin = require('imagemin'); +var imageminJpegtran = require('imagemin-jpegtran'); +var imageminJpegoptim = require('imagemin-jpegoptim'); +var imageminOptipng = require('imagemin-optipng'); +var imageminSvgo = require('imagemin-svgo'); var ImageOptimizer = function() { @@ -34,7 +36,7 @@ var ImageOptimizer = function() { return entry; } - var newFileSize = newFile.contents.length; + var newFileSize = newFile.length; debug('JPEG lossless compression complete for %s', entry.url); @@ -55,7 +57,7 @@ var ImageOptimizer = function() { return entry; } - var newFileSize = newFile.contents.length; + var newFileSize = newFile.length; debug('JPEG lossy compression complete for %s', entry.url); @@ -90,7 +92,7 @@ var ImageOptimizer = function() { return entry; } - var newFileSize = newFile.contents.length; + var newFileSize = newFile.length; debug('PNG lossless compression complete for %s', entry.url); @@ -124,12 +126,12 @@ var ImageOptimizer = function() { return entry; } - var newFileSize = newFile.contents.length; + var newFileSize = newFile.length; debug('SVG lossless compression complete for %s', entry.url); if (gainIsEnough(fileSize, newFileSize)) { - entry.weightCheck.bodyAfterOptimization = newFile.contents.toString(); + entry.weightCheck.bodyAfterOptimization = newFile.toString(); entry.weightCheck.lossless = entry.weightCheck.optimized = newFileSize; entry.weightCheck.isOptimized = false; debug('Filesize is %d bytes smaller (-%d%)', fileSize - newFileSize, Math.round((fileSize - newFileSize) * 100 / fileSize)); @@ -194,35 +196,30 @@ var ImageOptimizer = function() { var engine; if (type === 'jpeg' && !lossy) { - engine = Imagemin.jpegtran(); + engine = imageminJpegtran({progressive: false}); } else if (type === 'jpeg' && lossy) { - engine = jpegoptim({max: MAX_JPEG_QUALITY}); + engine = imageminJpegoptim({progressive: false, max: MAX_JPEG_QUALITY}); } else if (type === 'png' && !lossy) { - engine = Imagemin.optipng({optimizationLevel: OPTIPNG_COMPRESSION_LEVEL}); + engine = imageminOptipng({optimizationLevel: OPTIPNG_COMPRESSION_LEVEL}); } else if (type === 'svg' && !lossy) { - engine = Imagemin.svgo({ plugins: [ { removeUselessDefs: false } ] }); + engine = imageminSvgo({ plugins: [ { removeUselessDefs: false } ] }); } else { deferred.reject('No optimization engine found for imagemin'); } - try { - new Imagemin() - .src(imageBody) - .use(engine) - .run(function (err, files) { - if (err) { - deferred.reject(err); - } else { - deferred.resolve(files[0]); - var endTime = Date.now(); - debug('Optimization for %s took %d ms', type, endTime - startTime); - } - }); + imagemin.buffer(imageBody, {use: engine}) - } catch(err) { - deferred.reject(err); - } + .then(function(file) { + var endTime = Date.now(); + debug('Optimization for %s took %d ms', type, endTime - startTime); + deferred.resolve(file); + console.log('ET HOP'); + }) + + .catch(function(err) { + deferred.reject(file); + }); return deferred.promise; } diff --git a/package.json b/package.json index 40c381d..5de0205 100644 --- a/package.json +++ b/package.json @@ -16,55 +16,58 @@ "yellowlabtools": "./bin/cli.js" }, "engines": { - "node": ">= 0.12.0" + "node": ">= 4.0" }, "main": "./lib/index.js", "dependencies": { - "angular": "1.5.2", - "angular-animate": "1.5.2", - "angular-chart.js": "0.9.0", + "angular": "1.5.7", + "angular-animate": "1.5.7", + "angular-chart.js": "0.10.2", "angular-local-storage": "0.2.7", - "angular-resource": "1.5.2", - "angular-route": "1.5.2", - "angular-sanitize": "1.5.2", + "angular-resource": "1.5.7", + "angular-route": "1.5.7", + "angular-sanitize": "1.5.7", "async": "1.5.2", - "body-parser": "1.15.0", - "chart.js": "1.0.2", - "clean-css": "3.4.10", + "body-parser": "1.15.2", + "chart.js": "1.1.1", + "clean-css": "3.4.18", "color-diff": "1.0.0", - "compression": "1.6.1", + "compression": "1.6.2", "cors": "2.7.1", "css-mq-parser": "0.0.3", "debug": "2.2.0", "easyxml": "2.0.1", - "express": "4.13.4", - "imagemin": "4.0.0", - "imagemin-jpegoptim": "4.1.0", + "express": "4.14.0", + "imagemin": "5.2.2", + "imagemin-jpegoptim": "5.0.0", + "imagemin-jpegtran": "5.0.2", + "imagemin-optipng": "5.1.0", + "imagemin-svgo": "5.1.0", "is-http2": "1.0.4", "lwip": "0.0.9", "meow": "3.7.0", - "minimize": "1.8.1", + "minimize": "2.0.0", "parse-color": "1.0.0", "phantomas": "1.15.1", - "ps-node": "0.0.5", + "ps-node": "0.1.2", "q": "1.4.1", - "request": "2.69.0", - "rimraf": "2.5.2", + "request": "2.72.0", + "rimraf": "2.5.3", "temporary": "0.0.8", "try-thread-sleep": "1.0.0", - "uglify-js": "2.6.2" + "uglify-js": "2.7.0" }, "devDependencies": { "chai": "~3.5.0", "grunt": "~0.4.5", "grunt-blanket": "~0.0.10", "grunt-contrib-clean": "~1.0.0", - "grunt-contrib-concat": "~1.0.0", + "grunt-contrib-concat": "~1.0.1", "grunt-contrib-copy": "~1.0.0", "grunt-contrib-cssmin": "~1.0.1", - "grunt-contrib-htmlmin": "~1.1.0", + "grunt-contrib-htmlmin": "~1.4.0", "grunt-contrib-jshint": "~1.0.0", - "grunt-contrib-less": "~1.2.0", + "grunt-contrib-less": "~1.3.0", "grunt-contrib-uglify": "~1.0.1", "grunt-env": "~0.4.4", "grunt-express": "~1.4.1", @@ -72,12 +75,12 @@ "grunt-inline-angular-templates": "~0.1.5", "grunt-line-remover": "~0.0.2", "grunt-mocha-test": "~0.12.7", - "grunt-replace": "~0.11.0", + "grunt-replace": "~1.0.1", "grunt-usemin": "~3.1.1", - "grunt-webfont": "~1.2.0", + "grunt-webfont": "~1.4.0", "matchdep": "~1.0.1", - "mocha": "~2.4.5", - "sinon": "~1.17.3", + "mocha": "~2.5.3", + "sinon": "~1.17.4", "sinon-chai": "~2.8.0" }, "scripts": { diff --git a/test/core/imageOptimizerTest.js b/test/core/imageOptimizerTest.js index f1bc613..9871491 100644 --- a/test/core/imageOptimizerTest.js +++ b/test/core/imageOptimizerTest.js @@ -11,7 +11,7 @@ describe('imageOptimizer', function() { var fileSize = fileContent.length; imageOptimizer.compressJpegLosslessly(fileContent).then(function(newFile) { - var newFileSize = newFile.contents.length; + var newFileSize = newFile.length; newFileSize.should.be.below(fileSize); done(); }).fail(function(err) { @@ -25,7 +25,7 @@ describe('imageOptimizer', function() { var fileSize = fileContent.length; imageOptimizer.compressJpegLossly(fileContent).then(function(newFile) { - var newFileSize = newFile.contents.length; + var newFileSize = newFile.length; newFileSize.should.be.below(fileSize); done(); }).fail(function(err) { @@ -82,7 +82,7 @@ describe('imageOptimizer', function() { var fileSize = fileContent.length; imageOptimizer.compressPngLosslessly(fileContent).then(function(newFile) { - var newFileSize = newFile.contents.length; + var newFileSize = newFile.length; newFileSize.should.be.below(fileSize); done(); }).fail(function(err) { @@ -96,7 +96,7 @@ describe('imageOptimizer', function() { var fileSize = fileContent.length; imageOptimizer.compressPngLosslessly(fileContent).then(function(newFile) { - var newFileSize = newFile.contents.length; + var newFileSize = newFile.length; newFileSize.should.equal(fileSize); done(); }).fail(function(err) { @@ -110,7 +110,7 @@ describe('imageOptimizer', function() { var fileSize = fileContent.length; imageOptimizer.compressPngLosslessly(fileContent).then(function(newFile) { - var newFileSize = newFile.contents.length; + var newFileSize = newFile.length; newFileSize.should.equal(fileSize); done(); }).fail(function(err) { @@ -166,7 +166,7 @@ describe('imageOptimizer', function() { var fileSize = fileContent.length; imageOptimizer.compressSvgLosslessly(fileContent).then(function(newFile) { - var newFileSize = newFile.contents.length; + var newFileSize = newFile.length; newFileSize.should.be.below(fileSize); done(); }).fail(function(err) { From 7432f4de0850eadeddabc8086ffd29d4fea6abeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20M=C3=A9tais?= Date: Fri, 8 Jul 2016 13:11:05 +0800 Subject: [PATCH 10/22] Check JPEG compression with progressive flag by default --- lib/tools/weightChecker/imageOptimizer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/tools/weightChecker/imageOptimizer.js b/lib/tools/weightChecker/imageOptimizer.js index 4009a59..03f5861 100644 --- a/lib/tools/weightChecker/imageOptimizer.js +++ b/lib/tools/weightChecker/imageOptimizer.js @@ -196,9 +196,9 @@ var ImageOptimizer = function() { var engine; if (type === 'jpeg' && !lossy) { - engine = imageminJpegtran({progressive: false}); + engine = imageminJpegtran({progressive: true}); } else if (type === 'jpeg' && lossy) { - engine = imageminJpegoptim({progressive: false, max: MAX_JPEG_QUALITY}); + engine = imageminJpegoptim({progressive: true, max: MAX_JPEG_QUALITY}); } else if (type === 'png' && !lossy) { engine = imageminOptipng({optimizationLevel: OPTIPNG_COMPRESSION_LEVEL}); } else if (type === 'svg' && !lossy) { From 50a9ea628da453d2970f7cebde7468e9bd4f024e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20M=C3=A9tais?= Date: Sat, 9 Jul 2016 23:29:02 +0800 Subject: [PATCH 11/22] Remove 2 rules related to CSS (#155) --- lib/metadata/policies.js | 32 ----------------------- lib/metadata/scoreProfileGeneric.json | 2 -- lib/tools/weightChecker/imageOptimizer.js | 1 - 3 files changed, 35 deletions(-) diff --git a/lib/metadata/policies.js b/lib/metadata/policies.js index dd51fdf..f94495c 100644 --- a/lib/metadata/policies.js +++ b/lib/metadata/policies.js @@ -473,24 +473,6 @@ var policies = { return offendersHelpers.orderByFile(parsedOffenders); } }, - "cssComplexSelectorsByAttribute": { - "tool": "phantomas", - "label": "Complex attributes selector", - "message": "

Complex attributes selectors are one of these:

  • .foo[type*=bar] (contains bar)
  • .foo[type^=bar] (starts with bar)
  • .foo[type|=bar] (starts with bar or bar-)
  • .foo[type$=bar] (ends with bar)
  • .foo[type~=bar baz] (bar or baz)

Their matching process needs more CPU and it has a cost on performances.

", - "isOkThreshold": 0, - "isBadThreshold": 75, - "isAbnormalThreshold": 150, - "hasOffenders": true, - "offendersTransformFn": function(offenders) { - var parsedOffenders = offenders.map(function(offender) { - var splittedOffender = offendersHelpers.cssOffenderPattern(offender); - splittedOffender.bolded = splittedOffender.css.replace(/(\[[^ ]+[~\|\^\$\*]=["']?[^"'\]]+["']?\])/g, '$1'); - return splittedOffender; - }); - - return offendersHelpers.orderByFile(parsedOffenders); - } - }, "cssColors": { "tool": "phantomas", "label": "Colors count", @@ -856,20 +838,6 @@ var policies = { }; } }, - "cssUniversalSelectors": { - "tool": "phantomas", - "label": "Universal selectors", - "message": "

Universal selectors are the most expensive CSS selectors.

More informations here.

", - "isOkThreshold": 0, - "isBadThreshold": 50, - "isAbnormalThreshold": 150, - "hasOffenders": true, - "offendersTransformFn": function(offenders) { - var parsedOffenders = offenders.map(offendersHelpers.cssOffenderPattern); - - return offendersHelpers.orderByFile(parsedOffenders); - } - }, "cssRedundantBodySelectors": { "tool": "phantomas", "label": "Redundant body selectors", diff --git a/lib/metadata/scoreProfileGeneric.json b/lib/metadata/scoreProfileGeneric.json index a65a931..521fcfc 100644 --- a/lib/metadata/scoreProfileGeneric.json +++ b/lib/metadata/scoreProfileGeneric.json @@ -69,7 +69,6 @@ "policies": { "cssRules": 2, "cssComplexSelectors": 2, - "cssComplexSelectorsByAttribute": 1.5, "cssColors": 0.5, "similarColors": 0.5, "cssBreakpoints": 1, @@ -88,7 +87,6 @@ "cssImportants": 3, "cssOldIEFixes": 1, "cssOldPropertyPrefixes": 1, - "cssUniversalSelectors": 1, "cssRedundantBodySelectors": 1, "cssRedundantChildNodesSelectors": 1 } diff --git a/lib/tools/weightChecker/imageOptimizer.js b/lib/tools/weightChecker/imageOptimizer.js index 03f5861..32107f6 100644 --- a/lib/tools/weightChecker/imageOptimizer.js +++ b/lib/tools/weightChecker/imageOptimizer.js @@ -214,7 +214,6 @@ var ImageOptimizer = function() { var endTime = Date.now(); debug('Optimization for %s took %d ms', type, endTime - startTime); deferred.resolve(file); - console.log('ET HOP'); }) .catch(function(err) { From 3d377b7b1f94dab0b9f50ec13aaef6f8fdce702b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20M=C3=A9tais?= Date: Sun, 10 Jul 2016 08:50:48 +0800 Subject: [PATCH 12/22] Reduce the weight of the breakpoints count rule (#176) --- lib/metadata/scoreProfileGeneric.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/metadata/scoreProfileGeneric.json b/lib/metadata/scoreProfileGeneric.json index 521fcfc..bf050f7 100644 --- a/lib/metadata/scoreProfileGeneric.json +++ b/lib/metadata/scoreProfileGeneric.json @@ -71,7 +71,7 @@ "cssComplexSelectors": 2, "cssColors": 0.5, "similarColors": 0.5, - "cssBreakpoints": 1, + "cssBreakpoints": 0.5, "cssMobileFirst": 1 } }, From 5ccab1770b7314061214703c8c2b340cfc358cae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20M=C3=A9tais?= Date: Sun, 10 Jul 2016 10:24:51 +0800 Subject: [PATCH 13/22] Fix JS backtrace parsing since PhantomJS 2.x (#177) Fixes #177. --- .../src/js/directives/offendersDirectives.js | 20 ++++++--- lib/offendersHelpers.js | 29 +++++++++++-- test/core/offendersHelpersTest.js | 41 +++++++++++++++++++ 3 files changed, 80 insertions(+), 10 deletions(-) diff --git a/front/src/js/directives/offendersDirectives.js b/front/src/js/directives/offendersDirectives.js index 3ed389a..ae84679 100644 --- a/front/src/js/directives/offendersDirectives.js +++ b/front/src/js/directives/offendersDirectives.js @@ -641,6 +641,11 @@ withFnResult = /^([^\s\(]+) \((.+:\d+:\d+)\)$/.exec(trace); } + if (withFnResult === null) { + // Yet another PhantomJS 2 format? + withFnResult = /^([^\s\(]+|global code)@(.+:\d+:\d+)$/.exec(trace); + } + if (withFnResult === null) { // Try the PhantomJS 2 ERROR format withFnResult = /^([^\s\(]+) (http.+:\d+)$/.exec(trace); @@ -664,12 +669,15 @@ var line = fileAndLineSplit[2]; var column = fileAndLineSplit[3]; - out.push({ - fnName: fnName, - filePath: filePath, - line: line, - column: column - }); + // Filter phantomas code + if (filePath.indexOf('phantomjs://') === -1) { + out.push({ + fnName: fnName, + filePath: filePath, + line: line, + column: column + }); + } }); } catch(e) { diff --git a/lib/offendersHelpers.js b/lib/offendersHelpers.js index 69e7b1b..3fe906a 100644 --- a/lib/offendersHelpers.js +++ b/lib/offendersHelpers.js @@ -113,14 +113,17 @@ var OffendersHelpers = function() { if (traceArray) { var results = []; var parts = null; + var obj; for (var i=0 ; i Date: Sun, 10 Jul 2016 10:41:56 +0800 Subject: [PATCH 14/22] Disable Angular debugging, should improve perfs --- front/src/js/app.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/front/src/js/app.js b/front/src/js/app.js index 2cb2875..d1decbe 100644 --- a/front/src/js/app.js +++ b/front/src/js/app.js @@ -82,3 +82,7 @@ yltApp.config(['$routeProvider', '$locationProvider', } ]); +// Disable debugging https://docs.angularjs.org/guide/production +yltApp.config(['$compileProvider', function ($compileProvider) { + $compileProvider.debugInfoEnabled(false); +}]); \ No newline at end of file From e1316ea48b51810bf1fdb431f749d523e744a127 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20M=C3=A9tais?= Date: Sun, 10 Jul 2016 15:11:34 +0800 Subject: [PATCH 15/22] Add a new rule for Synchronous XMLHttpRequest (#178) * Fix bug in spying function * New rule Synchronous XHR * Add the synchronousXHR rule to the dashboard --- front/src/views/rule.html | 2 +- lib/metadata/policies.js | 9 ++++++ lib/metadata/scoreProfileGeneric.json | 3 +- .../custom_modules/core/scopeYLT/scopeYLT.js | 5 ++-- .../modules/ajaxReqYLT/ajaxReqYLT.js | 30 +++++++++++++++++++ lib/tools/phantomas/phantomasWrapper.js | 9 +++--- test/www/jquery-page.html | 5 ++++ 7 files changed, 55 insertions(+), 8 deletions(-) create mode 100644 lib/tools/phantomas/custom_modules/modules/ajaxReqYLT/ajaxReqYLT.js diff --git a/front/src/views/rule.html b/front/src/views/rule.html index eb14e77..ee8fa78 100644 --- a/front/src/views/rule.html +++ b/front/src/views/rule.html @@ -155,7 +155,7 @@ ()
-
+
{{offender}}
diff --git a/lib/metadata/policies.js b/lib/metadata/policies.js index f94495c..869f50a 100644 --- a/lib/metadata/policies.js +++ b/lib/metadata/policies.js @@ -241,6 +241,15 @@ var policies = { }; } }, + "synchronousXHR": { + "tool": "phantomas", + "label": "Synchronous Ajax requests", + "message": "

Making an XMLHttpRequest with the async option set to false is deprecated due to the negative effect to performances. The browser's main thread needs to stop everything until the response is received.

", + "isOkThreshold": 0, + "isBadThreshold": 1, + "isAbnormalThreshold": 1, + "hasOffenders": true + }, "consoleMessages": { "tool": "phantomas", "label": "Console messages", diff --git a/lib/metadata/scoreProfileGeneric.json b/lib/metadata/scoreProfileGeneric.json index bf050f7..565ead7 100644 --- a/lib/metadata/scoreProfileGeneric.json +++ b/lib/metadata/scoreProfileGeneric.json @@ -50,6 +50,7 @@ "policies": { "jsErrors": 1, "documentWriteCalls": 2, + "synchronousXHR": 5, "consoleMessages": 0.5, "globalVariables": 0.5 } @@ -108,7 +109,7 @@ "domComplexity": 2, "domManipulations": 2, "scroll": 1, - "badJavascript": 1, + "badJavascript": 2, "jQuery": 1, "cssSyntaxError": 1, "cssComplexity": 1, diff --git a/lib/tools/phantomas/custom_modules/core/scopeYLT/scopeYLT.js b/lib/tools/phantomas/custom_modules/core/scopeYLT/scopeYLT.js index aa0aaa7..322f504 100644 --- a/lib/tools/phantomas/custom_modules/core/scopeYLT/scopeYLT.js +++ b/lib/tools/phantomas/custom_modules/core/scopeYLT/scopeYLT.js @@ -49,7 +49,7 @@ exports.module = function(phantomas) { var err; // Before - if (enabled) { + if (enabled && callbackBefore) { callbackBefore.apply(this, arguments); } @@ -71,7 +71,8 @@ exports.module = function(phantomas) { // After if (enabled && callbackAfter) { - callbackAfter.call(this, result, arguments); + var args = Array.prototype.slice.call(arguments); + callbackAfter.apply(this, [result].concat(args)); } if (err) { diff --git a/lib/tools/phantomas/custom_modules/modules/ajaxReqYLT/ajaxReqYLT.js b/lib/tools/phantomas/custom_modules/modules/ajaxReqYLT/ajaxReqYLT.js new file mode 100644 index 0000000..a1577e8 --- /dev/null +++ b/lib/tools/phantomas/custom_modules/modules/ajaxReqYLT/ajaxReqYLT.js @@ -0,0 +1,30 @@ +/** + * Analyzes AJAX requests + */ +/* global window: true */ + +exports.version = '0.2.a'; + +exports.module = function(phantomas) { + 'use strict'; + + phantomas.setMetric('ajaxRequests'); // @desc number of AJAX requests + phantomas.setMetric('synchronousXHR'); // @desc number of synchronous + + phantomas.on('init', function() { + phantomas.evaluate(function() { + (function(phantomas) { + phantomas.spy(window.XMLHttpRequest.prototype, 'open', null, function(result, method, url, async) { + phantomas.incrMetric('ajaxRequests'); + phantomas.addOffender('ajaxRequests', '<%s> [%s]', url, method); + + if (async === false) { + phantomas.incrMetric('synchronousXHR'); + phantomas.addOffender('synchronousXHR', url); + phantomas.log('ajaxRequests: synchronous XMLHttpRequest call to <%s>', url); + } + }, true); + })(window.__phantomas); + }); + }); +}; \ No newline at end of file diff --git a/lib/tools/phantomas/phantomasWrapper.js b/lib/tools/phantomas/phantomasWrapper.js index e6a0bc8..910d3d5 100644 --- a/lib/tools/phantomas/phantomasWrapper.js +++ b/lib/tools/phantomas/phantomasWrapper.js @@ -39,18 +39,19 @@ var PhantomasWrapper = function() { 'analyze-css': true, 'ignore-ssl-errors': true, 'skip-modules': [ - 'domHiddenContent', // overriden + 'ajaxRequests', // overridden + 'domHiddenContent', // overridden 'domMutations', // not compatible with webkit - 'domQueries', // overriden + 'domQueries', // overridden 'events', // overridden 'filmStrip', // not needed 'har', // not needed for the moment 'javaScriptBottlenecks', // needs to be launched after custom module scopeYLT 'jQuery', // overridden 'jserrors', // overridden - 'lazyLoadableImages', //overriden + 'lazyLoadableImages', //overridden 'pageSource', // not needed - 'windowPerformance' // overriden + 'windowPerformance' // overridden ].join(','), 'include-dirs': [ path.join(__dirname, 'custom_modules/core'), diff --git a/test/www/jquery-page.html b/test/www/jquery-page.html index f2e3f16..ff03ef8 100644 --- a/test/www/jquery-page.html +++ b/test/www/jquery-page.html @@ -190,6 +190,11 @@ $li.parentsUntil('body', 'div'); $li.siblings(); $li.siblings('li'); + + $.ajax({ + url: 'xml.xml', + async: false + }); \ No newline at end of file From e186620a60077acf7665174c663430f3a162d221 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20M=C3=A9tais?= Date: Sun, 10 Jul 2016 15:15:45 +0800 Subject: [PATCH 16/22] Now that Uglify-JS is faster with already minified files... --- lib/tools/weightChecker/fileMinifier.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/tools/weightChecker/fileMinifier.js b/lib/tools/weightChecker/fileMinifier.js index 45dc14e..10d9efc 100644 --- a/lib/tools/weightChecker/fileMinifier.js +++ b/lib/tools/weightChecker/fileMinifier.js @@ -322,11 +322,11 @@ var FileMinifier = function() { // Avoid loosing some trying to compress JS files if they alreay look minified // by counting the number of lines compared to the total size. - // Less than 1KB per line is suspicious + // Less than 2KB per line is suspicious function looksAlreadyMinified(code) { var linesCount = code.split(/\r\n|\r|\n/).length; var linesRatio = code.length / linesCount; - var looksMinified = linesRatio > 1024; + var looksMinified = linesRatio > 2 * 1024; debug('Lines ratio is %d bytes per line', Math.round(linesRatio)); debug(looksMinified ? 'It looks already minified' : 'It doesn\'t look minified'); From f10fbc3fa3a4e355ee6b19672922baceb53a91ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20M=C3=A9tais?= Date: Sun, 10 Jul 2016 16:00:52 +0800 Subject: [PATCH 17/22] Sometimes the lossy JPEG weights more than the lossless --- lib/tools/weightChecker/imageOptimizer.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/tools/weightChecker/imageOptimizer.js b/lib/tools/weightChecker/imageOptimizer.js index 32107f6..b9c3b51 100644 --- a/lib/tools/weightChecker/imageOptimizer.js +++ b/lib/tools/weightChecker/imageOptimizer.js @@ -61,7 +61,9 @@ var ImageOptimizer = function() { debug('JPEG lossy compression complete for %s', entry.url); - if (gainIsEnough(fileSize, newFileSize)) { + if (entry.weightCheck.lossless && entry.weightCheck.lossless < newFileSize) { + debug('Lossy compression is not as good as lossless compression. Skipping the lossy.'); + } else if (gainIsEnough(fileSize, newFileSize)) { if (entry.weightCheck.isOptimized !== false || newFileSize < entry.weightCheck.lossless) { entry.weightCheck.optimized = newFileSize; From fe8466b0e3497228629ca29b14eb7d6b6d04b2fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20M=C3=A9tais?= Date: Mon, 11 Jul 2016 00:39:21 +0800 Subject: [PATCH 18/22] Improve content type detection (#179) --- lib/tools/weightChecker/contentTypeChecker.js | 188 ++++++++++++++++++ lib/tools/weightChecker/weightChecker.js | 40 +++- package.json | 9 + test/core/contentTypeCheckerTest.js | 20 ++ 4 files changed, 248 insertions(+), 9 deletions(-) create mode 100644 lib/tools/weightChecker/contentTypeChecker.js create mode 100644 test/core/contentTypeCheckerTest.js diff --git a/lib/tools/weightChecker/contentTypeChecker.js b/lib/tools/weightChecker/contentTypeChecker.js new file mode 100644 index 0000000..d5fa7ce --- /dev/null +++ b/lib/tools/weightChecker/contentTypeChecker.js @@ -0,0 +1,188 @@ +var debug = require('debug')('ylt:contentTypeChecker'); +var Q = require('q'); +var isJpg = require('is-jpg'); +var isPng = require('is-png'); +var isSvg = require('is-svg'); +var isGif = require('is-gif'); +var isWoff = require('is-woff'); +var isWoff2 = require('is-woff2'); +var isOtf = require('is-otf'); +var isTtf = require('is-ttf'); +var isEot = require('is-eot'); + +var ContentTypeChecker = function() { + + function checkContentType(entry) { + var deferred = Q.defer(); + + debug('Entering contentTypeChecker'); + + // Ignore very small files as they are generally tracking pixels + if (entry.weightCheck && entry.weightCheck.body && entry.weightCheck.bodySize > 100) { + var foundType; + + try { + foundType = findContentType(entry.weightCheck.body); + + if (!entry.contentType || entry.contentType === '') { + if (foundType === null) { + debug('ContentType is empty for file %s', entry.url); + } else { + debug('ContentType is empty for file %s. It should be %s.', entry.url, foundType.mimes[0]); + entry.oldContentType = null; + rewriteContentType(entry, foundType); + } + } else { + if (foundType !== null && foundType.mimes.indexOf(entry.contentType) === -1) { + debug('ContentType %s is wrong for %s. It should be %s.', entry.contentType, entry.url, foundType.mimes[0]); + entry.oldContentType = entry.contentType; + rewriteContentType(entry, foundType); + } + } + + } catch(err) { + debug('Error while analyzing the contentType of %s', entry.url); + debug(err); + } + } + + deferred.resolve(entry); + + return deferred.promise; + } + + function findContentType(body) { + var buffer = new Buffer(body, 'binary'); + + if (isJpg(buffer)) { + return contentTypes.jpeg; + } + + if (isPng(buffer)) { + return contentTypes.png; + } + + // https://github.com/sindresorhus/is-svg/issues/7 + if (/ Date: Mon, 11 Jul 2016 15:46:00 +0800 Subject: [PATCH 19/22] New rule called "Empty requests" (#180) --- front/src/views/rule.html | 3 +- lib/metadata/policies.js | 21 +++-- lib/metadata/scoreProfileGeneric.json | 1 + lib/runner.js | 4 +- .../contentTypeChecker.js | 0 .../fileMinifier.js | 0 .../gzipCompressor.js | 0 .../imageOptimizer.js | 0 .../redownload.js} | 38 ++++++-- test/core/contentTypeCheckerTest.js | 2 +- test/core/fileMinifierTest.js | 2 +- test/core/gzipCompressorTest.js | 4 +- test/core/imageOptimizerTest.js | 2 +- ...weightCheckerTest.js => redownloadTest.js} | 86 +++++++++---------- 14 files changed, 99 insertions(+), 64 deletions(-) rename lib/tools/{weightChecker => redownload}/contentTypeChecker.js (100%) rename lib/tools/{weightChecker => redownload}/fileMinifier.js (100%) rename lib/tools/{weightChecker => redownload}/gzipCompressor.js (100%) rename lib/tools/{weightChecker => redownload}/imageOptimizer.js (100%) rename lib/tools/{weightChecker/weightChecker.js => redownload/redownload.js} (94%) rename test/core/{weightCheckerTest.js => redownloadTest.js} (70%) diff --git a/front/src/views/rule.html b/front/src/views/rule.html index ee8fa78..769f378 100644 --- a/front/src/views/rule.html +++ b/front/src/views/rule.html @@ -141,7 +141,7 @@
-
+
@@ -158,7 +158,6 @@
{{offender}}
-
diff --git a/lib/metadata/policies.js b/lib/metadata/policies.js index 869f50a..0f52db5 100644 --- a/lib/metadata/policies.js +++ b/lib/metadata/policies.js @@ -899,7 +899,7 @@ var policies = { } }, "totalWeight": { - "tool": "weightChecker", + "tool": "redownload", "label": "Total weight", "message": "

The weight is of course very important if you want the page to load fast. Try to stay under 1MB, which is alreay very long to download over a slow connection.

Please note that Yellow Lab Tools' engine (PhantomJS) is not compatible with image srcset (unless you use a polyfill). This can lead to incorrect page weight.

", "isOkThreshold": 716800, @@ -909,7 +909,7 @@ var policies = { "unit": 'bytes' }, "imageOptimization": { - "tool": "weightChecker", + "tool": "redownload", "label": "Image optimization", "message": "

This metric measures the number of bytes that could be saved by optimizing images.

Image optimization is generally one of the easiest way to reduce a page weight, and as a result, the page load time. Don't use Photoshop or other image editing tools, they're not very good for optimization. Use specialized tools such as Kraken.io or the excellent ImageOptim on Mac. For SVG images, you can use SVGOMG

The tools in use in YellowLabTools are not set to their maximum optimization power (JPEG quality 85), so you might be able to compress even more!

Please note that Yellow Lab Tools' engine (PhantomJS) is not compatible with image srcset (unless you use a polyfill). This can lead to incorrect page weight.

", "isOkThreshold": 10240, @@ -919,7 +919,7 @@ var policies = { "unit": 'bytes' }, "gzipCompression": { - "tool": "weightChecker", + "tool": "redownload", "label": "Gzip compression", "message": "

Measures the number of bytes that could be saved by compressing file transfers.

Gzip is a powerfull weight reducer and should be enabled on text-based assets in your server's configuration. Note that gzipping small files (< 1 KB) is arguable, and that some assets such as images should not be gzipped as they are already compressed. Here is a list of Content-Types that should be gzipped.

", "isOkThreshold": 5125, @@ -929,7 +929,7 @@ var policies = { "unit": 'bytes' }, "fileMinification": { - "tool": "weightChecker", + "tool": "redownload", "label": "File minification", "message": "

This is the weight that could be saved if all text resources were correctly minified.

The tools in use here are UglifyJS, clean-css and HTMLMinifier. These tools are so good that some of your minified files can be marked as unminified. Change your tool it this happens :)

The gains of minification are generally small, but the impact can be high when these text files are loaded on the critical path.

", "isOkThreshold": 5125, @@ -939,7 +939,7 @@ var policies = { "unit": 'bytes' }, "totalRequests": { - "tool": "weightChecker", + "tool": "redownload", "label": "Requests number", "message": "

This is one of the most important performance rule. Every request is slowing down the page loading.

There are several technics to reduce their number:

  • Concatenate JS files
  • Concatenate CSS files
  • Embed or inline small JS or CSS files in the HTML
  • Create sprites or icon fonts
  • Base64 encode small images in HTML or stylesheets
  • Use lazyloading for images

", "isOkThreshold": 15, @@ -1003,8 +1003,17 @@ var policies = { "isAbnormalThreshold": 10, "hasOffenders": true }, + "emptyRequests": { + "tool": "redownload", + "label": "Empty requests", + "message": "

List of GET requests that respond with an empty body. These are probably the easiest requests to remove.

", + "isOkThreshold": 0, + "isBadThreshold": 1, + "isAbnormalThreshold": 5, + "hasOffenders": true + }, "smallRequests": { - "tool": "weightChecker", + "tool": "redownload", "label": "Small requests", "message": "

List of all requests that are less than 2 KB. Try to merge them with other files.

", "isOkThreshold": 4, diff --git a/lib/metadata/scoreProfileGeneric.json b/lib/metadata/scoreProfileGeneric.json index 565ead7..ccd5512 100644 --- a/lib/metadata/scoreProfileGeneric.json +++ b/lib/metadata/scoreProfileGeneric.json @@ -16,6 +16,7 @@ "domains": 3, "notFound": 3, "multipleRequests": 2, + "emptyRequests": 3, "smallRequests": 1, "lazyLoadableImagesBelowTheFold": 2, "hiddenImages": 1 diff --git a/lib/runner.js b/lib/runner.js index 4c5daf2..3648a73 100644 --- a/lib/runner.js +++ b/lib/runner.js @@ -6,7 +6,7 @@ var jsExecutionTransformer = require('./tools/jsExecutionTransformer'); var colorDiff = require('./tools/colorDiff'); var mediaQueriesChecker = require('./tools/mediaQueriesChecker'); var isHttp2 = require('./tools/isHttp2'); -var weightChecker = require('./tools/weightChecker/weightChecker'); +var redownload = require('./tools/redownload/redownload'); var rulesChecker = require('./rulesChecker'); var scoreCalculator = require('./scoreCalculator'); @@ -38,7 +38,7 @@ var Runner = function(params) { data = mediaQueriesChecker.analyzeMediaQueries(data); // Redownload every file - return weightChecker.recheckAllFiles(data); + return redownload.recheckAllFiles(data); }) diff --git a/lib/tools/weightChecker/contentTypeChecker.js b/lib/tools/redownload/contentTypeChecker.js similarity index 100% rename from lib/tools/weightChecker/contentTypeChecker.js rename to lib/tools/redownload/contentTypeChecker.js diff --git a/lib/tools/weightChecker/fileMinifier.js b/lib/tools/redownload/fileMinifier.js similarity index 100% rename from lib/tools/weightChecker/fileMinifier.js rename to lib/tools/redownload/fileMinifier.js diff --git a/lib/tools/weightChecker/gzipCompressor.js b/lib/tools/redownload/gzipCompressor.js similarity index 100% rename from lib/tools/weightChecker/gzipCompressor.js rename to lib/tools/redownload/gzipCompressor.js diff --git a/lib/tools/weightChecker/imageOptimizer.js b/lib/tools/redownload/imageOptimizer.js similarity index 100% rename from lib/tools/weightChecker/imageOptimizer.js rename to lib/tools/redownload/imageOptimizer.js diff --git a/lib/tools/weightChecker/weightChecker.js b/lib/tools/redownload/redownload.js similarity index 94% rename from lib/tools/weightChecker/weightChecker.js rename to lib/tools/redownload/redownload.js index f69fc4a..693eb23 100644 --- a/lib/tools/weightChecker/weightChecker.js +++ b/lib/tools/redownload/redownload.js @@ -5,7 +5,7 @@ */ -var debug = require('debug')('ylt:weightChecker'); +var debug = require('debug')('ylt:redownload'); var Q = require('q'); var http = require('http'); var zlib = require('zlib'); @@ -18,7 +18,7 @@ var gzipCompressor = require('./gzipCompressor'); var contentTypeChecker = require('./contentTypeChecker'); -var WeightChecker = function() { +var Redownload = function() { var MAX_PARALLEL_DOWNLOADS = 10; var REQUEST_TIMEOUT = 15000; // 15 seconds @@ -86,9 +86,10 @@ var WeightChecker = function() { offenders.totalRequests = listRequestsByType(results); metrics.totalRequests = offenders.totalRequests.total; - // Remove unwanted requests (redirections, about:blank) + + // Remove unwanted responses (redownload failed, about:blank) results = results.filter(function(result) { - return (result !== null && result.weightCheck && result.weightCheck.bodySize > 0); + return (result !== null && result.weightCheck && result.url.indexOf('about:blank') !== 0); }); @@ -100,6 +101,17 @@ var WeightChecker = function() { offenders.totalWeight = listRequestWeight(results); metrics.totalWeight = offenders.totalWeight.totalWeight; + // Empty files + offenders.emptyRequests = listEmptyRequests(results); + metrics.emptyRequests = offenders.emptyRequests.length; + + + // Now emove unwanted responses (redirections) + results = results.filter(function(result) { + return (result.status < 300 || result.status >= 400); + }); + + // Image compression offenders.imageOptimization = listImageNotOptimized(results); metrics.imageOptimization = offenders.imageOptimization.totalGain; @@ -116,7 +128,7 @@ var WeightChecker = function() { offenders.smallRequests = listSmallRequests(results); metrics.smallRequests = offenders.smallRequests.total; - data.toolsResults.weightChecker = { + data.toolsResults.redownload = { metrics: metrics, offenders: offenders }; @@ -144,6 +156,20 @@ var WeightChecker = function() { return results; } + function listEmptyRequests(requests) { + var results = []; + + requests.forEach(function(req) { + var weight = req.weightCheck.bodySize || req.contentLength; + + if (weight === 0 && req.method === 'GET' && req.status === 200) { + results.push(req.url); + } + }); + + return results; + } + function listRequestWeight(requests) { var results = { totalWeight: 0, @@ -555,4 +581,4 @@ var WeightChecker = function() { }; }; -module.exports = new WeightChecker(); \ No newline at end of file +module.exports = new Redownload(); \ No newline at end of file diff --git a/test/core/contentTypeCheckerTest.js b/test/core/contentTypeCheckerTest.js index ae7c833..ac67cc4 100644 --- a/test/core/contentTypeCheckerTest.js +++ b/test/core/contentTypeCheckerTest.js @@ -1,5 +1,5 @@ var should = require('chai').should(); -var contentTypeChecker = require('../../lib/tools/weightChecker/contentTypeChecker'); +var contentTypeChecker = require('../../lib/tools/redownload/contentTypeChecker'); var fs = require('fs'); var path = require('path'); diff --git a/test/core/fileMinifierTest.js b/test/core/fileMinifierTest.js index 90ce452..348810b 100644 --- a/test/core/fileMinifierTest.js +++ b/test/core/fileMinifierTest.js @@ -1,5 +1,5 @@ var should = require('chai').should(); -var fileMinifier = require('../../lib/tools/weightChecker/fileMinifier'); +var fileMinifier = require('../../lib/tools/redownload/fileMinifier'); var fs = require('fs'); var path = require('path'); diff --git a/test/core/gzipCompressorTest.js b/test/core/gzipCompressorTest.js index 66a66d6..c436e02 100644 --- a/test/core/gzipCompressorTest.js +++ b/test/core/gzipCompressorTest.js @@ -1,6 +1,6 @@ var should = require('chai').should(); -var gzipCompressor = require('../../lib/tools/weightChecker/gzipCompressor'); -var fileMinifier = require('../../lib/tools/weightChecker/fileMinifier'); +var gzipCompressor = require('../../lib/tools/redownload/gzipCompressor'); +var fileMinifier = require('../../lib/tools/redownload/fileMinifier'); var fs = require('fs'); var path = require('path'); diff --git a/test/core/imageOptimizerTest.js b/test/core/imageOptimizerTest.js index 9871491..e858962 100644 --- a/test/core/imageOptimizerTest.js +++ b/test/core/imageOptimizerTest.js @@ -1,5 +1,5 @@ var should = require('chai').should(); -var imageOptimizer = require('../../lib/tools/weightChecker/imageOptimizer'); +var imageOptimizer = require('../../lib/tools/redownload/imageOptimizer'); var fs = require('fs'); var path = require('path'); diff --git a/test/core/weightCheckerTest.js b/test/core/redownloadTest.js similarity index 70% rename from test/core/weightCheckerTest.js rename to test/core/redownloadTest.js index 2e93bea..8a12ab3 100644 --- a/test/core/weightCheckerTest.js +++ b/test/core/redownloadTest.js @@ -1,9 +1,9 @@ var should = require('chai').should(); -var weightChecker = require('../../lib/tools/weightChecker/weightChecker'); +var redownload = require('../../lib/tools/redownload/redownload'); var fs = require('fs'); var path = require('path'); -describe('weightChecker', function() { +describe('redownload', function() { it('should download a list of files', function(done) { this.timeout(10000); @@ -121,49 +121,49 @@ describe('weightChecker', function() { } }; - weightChecker.recheckAllFiles(data) + redownload.recheckAllFiles(data) .then(function(data) { - data.toolsResults.should.have.a.property('weightChecker'); - data.toolsResults.weightChecker.should.have.a.property('metrics'); - data.toolsResults.weightChecker.should.have.a.property('offenders'); + data.toolsResults.should.have.a.property('redownload'); + data.toolsResults.redownload.should.have.a.property('metrics'); + data.toolsResults.redownload.should.have.a.property('offenders'); - data.toolsResults.weightChecker.offenders.should.have.a.property('totalWeight'); - data.toolsResults.weightChecker.offenders.totalWeight.totalWeight.should.be.above(0); - data.toolsResults.weightChecker.offenders.totalWeight.byType.html.requests.length.should.equal(1); - data.toolsResults.weightChecker.offenders.totalWeight.byType.js.requests.length.should.equal(2); - data.toolsResults.weightChecker.offenders.totalWeight.byType.css.requests.length.should.equal(1); - data.toolsResults.weightChecker.offenders.totalWeight.byType.image.requests.length.should.equal(2); - data.toolsResults.weightChecker.offenders.totalWeight.byType.other.requests.length.should.equal(1); + data.toolsResults.redownload.offenders.should.have.a.property('totalWeight'); + data.toolsResults.redownload.offenders.totalWeight.totalWeight.should.be.above(0); + data.toolsResults.redownload.offenders.totalWeight.byType.html.requests.length.should.equal(1); + data.toolsResults.redownload.offenders.totalWeight.byType.js.requests.length.should.equal(2); + data.toolsResults.redownload.offenders.totalWeight.byType.css.requests.length.should.equal(1); + data.toolsResults.redownload.offenders.totalWeight.byType.image.requests.length.should.equal(2); + data.toolsResults.redownload.offenders.totalWeight.byType.other.requests.length.should.equal(1); - data.toolsResults.weightChecker.offenders.should.have.a.property('imageOptimization'); - data.toolsResults.weightChecker.offenders.imageOptimization.totalGain.should.be.above(0); - data.toolsResults.weightChecker.offenders.imageOptimization.images.length.should.equal(2); + data.toolsResults.redownload.offenders.should.have.a.property('imageOptimization'); + data.toolsResults.redownload.offenders.imageOptimization.totalGain.should.be.above(0); + data.toolsResults.redownload.offenders.imageOptimization.images.length.should.equal(2); - data.toolsResults.weightChecker.offenders.should.have.a.property('gzipCompression'); - data.toolsResults.weightChecker.offenders.gzipCompression.totalGain.should.be.above(0); - data.toolsResults.weightChecker.offenders.gzipCompression.files.length.should.equal(5); + data.toolsResults.redownload.offenders.should.have.a.property('gzipCompression'); + data.toolsResults.redownload.offenders.gzipCompression.totalGain.should.be.above(0); + data.toolsResults.redownload.offenders.gzipCompression.files.length.should.equal(5); - data.toolsResults.weightChecker.offenders.should.have.a.property('fileMinification'); - data.toolsResults.weightChecker.offenders.fileMinification.totalGain.should.be.above(0); - data.toolsResults.weightChecker.offenders.fileMinification.files.length.should.equal(2); + data.toolsResults.redownload.offenders.should.have.a.property('fileMinification'); + data.toolsResults.redownload.offenders.fileMinification.totalGain.should.be.above(0); + data.toolsResults.redownload.offenders.fileMinification.files.length.should.equal(2); - data.toolsResults.weightChecker.metrics.should.have.a.property('totalRequests').that.equals(7); - data.toolsResults.weightChecker.offenders.should.have.a.property('totalRequests'); - data.toolsResults.weightChecker.offenders.totalRequests.byType.html.length.should.equal(1); - data.toolsResults.weightChecker.offenders.totalRequests.byType.js.length.should.equal(2); - data.toolsResults.weightChecker.offenders.totalRequests.byType.css.length.should.equal(1); - data.toolsResults.weightChecker.offenders.totalRequests.byType.image.length.should.equal(2); - data.toolsResults.weightChecker.offenders.totalRequests.byType.json.length.should.equal(0); - data.toolsResults.weightChecker.offenders.totalRequests.byType.webfont.length.should.equal(0); - data.toolsResults.weightChecker.offenders.totalRequests.byType.video.length.should.equal(0); - data.toolsResults.weightChecker.offenders.totalRequests.byType.other.length.should.equal(1); + data.toolsResults.redownload.metrics.should.have.a.property('totalRequests').that.equals(7); + data.toolsResults.redownload.offenders.should.have.a.property('totalRequests'); + data.toolsResults.redownload.offenders.totalRequests.byType.html.length.should.equal(1); + data.toolsResults.redownload.offenders.totalRequests.byType.js.length.should.equal(2); + data.toolsResults.redownload.offenders.totalRequests.byType.css.length.should.equal(1); + data.toolsResults.redownload.offenders.totalRequests.byType.image.length.should.equal(2); + data.toolsResults.redownload.offenders.totalRequests.byType.json.length.should.equal(0); + data.toolsResults.redownload.offenders.totalRequests.byType.webfont.length.should.equal(0); + data.toolsResults.redownload.offenders.totalRequests.byType.video.length.should.equal(0); + data.toolsResults.redownload.offenders.totalRequests.byType.other.length.should.equal(1); - data.toolsResults.weightChecker.metrics.should.have.a.property('smallRequests').that.equals(0); - data.toolsResults.weightChecker.offenders.should.have.a.property('smallRequests'); - data.toolsResults.weightChecker.offenders.smallRequests.byType.js.length.should.equal(0); - data.toolsResults.weightChecker.offenders.smallRequests.byType.css.length.should.equal(0); - data.toolsResults.weightChecker.offenders.smallRequests.byType.image.length.should.equal(0); + data.toolsResults.redownload.metrics.should.have.a.property('smallRequests').that.equals(0); + data.toolsResults.redownload.offenders.should.have.a.property('smallRequests'); + data.toolsResults.redownload.offenders.smallRequests.byType.js.length.should.equal(0); + data.toolsResults.redownload.offenders.smallRequests.byType.css.length.should.equal(0); + data.toolsResults.redownload.offenders.smallRequests.byType.image.length.should.equal(0); done(); }) @@ -187,7 +187,7 @@ describe('weightChecker', function() { type: 'js' }; - weightChecker.redownloadEntry(entry) + redownload.redownloadEntry(entry) .then(function(newEntry) { @@ -221,7 +221,7 @@ describe('weightChecker', function() { contentType: 'image/png' }; - weightChecker.redownloadEntry(entry) + redownload.redownloadEntry(entry) .then(function(newEntry) { @@ -258,7 +258,7 @@ describe('weightChecker', function() { contentLength: 999 }; - weightChecker.redownloadEntry(entry) + redownload.redownloadEntry(entry) .then(function(newEntry) { newEntry.weightCheck.should.have.a.property('message').that.equals('error while downloading: 404'); @@ -285,7 +285,7 @@ describe('weightChecker', function() { contentLength: 999 }; - weightChecker.redownloadEntry(entry) + redownload.redownloadEntry(entry) .then(function(newEntry) { newEntry.should.not.have.a.property('weightCheck'); @@ -298,7 +298,7 @@ describe('weightChecker', function() { }); it('should listRequestWeight', function() { - var totalWeightObj = weightChecker.listRequestWeight([{ + var totalWeightObj = redownload.listRequestWeight([{ method: 'GET', url: 'http://localhost:8388/jquery1.8.3.js', requestHeaders: { @@ -328,7 +328,7 @@ describe('weightChecker', function() { }); it('should listRequestWeight even if download failed', function() { - var totalWeightObj = weightChecker.listRequestWeight([{ + var totalWeightObj = redownload.listRequestWeight([{ method: 'GET', url: 'http://localhost:8388/jquery1.8.3.js', requestHeaders: { From 6da6377bb518c2ae4855329370cd9446b6a536ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20M=C3=A9tais?= Date: Mon, 11 Jul 2016 17:01:24 +0800 Subject: [PATCH 20/22] New rule "Identical content" (#181) --- front/src/views/rule.html | 11 ++++++ lib/metadata/policies.js | 17 ++++++---- lib/metadata/scoreProfileGeneric.json | 2 +- lib/tools/redownload/redownload.js | 49 +++++++++++++++++++++++++-- package.json | 1 + 5 files changed, 70 insertions(+), 10 deletions(-) diff --git a/front/src/views/rule.html b/front/src/views/rule.html index 769f378..99aca48 100644 --- a/front/src/views/rule.html +++ b/front/src/views/rule.html @@ -335,6 +335,17 @@
+
+
+

A file of {{offender.weight | bytes}} is loaded {{offender.urls.length}} times:

+
+
+
+
+
+
+
+

diff --git a/lib/metadata/policies.js b/lib/metadata/policies.js index 0f52db5..65e7d3f 100644 --- a/lib/metadata/policies.js +++ b/lib/metadata/policies.js @@ -994,14 +994,17 @@ var policies = { "isAbnormalThreshold": 20, "hasOffenders": true }, - "multipleRequests": { - "tool": "phantomas", - "label": "Duplicated requests", - "message": "

This only happens when the asset has no cache and is requested more than once on the same page. Be very careful about it.

", + "identicalFiles": { + "tool": "redownload", + "label": "Identical content", + "message": "

This is the number of requests that could be avoided, because of downloaded files that have the same content but are loaded from different URLs.

Try to load them from the same URL.

", "isOkThreshold": 0, - "isBadThreshold": 3, - "isAbnormalThreshold": 10, - "hasOffenders": true + "isBadThreshold": 5, + "isAbnormalThreshold": 15, + "hasOffenders": true, + "offendersTransformFn": function(offenders) { + return offenders; + } }, "emptyRequests": { "tool": "redownload", diff --git a/lib/metadata/scoreProfileGeneric.json b/lib/metadata/scoreProfileGeneric.json index ccd5512..958db6a 100644 --- a/lib/metadata/scoreProfileGeneric.json +++ b/lib/metadata/scoreProfileGeneric.json @@ -15,7 +15,7 @@ "totalRequests": 5, "domains": 3, "notFound": 3, - "multipleRequests": 2, + "identicalFiles": 2, "emptyRequests": 3, "smallRequests": 1, "lazyLoadableImagesBelowTheFold": 2, diff --git a/lib/tools/redownload/redownload.js b/lib/tools/redownload/redownload.js index 693eb23..e5a72ce 100644 --- a/lib/tools/redownload/redownload.js +++ b/lib/tools/redownload/redownload.js @@ -11,6 +11,7 @@ var http = require('http'); var zlib = require('zlib'); var async = require('async'); var request = require('request'); +var md5 = require('md5'); var imageOptimizer = require('./imageOptimizer'); var fileMinifier = require('./fileMinifier'); @@ -106,9 +107,9 @@ var Redownload = function() { metrics.emptyRequests = offenders.emptyRequests.length; - // Now emove unwanted responses (redirections) + // Now remove unwanted responses (redirections and empty files) results = results.filter(function(result) { - return (result.status < 300 || result.status >= 400); + return ((result.status < 300 || result.status >= 400) && result.weightCheck.bodySize > 0); }); @@ -128,6 +129,11 @@ var Redownload = function() { offenders.smallRequests = listSmallRequests(results); metrics.smallRequests = offenders.smallRequests.total; + // Detect identical files + offenders.identicalFiles = listIdenticalFiles(results); + metrics.identicalFiles = offenders.identicalFiles.avoidableRequests; + + data.toolsResults.redownload = { metrics: metrics, offenders: offenders @@ -368,6 +374,45 @@ var Redownload = function() { return results; } + function listIdenticalFiles(requests) { + var hashes = {}; + var list = []; + var avoidableRequestsCount = 0; + + requests.forEach(function(req) { + var requestHash = md5(req.weightCheck.body); + + // Try to exclude tracking pixels + if (req.weightCheck.bodySize < 80 && req.type === 'image') { + return; + } + + if (!hashes[requestHash]) { + hashes[requestHash] = { + weight: req.weightCheck.bodySize, + urls: [] + }; + } + + if (hashes[requestHash].urls.indexOf(req.url) === -1) { + hashes[requestHash].urls.push(req.url); + } + }); + + for (var hash in hashes) { + if (hashes[hash].urls.length > 1) { + list.push(hashes[hash]); + avoidableRequestsCount += hashes[hash].urls.length - 1; + } + } + + return { + avoidableRequests: avoidableRequestsCount, + count: list.length, + list: list + }; + } + function redownloadEntry(entry, httpAuth) { var deferred = Q.defer(); diff --git a/package.json b/package.json index 6dc56b3..b29fa29 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "is-woff": "1.0.3", "is-woff2": "1.0.0", "lwip": "0.0.9", + "md5": "2.1.0", "meow": "3.7.0", "minimize": "2.0.0", "parse-color": "1.0.0", From decfc5823d03680df09700b0549e519b92b47e41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20M=C3=A9tais?= Date: Mon, 11 Jul 2016 18:17:15 +0800 Subject: [PATCH 21/22] Releasing v1.11.0 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index b29fa29..ad99ee2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "yellowlabtools", - "version": "1.10.2", + "version": "1.11.0", "description": "Online tool to audit a webpage for performance and front-end quality issues", "license": "GPL-2.0", "author": { @@ -58,7 +58,7 @@ "meow": "3.7.0", "minimize": "2.0.0", "parse-color": "1.0.0", - "phantomas": "1.15.1", + "phantomas": "1.16.0", "ps-node": "0.1.2", "q": "1.4.1", "request": "2.72.0", From c20cacac99afa894879c3db2d6868b6373aacb33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20M=C3=A9tais?= Date: Mon, 11 Jul 2016 22:03:27 +0800 Subject: [PATCH 22/22] Redownload files with the keep-alive option --- lib/tools/redownload/redownload.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/tools/redownload/redownload.js b/lib/tools/redownload/redownload.js index e5a72ce..97eff8a 100644 --- a/lib/tools/redownload/redownload.js +++ b/lib/tools/redownload/redownload.js @@ -4,6 +4,7 @@ * */ +/*jshint -W069 */ var debug = require('debug')('ylt:redownload'); var Q = require('q'); @@ -460,6 +461,7 @@ var Redownload = function() { // Always add a gzip header before sending, in case the server listens to it var reqHeaders = entry.requestHeaders; reqHeaders['Accept-Encoding'] = 'gzip, deflate'; + reqHeaders['Connection'] = 'keep-alive'; var requestOptions = { method: entry.method,