Browse Source

Revert custom dev and implement jQueryVersionsLoaded

Gaël Métais 10 years ago
parent
commit
61c09a5b49

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

@@ -128,7 +128,7 @@
                         (<ng-pluralize count="offender.requests" when="{'one':'1 request','other':'{} requests'}"></ng-pluralize>)
                     </div>
 
-                    <div ng-if="policyName === 'globalVariables' || policyName === 'jQueryDifferentVersions'">
+                    <div ng-if="policyName === 'globalVariables' || policyName === 'jQueryVersionsLoaded'">
                         {{offender}}
                     </div>
 

+ 2 - 2
lib/metadata/policies.js

@@ -273,7 +273,7 @@ var policies = {
         "message": "<p>Current latest versions of jQuery are 1.11 (with support for old IE versions) and 2.1 (without).</p><p>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.</p>",
         "hasOffenders": false,
         "scoreFn": function(data) {
-            var differentVersions = data.toolsResults.phantomas.metrics.jQueryDifferentVersions;
+            var differentVersions = data.toolsResults.phantomas.metrics.jQueryVersionsLoaded;
 
             if (differentVersions === 0 || differentVersions > 1 || !data.toolsResults.phantomas.metrics.jQueryVersion) {
                 // Not applicable
@@ -322,7 +322,7 @@ var policies = {
             }
         }
     },
-    "jQueryDifferentVersions": {
+    "jQueryVersionsLoaded": {
         "tool": "phantomas",
         "label": "Several versions loaded",
         "message": "<p>jQuery is a heavy library. You should <b>never</b> load jQuery more than once on the same page.</p>",

+ 1 - 1
lib/metadata/scoreProfileGeneric.json

@@ -32,7 +32,7 @@
             "label": "jQuery version",
             "policies": {
                 "jQueryVersion": 5,
-                "jQueryDifferentVersions": 0.1
+                "jQueryVersionsLoaded": 0.1
             }
         },
         "cssSyntaxError": {

+ 62 - 48
lib/tools/phantomas/custom_modules/modules/jQYLT/jQYLT.js

@@ -7,16 +7,17 @@
 /* global document: true, window: true */
 /* jshint -W030 */
 
-exports.version = '0.2.a';
+exports.version = '1.0.a';
 
 exports.module = function(phantomas) {
     'use strict';
 
     phantomas.setMetric('jQueryVersion', ''); // @desc version of jQuery framework (if loaded) [string]
+    phantomas.setMetric('jQueryVersionsLoaded'); // @desc number of loaded jQuery "instances" (even in the same version)
     phantomas.setMetric('jQueryOnDOMReadyFunctions'); // @desc number of functions bound to onDOMReady event
+    phantomas.setMetric('jQueryWindowOnLoadFunctions'); // @desc number of functions bound to windowOnLoad event
     phantomas.setMetric('jQuerySizzleCalls'); // @desc number of calls to Sizzle (including those that will be resolved using querySelectorAll)
-    phantomas.setMetric('jQuerySizzleCallsDuplicated'); // @desc number of calls on the same Sizzle request
-    phantomas.setMetric('jQueryDifferentVersions'); //@desc number of different jQuery versions loaded on the page (not counting iframes)
+    //phantomas.setMetric('jQueryEventTriggers'); // @desc number of jQuery event triggers
 
     var jQueryFunctions = [
         // DOM manipulations
@@ -110,30 +111,28 @@ exports.module = function(phantomas) {
         phantomas.evaluate(function(jQueryFunctions) {
             (function(phantomas) {
                 var jQuery;
+                var oldJQuery;
 
-                // TODO: create a helper - phantomas.spyGlobalVar() ?
-                window.__defineSetter__('jQuery', function(val) {
+                phantomas.spyGlobalVar('jQuery', function(jQuery) {
                     var version;
-                    var jQueryFn;
-                    var oldJQuery = jQuery;
 
-                    if (!val || !val.fn) {
+                    if (!jQuery || !jQuery.fn) {
                         phantomas.log('jQuery: unable to detect version!');
                         return;
                     }
 
-                    version = val.fn.jquery;
-                    jQuery = val;
-                    jQueryFn = val.fn;
-                    // Older jQuery (v?.?) compatibility
-                    if (!jQueryFn) {
-                        jQueryFn = jQuery;
+                    // Tag the current version of jQuery to avoid multiple reports of jQuery being loaded
+                    // when it's actually only restored via $.noConflict(true) - see comments in #435
+                    if (jQuery.__phantomas === true) {
+                        phantomas.log('jQuery: this instance has already been seen by phantomas');
+                        return;
                     }
+                    jQuery.__phantomas = true;
 
-                    phantomas.log('jQuery: loaded v' + version);
-                    phantomas.setMetric('jQueryVersion', version);
+                    // report the version of jQuery
+                    version = jQuery.fn.jquery;
                     phantomas.emit('jQueryLoaded', version);
-                    
+
                     phantomas.pushContext({
                         type: (oldJQuery) ? 'jQuery version change' : 'jQuery loaded',
                         callDetails: {
@@ -141,11 +140,13 @@ exports.module = function(phantomas) {
                         },
                         backtrace: phantomas.getBacktrace()
                     });
+                    oldJQuery = version;
 
                     // jQuery.ready.promise
                     // works for jQuery 1.8.0+ (released Aug 09 2012)
-                    phantomas.spy(val.ready, 'promise', function(func) {
+                    phantomas.spy(jQuery.ready, 'promise', function(func) {
                         phantomas.incrMetric('jQueryOnDOMReadyFunctions');
+                        phantomas.addOffender('jQueryOnDOMReadyFunctions', phantomas.getCaller(3));
 
                         phantomas.pushContext({
                             type: 'jQuery - onDOMReady',
@@ -160,9 +161,9 @@ exports.module = function(phantomas) {
 
                     // Sizzle calls - jQuery.find
                     // works for jQuery 1.3+ (released Jan 13 2009)
-                    phantomas.spy(val, 'find', function(selector, context) {
+                    phantomas.spy(jQuery, 'find', function(selector, context) {
                         phantomas.incrMetric('jQuerySizzleCalls');
-                        phantomas.emit('onSizzleCall', selector + ' (context: ' + (phantomas.getDOMPath(context) || 'unknown') + ')');
+                        phantomas.addOffender('jQuerySizzleCalls', '%s (in %s)', selector, (phantomas.getDOMPath(context) || 'unknown'));
                         
                         phantomas.enterContext({
                             type: 'jQuery - find',
@@ -183,12 +184,39 @@ exports.module = function(phantomas) {
                         phantomas.leaveContext(moreData);
                     }) || phantomas.log('jQuery: can not measure jQuerySizzleCalls (jQuery used on the page is too old)!');
 
+                    /*if (!jQuery.event) {
+                        phantomas.spy(jQuery.event, 'trigger', function(ev, data, elem) {
+                            var path = phantomas.getDOMPath(elem),
+                                type = ev.type || ev;
+
+                            phantomas.log('Event: triggered "%s" on "%s"', type, path);
+
+                            phantomas.incrMetric('jQueryEventTriggers');
+                            phantomas.addOffender('jQueryEventTriggers', '"%s" on "%s"', type, path);
+                        });
+                    }*/
+
+                    // jQuery events bound to window' onLoad event (#451)
+                    phantomas.spy(jQuery.fn, 'on', function(eventName, func) {
+                        if ((eventName === 'load') && (this[0] === window)) {
+                            phantomas.incrMetric('jQueryWindowOnLoadFunctions');
+                            phantomas.addOffender('jQueryWindowOnLoadFunctions', phantomas.getCaller(2));
+
+                            phantomas.pushContext({
+                                type: 'jQuery - windowOnLoad',
+                                callDetails: {
+                                    arguments: [func]
+                                },
+                                backtrace: phantomas.getBacktrace()
+                            });
+                        }
+                    });
 
                     // Add spys on many jQuery functions
                     jQueryFunctions.forEach(function(functionName) {
                         var capitalizedName = functionName.substring(0,1).toUpperCase() + functionName.substring(1);
                         
-                        phantomas.spy(jQueryFn, functionName, function(args) {
+                        phantomas.spy(jQuery.fn, functionName, function(args) {
 
                             // Clean args
                             args = [].slice.call(arguments);
@@ -263,42 +291,28 @@ exports.module = function(phantomas) {
                             phantomas.leaveContext();
                         }) || phantomas.log('jQuery: can not track jQuery - ' + capitalizedName + ' (this version of jQuery doesn\'t support it)');
                     });
-
-
-                });
-
-                window.__defineGetter__('jQuery', function() {
-                    return jQuery;
                 });
             })(window.__phantomas);
         }, jQueryFunctions);
     });
 
 
-    // count Sizzle calls to detect duplicated queries
-    var Collection = require('../../util/collection'),
-        sizzleCalls = new Collection(),
-        jQueryLoading = new Collection();
-
-    phantomas.on('onSizzleCall', function(request) {
-        sizzleCalls.push(request);
+    // store the last resource that was received
+    // try to report where given jQuery version was loaded from
+    phantomas.on('recv', function(entry) {
+        if (entry.isJS) {
+            lastUrl = entry.url;
+        }
     });
 
     phantomas.on('jQueryLoaded', function(version) {
-        jQueryLoading.push(version);
-    });
+        phantomas.log('jQuery: loaded v' + version);
+        phantomas.setMetric('jQueryVersion', version);
+
+        // report multiple jQuery "instances" (issue #435)
+        phantomas.incrMetric('jQueryVersionsLoaded');
+        phantomas.addOffender('jQueryVersionsLoaded', 'v%s', version);
 
-    phantomas.on('report', function() {
-        sizzleCalls.sort().forEach(function(id, cnt) {
-            if (cnt > 1) {
-                phantomas.incrMetric('jQuerySizzleCallsDuplicated');
-                phantomas.addOffender('jQuerySizzleCallsDuplicated', '%s: %d', id, cnt);
-            }
-        });
-
-        jQueryLoading.forEach(function(version) {
-            phantomas.incrMetric('jQueryDifferentVersions');
-            phantomas.addOffender('jQueryDifferentVersions', '%s', version);
-        });
+        phantomas.log('jQuery: v%s (probably loaded from <%s>)', version, lastUrl);
     });
 };