Browse Source

New DOMaccess agregated form + new score category JS complexity

Gaël Métais 4 years ago
parent
commit
ffd9efeb98

+ 7 - 0
front/src/js/directives/offendersDirectives.js

@@ -93,6 +93,13 @@
         };
     });
 
+    offendersDirectives.filter('lastDOMNode', function() {
+        return function(str) {
+            var splited = str.split(' > ');
+            return splited[splited.length - 1];
+        };
+    });
+
     function getBacktraceHTML(backtrace) {
         var html = '';
         var parsedBacktrace = parseBacktrace(backtrace);

+ 31 - 1
front/src/views/rule.html

@@ -30,7 +30,7 @@
         <p>This rule reached the abnormality threshold, which means there is a real problem you should care about.</p>
     </div>
     <div class="offenders" ng-if="rule.policy.hasOffenders">
-        <h3 ng-if="rule.offendersObj.count >= 0"><ng-pluralize count="rule.offendersObj.count" when="{'0': 'No offenders', 'one': '1 offender', 'other': '{} offenders'}"></ng-pluralize></h3>
+        <h3 ng-if="rule.offendersObj.count >= 0"><ng-pluralize count="rule.offendersObj.count" when="{'0': 'No offender', 'one': '1 offender', 'other': '{} offenders'}"></ng-pluralize></h3>
 
         <div ng-if="rule.offendersObj.list" class="offendersTable">
             <div ng-repeat="offender in rule.offendersObj.list track by $index">
@@ -264,6 +264,36 @@
         </div>
     </div>
 
+    <div ng-if="policyName === 'DOMaccesses'">
+        <div ng-repeat="(type, list) in rule.offendersObj.list.byType">
+            <h3>
+                <ng-pluralize count="list.length" when="{'0': 'No offender', 'one': '1 offender', 'other': '{} offenders'}"></ng-pluralize> from
+                <span ng-if="type === 'DOMqueriesById'">getElementById()</span>
+                <span ng-if="type === 'DOMqueriesByTagName'">getElementsByTagName()</span>
+                <span ng-if="type === 'DOMqueriesByClassName'">getElementsByClassName()</span>
+                <span ng-if="type === 'DOMqueriesByQuerySelectorAll'">querySelector() or querySelectorAll()</span>
+                <span ng-if="type === 'DOMinserts'">appendChild() or insertBefore()</span>
+                <span ng-if="type === 'DOMmutationsInserts'">added nodes</span>
+                <span ng-if="type === 'DOMmutationsRemoves'">removed nodes</span>
+                <span ng-if="type === 'DOMmutationsAttributes'">attribute changes</span>
+                <span ng-if="type === 'eventsBound'">addEventListener()</span>
+            </h3>
+            <div class="offendersTable">
+                <div ng-repeat="access in list">
+                    <div ng-if="type === 'DOMqueriesById'">#{{access.id}}</div>
+                    <div ng-if="type === 'DOMqueriesByTagName'">{{access.tag}} <b>on</b> <span title="{{access.node}}">{{access.node | lastDOMNode}}</span></div>
+                    <div ng-if="type === 'DOMqueriesByClassName'">.{{access.class}} <b>on</b> <span title="{{access.node}}">{{access.node | lastDOMNode}}</span></div>
+                    <div ng-if="type === 'DOMqueriesByQuerySelectorAll'">{{access.selector}} <b>on</b> <span title="{{access.node}}">{{access.node | lastDOMNode}}</span></div>
+                    <div ng-if="type === 'DOMinserts'"><span title="{{access.append}}">{{access.append | lastDOMNode}}</span> <b>added to</b> <span title="{{access.node}}">{{access.node | lastDOMNode}}</span></div>
+                    <div ng-if="type === 'DOMmutationsInserts'">{{access.node}} <b>added to</b> {{access.target}}</div>
+                    <div ng-if="type === 'DOMmutationsRemoves'">{{access.node}} <b>removed from</b> {{access.target}}</div>
+                    <div ng-if="type === 'DOMmutationsAttributes'">{{access.attribute}} <b>changed on</b> {{access.node}}</div>
+                    <div ng-if="type === 'eventsBound'">{{access.eventType}} <b>on</b> <span title="{{access.path}}">{{access.path | lastDOMNode}}</span></div>
+                </div>
+            </div>
+        </div>
+    </div>
+
     <div ng-if="policyName === 'imageOptimization'">
         <h3 ng-if="rule.value > 0">{{rule.value | bytes}} could be saved on <ng-pluralize count="rule.offendersObj.list.images.length" when="{'one': '1 image', 'other': '{} images'}"></ng-pluralize></h3>
         <div class="imageOffenders">

+ 8 - 31
lib/metadata/policies.js

@@ -46,37 +46,14 @@ var policies = {
         "isAbnormalThreshold": 50,
         "hasOffenders": true
     },
-    "DOMqueriesAvoidable": {
-        "tool": "phantomas",
-        "label": "Duplicated DOM queries",
-        "message": "<p>This is the number of queries that could be avoided by removing all duplicated queries.</p><p>Simply save the result of a query in a variable. Ok it is not always simple, especially with third-party scripts, but at least do it with your own code.</p>",
-        "isOkThreshold": 0,
-        "isBadThreshold": 300,
-        "isAbnormalThreshold": 600,
-        "hasOffenders": true,
-        "takeOffendersFrom": "DOMqueriesDuplicated",
-        "offendersTransformFn": function(offenders) {
-            return {
-                count: offenders.length,
-                list: offenders.map(function(offender) {
-                    var parts = /^[^"]* ?"(.*)" ?with ?(.*) ?\(in ?context ?(.*)\): ?(.*)\s?queries$/.exec(offender);
-
-                    if (!parts) {
-                        debug('DOMqueriesAvoidable offenders transform function error with "%s"', offender);
-                        return {
-                            parseError: offender
-                        };
-                    }
-
-                    return {
-                        query: parts[1],
-                        context: offendersHelpers.domPathToDomElementObj(parts[3]),
-                        fn: parts[2],
-                        count: parseInt(parts[4], 10)
-                    };
-                })
-            };
-        }
+    "DOMaccesses": {
+        "tool": "domAccessAgregator",
+        "label": "DOM access",
+        "message": "<p>This metric estimates the number of times the JavaScript reads, changes or binds the DOM.</p><p>The more your JavaScript code accesses the DOM, the slower the page will load.</p><p>Try, as much as possible, to have an HTML page fully generated by the server instead of making changes with JS.</p><p>Try to reduce the number of queries by refactoring your JavaScript code.</p><p>Binding too many events also has a cost.</p>",
+        "isOkThreshold": 500,
+        "isBadThreshold": 2500,
+        "isAbnormalThreshold": 5000,
+        "hasOffenders": true
     },
     "eventsScrollBound": {
         "tool": "phantomas",

+ 9 - 1
lib/metadata/scoreProfileGeneric.json

@@ -32,8 +32,15 @@
                 "DOMidDuplicated": 1
             }
         },
+        "javascriptComplexity": {
+            "label": "JS complexity",
+            "policies": {
+                "DOMaccesses": 4,
+                "eventsScrollBound": 1
+            }
+        },
         "badJavascript": {
-            "label": "Bad JavaScript",
+            "label": "Bad JS",
             "policies": {
                 "jsErrors": 1,
                 "documentWriteCalls": 2,
@@ -100,6 +107,7 @@
         "pageWeight": 3,
         "requests": 3,
         "domComplexity": 2,
+        "javascriptComplexity": 2,
         "badJavascript": 2,
         "jQuery": 1,
         "cssSyntaxError": 1,

+ 4 - 0
lib/runner.js

@@ -3,6 +3,7 @@ var debug                   = require('debug')('ylt:runner');
 
 var phantomasWrapper        = require('./tools/phantomas/phantomasWrapper');
 var colorDiff               = require('./tools/colorDiff');
+var domAccessAgregator      = require('./tools/domAccessAgregator');
 var mediaQueriesChecker     = require('./tools/mediaQueriesChecker');
 var isHttp2                 = require('./tools/isHttp2');
 var redownload              = require('./tools/redownload/redownload');
@@ -27,6 +28,9 @@ var Runner = function(params) {
     .then(function(phantomasResults) {
         data.toolsResults.phantomas = phantomasResults;
 
+        // Mix all DOM Access metrics together
+        data = domAccessAgregator.agregate(data);
+
         // Compare colors
         data = colorDiff.compareAllColors(data);
 

+ 53 - 0
lib/tools/domAccessAgregator.js

@@ -0,0 +1,53 @@
+var debug   = require('debug')('ylt:domAccessAgregator');
+
+var domAccessAgregator = function() {
+    'use strict';
+
+    this.agregate = function(data) {
+        debug('Starting to agregate DOM Accesses...');
+
+        let count = 0;
+        let offenders = {
+            byType: {}
+        };
+
+        const metricsToGather = [
+            'DOMqueriesById',
+            'DOMqueriesByTagName',
+            'DOMqueriesByClassName',
+            'DOMqueriesByQuerySelectorAll',
+            'DOMinserts',
+            'DOMmutationsInserts',
+            'DOMmutationsRemoves',
+            'DOMmutationsAttributes',
+            'eventsBound'
+        ];
+
+        metricsToGather.forEach(key => {
+            
+            if (data.toolsResults.phantomas.metrics[key]) {
+                count += data.toolsResults.phantomas.metrics[key];
+            }
+            
+            offenders.byType[key] = [];
+            if (data.toolsResults.phantomas.offenders[key]) {
+                offenders.byType[key] = data.toolsResults.phantomas.offenders[key];
+            }
+        });
+
+        data.toolsResults.domAccessAgregator = {
+            metrics: {
+                DOMaccesses: count
+            },
+            offenders: {
+                DOMaccesses: offenders
+            }
+        };
+
+        debug('Done agregating DOM Accesses.');
+
+        return data;
+    };
+};
+
+module.exports = new domAccessAgregator();