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