Krinkle has uploaded a new change for review. ( 
https://gerrit.wikimedia.org/r/339095 )

Change subject: [WIP] Initial POC for detecting unused images in style rules
......................................................................

[WIP] Initial POC for detecting unused images in style rules

Bug: T121144
Change-Id: Ibe91fbfb581f836a793a7bcd297415959c73f233
---
M modules/collectors/ext.PerformanceInspector.modulescss.js
M modules/css/ext.PerformanceInspector.css
M modules/templates/modulescss.mustache
3 files changed, 139 insertions(+), 23 deletions(-)


  git pull 
ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/PerformanceInspector 
refs/changes/95/339095/1

diff --git a/modules/collectors/ext.PerformanceInspector.modulescss.js 
b/modules/collectors/ext.PerformanceInspector.modulescss.js
index 253578b..470747e 100644
--- a/modules/collectors/ext.PerformanceInspector.modulescss.js
+++ b/modules/collectors/ext.PerformanceInspector.modulescss.js
@@ -4,50 +4,105 @@
 
                function toView( name, stats, index ) {
                        return {
-                                       name: name,
-                                       selectors: mw.msg( 
'performanceinspector-modules-css-used-selectors-values', stats.total !== 0 ?
-                                                       ( stats.matched / 
stats.total * 100 ).toFixed( 2 ) + '%' : null, stats.matched, stats.total ),
-                                       unmatchedSelectors: stats.unmatched,
-                                       index: index
-                               };
+                               name: name,
+                               selectors: mw.msg( 
'performanceinspector-modules-css-used-selectors-values', stats.total !== 0 ?
+                                               ( stats.matched / stats.total * 
100 ).toFixed( 2 ) + '%' : null, stats.matched, stats.total ),
+                               unmatchedSelectors: stats.unmatched,
+                               index: index
+                       };
                }
-               function auditSelectors( css ) {
-                       var selectors = { total: 0, matched: 0, unmatched: [] },
-                                       style = document.createElement( 'style' 
);
+
+               function toImageView( name, stats, index ) {
+                       return {
+                               name: name,
+                               used: mw.msg( 
'performanceinspector-modules-css-used-selectors-values', stats.total !== 0 ?
+                                               ( stats.used / stats.total * 
100 ).toFixed( 2 ) + '%' : '100%', stats.used, stats.total ),
+                               unusedImages: stats.unused,
+                               index: index
+                       };
+               }
+
+               function dashCase( str ) {
+                       return str.replace( /([A-Z])/g, function ( all, letter 
) {
+                               return '-' + letter.toLowerCase();
+                       } );
+               }
+
+               function analyze( css ) {
+                       var result = {
+                                       rules: {
+                                               total: 0, matched: 0, 
unmatched: []
+                                       },
+                                       images: {
+                                               total: 0, used: 0, unused: []
+                                       }
+                               },
+                               style = document.createElement( 'style' ),
+                               urlRegex = 
/url\(\s*[\'"]?([^\)\'"]*?)[\'"]?\s*\)/g;
                        style.textContent = css;
                        document.body.appendChild( style );
                        $.each( style.sheet.cssRules, function ( index, rule ) {
+                               var prop, urlMatches, images = [];
+                               function mapUrlMatch( url ) {
+                                       return { prop: dashCase( prop ), url: 
url };
+                               }
                                // Only pickup CSSStyleRule
-                               if ( rule.selectorText !== undefined ) {
-                                       selectors.total++;
+                               if ( rule.style && rule.selectorText ) {
+                                       result.rules.total++;
+                                       for ( prop in rule.style ) {
+                                               if ( prop === 'cssText' ) {
+                                                       continue;
+                                               }
+                                               // Ignore default/empty values 
and numerical values
+                                               urlMatches = rule.style[ prop ] 
&&
+                                                       typeof rule.style[ prop 
] === 'string' &&
+                                                       rule.style[ prop 
].match( urlRegex );
+                                               if ( urlMatches ) {
+                                                       images.push.apply( 
images, $.map( urlMatches, mapUrlMatch ) );
+                                               }
+                                       }
+                                       result.images.total += images.length;
+
                                        // document.querySelector() on prefixed 
pseudo-elements can throw exceptions
                                        // in Firefox and Safari. Ignore these 
exceptions.
                                        // 
https://bugs.webkit.org/show_bug.cgi?id=149160
                                        // 
https://bugzilla.mozilla.org/show_bug.cgi?id=1204880
                                        try {
                                                if ( document.querySelector( 
rule.selectorText ) !== null ) {
-                                                       selectors.matched++;
+                                                       result.rules.matched++;
+                                                       result.images.used += 
images.length;
                                                } else {
-                                                       
selectors.unmatched.push( rule.selectorText );
+                                                       
result.rules.unmatched.push( rule.selectorText );
+                                                       $.each( images, 
function ( i, image ) {
+                                                               
result.images.unused.push( {
+                                                                       
selector: rule.selectorText,
+                                                                       prop: 
image.prop,
+                                                                       url: 
image.url
+                                                               } );
+                                                       } );
                                                }
                                        } catch ( e ) {}
                                }
                        } );
                        document.body.removeChild( style );
-                       return selectors;
+                       return result;
+               }
+
+               function auditSelectors( css ) {
+                       return analyze( css ).rules;
                }
 
                function cssResourceLoader() {
                        var modules = [];
                        $.each( data.inspect.modules, function ( index, mod ) {
-                                       var css, stats, module = 
mw.loader.moduleRegistry[ mod.name ];
-                                       try {
-                                               css = module.style.css.join();
-                                       } catch ( e ) { return; } // skip
+                               var css, stats, module = 
mw.loader.moduleRegistry[ mod.name ];
+                               try {
+                                       css = module.style.css.join();
+                               } catch ( e ) { return; } // skip
 
-                                       stats = auditSelectors( css );
-                                       modules.push( toView( mod.name, stats, 
index ) );
-                               } );
+                               stats = auditSelectors( css );
+                               modules.push( toView( mod.name, stats, index ) 
);
+                       } );
                        return modules;
                }
 
@@ -76,6 +131,23 @@
 
                        return cssFromFiles;
                }
+
+               function cssImages() {
+                       var modules = [];
+                       $.each( data.inspect.modules, function ( index, mod ) {
+                               var css, stats, module = 
mw.loader.moduleRegistry[ mod.name ];
+                               try {
+                                       css = module.style.css.join();
+                               } catch ( e ) { return; } // skip
+
+                               stats = analyze( css ).images;
+                               if ( stats.total > 0 ) {
+                                       modules.push( toImageView( mod.name, 
stats, index ) );
+                               }
+                       } );
+                       return modules;
+               }
+
                modulesTemplate = mw.template.get( 
'ext.PerformanceInspector.analyze', 'modulescss.mustache' );
 
                return {
@@ -87,7 +159,8 @@
                                template: modulesTemplate,
                                data: {
                                        cssResourceLoader: cssResourceLoader(),
-                                       cssFromFiles: cssFromURL()
+                                       cssFromFiles: cssFromURL(),
+                                       cssImages: cssImages()
                                }
                        }
                };
diff --git a/modules/css/ext.PerformanceInspector.css 
b/modules/css/ext.PerformanceInspector.css
index 71279fb..6685bfd 100644
--- a/modules/css/ext.PerformanceInspector.css
+++ b/modules/css/ext.PerformanceInspector.css
@@ -1,7 +1,6 @@
 .barchart {
     color: white;
     font-size: 14px;
-    -
 }
 .barchart .row {
     position: relative;
@@ -45,3 +44,12 @@
     max-width: 200px;
     word-break: break-all;
 }
+
+.mw-pi-url-crop {
+    display: inline-block;
+    max-width: 200px;
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    vertical-align: text-bottom;
+}
diff --git a/modules/templates/modulescss.mustache 
b/modules/templates/modulescss.mustache
index 4ae6cb1..a5f3ce8 100644
--- a/modules/templates/modulescss.mustache
+++ b/modules/templates/modulescss.mustache
@@ -69,3 +69,38 @@
        </tr>
        {{/cssFromFiles}}
 </table>
+
+<p>{{#msg}}performanceinspector-modules-css-images-description{{/msg}}</p>
+
+<table class="wikitable full">
+       <thead>
+               <tr>
+                       <th>
+                               
{{#msg}}performanceinspector-modules-css-column-module{{/msg}}
+                       </th>
+                       <th>
+                               
{{#msg}}performanceinspector-modules-css-column-used-images{{/msg}}
+                       </th>
+                       <th></th>
+               </tr>
+       </thead>
+       {{#cssImages}}
+       <tr>
+               <td class="url">
+                       {{name}}
+               </td>
+               <td>
+                       {{used}}
+               </td>
+               <td><button href="#" onClick="$( '#mw-pi-unused-images-' + 
{{index}} 
).toggle();">{{#msg}}performanceinspector-modules-css-show-details{{/msg}}</button>
+               </td>
+       </tr>
+       <tr id="mw-pi-unused-images-{{index}}" class="hidden">
+               <td colspan="5">
+                       {{#unusedImages}}
+                               <pre>{{selector}} { {{prop}}: <span 
class="mw-pi-url-crop">{{url}}</span></pre>
+                       {{/unusedImages}}
+               </td>
+       </tr>
+       {{/cssImages}}
+</table>

-- 
To view, visit https://gerrit.wikimedia.org/r/339095
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ibe91fbfb581f836a793a7bcd297415959c73f233
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/PerformanceInspector
Gerrit-Branch: master
Gerrit-Owner: Krinkle <krinklem...@gmail.com>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to