|
@@ -66,6 +66,15 @@ var policies = {
|
|
|
};
|
|
|
}
|
|
|
},
|
|
|
+ /*"DOMaccesses": {
|
|
|
+ "tool": "jsExecutionTransformer",
|
|
|
+ "label": "DOM access",
|
|
|
+ "message": "<p>TODO</p><p>TODO</p>",
|
|
|
+ "isOkThreshold": 50,
|
|
|
+ "isBadThreshold": 2000,
|
|
|
+ "isAbnormalThreshold": 3000,
|
|
|
+ "hasOffenders": false
|
|
|
+ },*/
|
|
|
"DOMinserts": {
|
|
|
"tool": "phantomas",
|
|
|
"label": "DOM inserts",
|
|
@@ -195,6 +204,49 @@ var policies = {
|
|
|
};
|
|
|
}
|
|
|
},
|
|
|
+ "eventsScrollBound": {
|
|
|
+ "tool": "phantomas",
|
|
|
+ "label": "Scroll events bound",
|
|
|
+ "message": "<p>Number of 'scroll' event listeners binded to 'window' or 'document'.</p><p>Asking too much work to the browser on scroll hurts the smoothness of the scroll. Merging all your event listeners into an unique listener can help you factorize their code and reduce their footprint on scroll.</p>",
|
|
|
+ "isOkThreshold": 1,
|
|
|
+ "isBadThreshold": 7,
|
|
|
+ "isAbnormalThreshold": 12,
|
|
|
+ "hasOffenders": true,
|
|
|
+ "offendersTransformFn": function(offenders) {
|
|
|
+ return {
|
|
|
+ count: offenders.length,
|
|
|
+ list: offenders.map(function(offender) {
|
|
|
+ var parts = /^bound by (.*) on ([^ ]+)$/.exec(offender);
|
|
|
+
|
|
|
+ if (!parts) {
|
|
|
+ debug('eventsScrollBound offenders transform function error with "%s"', offender);
|
|
|
+ return {
|
|
|
+ parseError: offender
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ var backtraceArray = offendersHelpers.backtraceToArray(parts[1]);
|
|
|
+
|
|
|
+ return {
|
|
|
+ backtrace: backtraceArray || [],
|
|
|
+ target: parts[2]
|
|
|
+ };
|
|
|
+ })
|
|
|
+ };
|
|
|
+ }
|
|
|
+ },
|
|
|
+ "DOMaccessesOnScroll": {
|
|
|
+ "tool": "jsExecutionTransformer",
|
|
|
+ "label": "DOM access on scroll",
|
|
|
+ "message": "<p>This rule counts the number of DOM-accessing functions calls, such as queries, readings, writings, bindings and jQuery functions.</p><p>Two scroll events are triggered quickly, one after the other, and only the second one is analyzed so throttled functions are ignored.</p><p>One of the main reasons of a poor scrolling experience is when too much JS is executed on each scroll event. Note that some devices such as smartphones and MacBooks send more scroll events than others.</p><p>Reduce the number of DOM accesses inside scroll listeners. Put DOM queries outside them when possible. Use <a href=\"http://blogorama.nerdworks.in/javascriptfunctionthrottlingan/\" target=\"_blank\">throttling or deboucing</a>.</p>",
|
|
|
+ "isOkThreshold": 1,
|
|
|
+ "isBadThreshold": 12,
|
|
|
+ "isAbnormalThreshold": 25,
|
|
|
+ "hasOffenders": true,
|
|
|
+ "offendersTransformFn": function(offenders) {
|
|
|
+ return offenders;
|
|
|
+ }
|
|
|
+ },
|
|
|
"jsErrors": {
|
|
|
"tool": "phantomas",
|
|
|
"label": "JavaScript errors",
|
|
@@ -371,39 +423,79 @@ var policies = {
|
|
|
},
|
|
|
"jQueryVersionsLoaded": {
|
|
|
"tool": "phantomas",
|
|
|
- "label": "Several versions loaded",
|
|
|
+ "label": "Several jQuery loaded",
|
|
|
"message": "<p>jQuery is a heavy library. You should <b>never</b> load jQuery more than once on the same page.</p>",
|
|
|
"isOkThreshold": 1,
|
|
|
"isBadThreshold": 2,
|
|
|
"isAbnormalThreshold": 2,
|
|
|
"hasOffenders": true
|
|
|
},
|
|
|
+ "jQueryFunctionsUsed": {
|
|
|
+ "tool": "jsExecutionTransformer",
|
|
|
+ "label": "jQuery usage",
|
|
|
+ "message": "<p>This is the number of different jQuery functions called on load. This rule is not trying to blame you for using jQuery too much, but the opposite.</p><p>If only a few functions are used, why not trying to get rid of jQuery? Have a look at <a href=\"http://youmightnotneedjquery.com/\" target=\"_blank\">http://youmightnotneedjquery.com</a>.</p>",
|
|
|
+ "isOkThreshold": 15,
|
|
|
+ "isBadThreshold": 6,
|
|
|
+ "isAbnormalThreshold": 0,
|
|
|
+ "hasOffenders": true
|
|
|
+ },
|
|
|
+ "jQueryNotDelegatedEvents": {
|
|
|
+ "tool": "jsExecutionTransformer",
|
|
|
+ "label": "Events not delegated",
|
|
|
+ "message": "<p>This is the number of events that are bound with the .bind() or the .on() function without using <a href=\"https://learn.jquery.com/events/event-delegation/\" target=\"_blank\">event delegation</a>.</p><p>This means jQuery binds each element contained in the object one by one. This is bad for performance.</p>",
|
|
|
+ "isOkThreshold": 1,
|
|
|
+ "isBadThreshold": 100,
|
|
|
+ "isAbnormalThreshold": 180,
|
|
|
+ "hasOffenders": true
|
|
|
+ },
|
|
|
"cssParsingErrors": {
|
|
|
"tool": "phantomas",
|
|
|
"label": "CSS syntax error",
|
|
|
"message": "<p>Yellow Lab Tools failed to parse a CSS file. I doubt the problem comes from the css parser.</p><p>Maybe a <a href=\"http://jigsaw.w3.org/css-validator\" target=\"_blank\">CSS validator</a> can help you.</p>",
|
|
|
"isOkThreshold": 0,
|
|
|
"isBadThreshold": 1,
|
|
|
- "isAbnormalThreshold": 1,
|
|
|
+ "isAbnormalThreshold": 8,
|
|
|
"hasOffenders": true,
|
|
|
"offendersTransformFn": function(offenders) {
|
|
|
return {
|
|
|
count: offenders.length,
|
|
|
list: offenders.map(function(offender) {
|
|
|
+ if (offender === '[inline CSS] (Empty CSS was provided)') {
|
|
|
+ return {
|
|
|
+ error: 'Empty style tag',
|
|
|
+ file: null,
|
|
|
+ line: null,
|
|
|
+ column: null
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
var parts = /^(?:(?:<([^ \(]*)>|\[inline CSS\]) ?)?(?:\((((?! @ ).)*)(?: @ (\d+):(\d+))?\))?$/.exec(offender);
|
|
|
|
|
|
- if (!parts) {
|
|
|
- debug('cssParsingErrors offenders transform function error with "%s"', offender);
|
|
|
+ if (parts) {
|
|
|
return {
|
|
|
- parseError: offender
|
|
|
+ error: parts[2] || 'Unknown parsing error' + (parts[1] ? '. The entire file was ignored. As a result, the other CSS metrics and scores are miscalculated.' : ''),
|
|
|
+ file: parts[1] || null,
|
|
|
+ line: (parts[4] && parts[5]) ? parseInt(parts[4], 10) : null,
|
|
|
+ column: (parts[4] && parts[5]) ? parseInt(parts[5], 10) : null
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ // Try another syntax
|
|
|
+ parts = /^(.*) <(.*)> @ (\d+):(\d+)$/.exec(offender);
|
|
|
+
|
|
|
+ if (parts) {
|
|
|
+ return {
|
|
|
+ error: parts[1] || 'Unknown parsing error',
|
|
|
+ file: parts[2] || null,
|
|
|
+ line: parseInt(parts[3], 10),
|
|
|
+ column: parseInt(parts[4], 10)
|
|
|
};
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ debug('cssParsingErrors offenders transform function error with "%s"', offender);
|
|
|
return {
|
|
|
- error: parts[2],
|
|
|
- file: parts[1] || null,
|
|
|
- line: (parts[4] && parts[5]) ? parseInt(parts[4], 10) : null,
|
|
|
- column: (parts[4] && parts[5]) ? parseInt(parts[5], 10) : null
|
|
|
+ parseError: offender
|
|
|
};
|
|
|
})
|
|
|
};
|
|
@@ -413,9 +505,9 @@ var policies = {
|
|
|
"tool": "phantomas",
|
|
|
"label": "Rules count",
|
|
|
"message": "<p>Having a huge number of CSS rules hurts performances. If the number of CSS rules is higher than the number of DOM elements, there is clearly a problem.</p><p>Huge stylesheets generally occur when the different pages of a website load all the CSS, concatenated in a single stylesheet, even if a large part of the rules are page-specific. Solution is to create one main CSS file with global rules and one custom file per page.</p>",
|
|
|
- "isOkThreshold": 500,
|
|
|
- "isBadThreshold": 2500,
|
|
|
- "isAbnormalThreshold": 4000,
|
|
|
+ "isOkThreshold": 750,
|
|
|
+ "isBadThreshold": 3000,
|
|
|
+ "isAbnormalThreshold": 4500,
|
|
|
"hasOffenders": false
|
|
|
},
|
|
|
"cssComplexSelectors": {
|
|
@@ -423,7 +515,7 @@ var policies = {
|
|
|
"label": "Complex selectors",
|
|
|
"message": "<p>Complex selectors are CSS selectors with 4 or more expressions, like \"#header ul li .foo\".</p><p>They are adding more work for the browser, and this could be avoided by simplifying selectors.</p>",
|
|
|
"isOkThreshold": 0,
|
|
|
- "isBadThreshold": 500,
|
|
|
+ "isBadThreshold": 600,
|
|
|
"isAbnormalThreshold": 2000,
|
|
|
"hasOffenders": true,
|
|
|
"offendersTransformFn": function(offenders) {
|
|
@@ -441,8 +533,8 @@ var policies = {
|
|
|
"label": "Complex attributes selector",
|
|
|
"message": "<p>Complex attributes selectors are one of these:<ul><li>.foo[type*=bar] (contains bar)</li><li>.foo[type^=bar] (starts with bar)</li><li>.foo[type|=bar] (starts with bar or bar-)</li><li>.foo[type$=bar] (ends with bar)</li><li>.foo[type~=bar baz] (bar or baz)</li></ul></p><p>Their matching process needs more CPU and it has a cost on performances.</p>",
|
|
|
"isOkThreshold": 0,
|
|
|
- "isBadThreshold": 50,
|
|
|
- "isAbnormalThreshold": 100,
|
|
|
+ "isBadThreshold": 75,
|
|
|
+ "isAbnormalThreshold": 150,
|
|
|
"hasOffenders": true,
|
|
|
"offendersTransformFn": function(offenders) {
|
|
|
return {
|
|
@@ -526,8 +618,8 @@ var policies = {
|
|
|
"label": "Duplicated selectors",
|
|
|
"message": "<p>This is when two or more selectors are strictly identical and should be merged.</p>",
|
|
|
"isOkThreshold": 0,
|
|
|
- "isBadThreshold": 40,
|
|
|
- "isAbnormalThreshold": 80,
|
|
|
+ "isBadThreshold": 50,
|
|
|
+ "isAbnormalThreshold": 100,
|
|
|
"hasOffenders": true,
|
|
|
"offendersTransformFn": function(offenders) {
|
|
|
return {
|
|
@@ -555,8 +647,8 @@ var policies = {
|
|
|
"label": "Duplicated properties",
|
|
|
"message": "<p>This is the number of property definitions duplicated within a selector.</p>",
|
|
|
"isOkThreshold": 0,
|
|
|
- "isBadThreshold": 50,
|
|
|
- "isAbnormalThreshold": 100,
|
|
|
+ "isBadThreshold": 60,
|
|
|
+ "isAbnormalThreshold": 120,
|
|
|
"hasOffenders": true,
|
|
|
"offendersTransformFn": function(offenders) {
|
|
|
return {
|
|
@@ -589,7 +681,7 @@ var policies = {
|
|
|
"label": "Empty rules",
|
|
|
"message": "<p>Very easy to fix: remove all empty rules.</p>",
|
|
|
"isOkThreshold": 0,
|
|
|
- "isBadThreshold": 40,
|
|
|
+ "isBadThreshold": 50,
|
|
|
"isAbnormalThreshold": 100,
|
|
|
"hasOffenders": true,
|
|
|
"offendersTransformFn": function(offenders) {
|
|
@@ -643,8 +735,8 @@ var policies = {
|
|
|
"label": "Uses of !important",
|
|
|
"message": "<p>It can be useful, but only as a last resort. It is a bad practice because it overrides the normal cascading logic. The more you use !important, the more you need it again to over-override. This conducts to a poor maintainability.</p>",
|
|
|
"isOkThreshold": 0,
|
|
|
- "isBadThreshold": 50,
|
|
|
- "isAbnormalThreshold": 150,
|
|
|
+ "isBadThreshold": 75,
|
|
|
+ "isAbnormalThreshold": 200,
|
|
|
"hasOffenders": true,
|
|
|
"offendersTransformFn": function(offenders) {
|
|
|
return {
|
|
@@ -678,7 +770,7 @@ var policies = {
|
|
|
"label": "Old IE fixes",
|
|
|
"message": "<p>What browser do you need to support? Once you've got the answer, take a look at these old rules that pollute your CSS code and remove them.</p><p>IE6:<ul><li>* html</li><li>html > body (everything but IE6)</li></ul><p><p>IE7:<ul><li><b>*</b>height: 123px;</li><li>height: 123px <b>!ie</b>;</li></ul><p><p>IE9:<ul><li>-ms-filter</li><li>progid:DXImageTransform.Microsoft</li></ul></p>",
|
|
|
"isOkThreshold": 0,
|
|
|
- "isBadThreshold": 50,
|
|
|
+ "isBadThreshold": 75,
|
|
|
"isAbnormalThreshold": 300,
|
|
|
"hasOffenders": true,
|
|
|
"offendersTransformFn": function(offenders) {
|
|
@@ -735,7 +827,7 @@ var policies = {
|
|
|
"label": "Old prefixes",
|
|
|
"message": "<p>Many property prefixes such as -moz- or -webkit- are not needed anymore, or by very few people. You can remove them or replace them with the non-prefixed version. This will help reducing your stylesheets weight.</p>",
|
|
|
"isOkThreshold": 0,
|
|
|
- "isBadThreshold": 50,
|
|
|
+ "isBadThreshold": 75,
|
|
|
"isAbnormalThreshold": 300,
|
|
|
"hasOffenders": true,
|
|
|
"offendersTransformFn": function(offenders) {
|
|
@@ -771,7 +863,7 @@ var policies = {
|
|
|
"label": "Universal selectors",
|
|
|
"message": "<p>Universal selectors are the most expensive CSS selectors.</p><p>More informations <a href=\"http://perfectionkills.com/profiling-css-for-fun-and-profit-optimization-notes/\" target=\"_blank\">here</a>.</p>",
|
|
|
"isOkThreshold": 0,
|
|
|
- "isBadThreshold": 40,
|
|
|
+ "isBadThreshold": 50,
|
|
|
"isAbnormalThreshold": 150,
|
|
|
"hasOffenders": true,
|
|
|
"offendersTransformFn": function(offenders) {
|
|
@@ -789,7 +881,7 @@ var policies = {
|
|
|
"label": "Redundant body selectors",
|
|
|
"message": "<p>This is one way to remove complexity from a CSS rule. Generally, when \"body\" is specified in a rule it can be removed, because an element is necessarily inside the body.</p>",
|
|
|
"isOkThreshold": 0,
|
|
|
- "isBadThreshold": 50,
|
|
|
+ "isBadThreshold": 60,
|
|
|
"isAbnormalThreshold": 200,
|
|
|
"hasOffenders": true,
|
|
|
"offendersTransformFn": function(offenders) {
|
|
@@ -810,7 +902,7 @@ var policies = {
|
|
|
"label": "Redundant tags selectors",
|
|
|
"message": "<p>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 <b>always</b> inside a \"ul\". Same thing for \"tr td\", \"select option\", ...</p><p>Lowering compexity in CSS selectors can make the page load a little faster.</p>",
|
|
|
"isOkThreshold": 0,
|
|
|
- "isBadThreshold": 50,
|
|
|
+ "isBadThreshold": 60,
|
|
|
"isAbnormalThreshold": 200,
|
|
|
"hasOffenders": true,
|
|
|
"offendersTransformFn": function(offenders) {
|
|
@@ -1056,6 +1148,35 @@ var policies = {
|
|
|
"isAbnormalThreshold": 1,
|
|
|
"hasOffenders": true
|
|
|
},
|
|
|
+ "assetsNotGzipped": {
|
|
|
+ "tool": "phantomas",
|
|
|
+ "label": "Not gzipped",
|
|
|
+ "message": "<p>This is the number of requests that should be compressed with gzip but aren't.</p><p>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. <a href=\"https://gist.github.com/gmetais/971ce13a1fbeebd88445\" target=\"_blank\">Here</a> is a list of Content-Types that should be gzipped.</p>",
|
|
|
+ "isOkThreshold": 0,
|
|
|
+ "isBadThreshold": 12,
|
|
|
+ "isAbnormalThreshold": 20,
|
|
|
+ "hasOffenders": true,
|
|
|
+ "offendersTransformFn": function(offenders) {
|
|
|
+ return {
|
|
|
+ count: offenders.length,
|
|
|
+ list: offenders.map(function(offender) {
|
|
|
+ var parts = /^([^ ]*) \((.+)\)$/.exec(offender);
|
|
|
+
|
|
|
+ if (!parts) {
|
|
|
+ debug('assetsNotGzipped offenders transform function error with "%s"', offender);
|
|
|
+ return {
|
|
|
+ parseError: offender
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ return {
|
|
|
+ file: parts[1],
|
|
|
+ type: parts[2]
|
|
|
+ };
|
|
|
+ })
|
|
|
+ };
|
|
|
+ }
|
|
|
+ },
|
|
|
"closedConnections": {
|
|
|
"tool": "phantomas",
|
|
|
"label": "Connections closed",
|
|
@@ -1176,7 +1297,6 @@ var policies = {
|
|
|
domain: parts[1],
|
|
|
requests: parseInt(parts[2])
|
|
|
};
|
|
|
-
|
|
|
})
|
|
|
};
|
|
|
}
|