Ori.livneh has uploaded a new change for review.
https://gerrit.wikimedia.org/r/90742
Change subject: mediawiki.inspect: add CSS report
......................................................................
mediawiki.inspect: add CSS report
This patch extends mediawiki#inspect to add a notion of 'reports'. Instead of
there being one single view for all ResourceLoader module debug data, you can
now request that a specific report be run. Each report highlights a set of
metrics that are unified by some common theme.
The previous, unqualified report is now branded the 'size' report. In addition
to it, this patch also adds a CSS report, which prints the count of selectors
and the count of selectors that match against the current time
Change-Id: I0e7a47b5a93a66ecb103fe30a3de8a2ca8a4eb84
---
M resources/mediawiki/mediawiki.inspect.js
1 file changed, 128 insertions(+), 20 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core
refs/changes/42/90742/1
diff --git a/resources/mediawiki/mediawiki.inspect.js
b/resources/mediawiki/mediawiki.inspect.js
index 5cecc16..0a2a3d5 100644
--- a/resources/mediawiki/mediawiki.inspect.js
+++ b/resources/mediawiki/mediawiki.inspect.js
@@ -4,7 +4,23 @@
* @author Ori Livneh
* @since 1.22
*/
+/*global console*/
( function ( mw, $ ) {
+
+ /**
+ * Sort an array of objects by common attribute value.
+ *
+ * @param {Array} collection Collection to sort
+ * @param {string} prop Sort on the value of this property
+ * @param {boolean} [ascending=false] Sort in ascending order
+ * @return {Array} A sorted copy of the original array.
+ */
+ function sort( collection, prop, ascending ) {
+ var order = ascending ? 1 : -1;
+ return collection.slice().sort( function ( a, b ) {
+ return a[prop] > b[prop] ? order : a[prop] < b[prop] ?
-order : 0;
+ } );
+ }
/**
* @class mw.inspect
@@ -46,6 +62,45 @@
},
/**
+ * Parse CSS source into an array of rules.
+ *
+ * @param {string} css CSS source to parse
+ * @return {Array} Array of objects implementing the CSSRule
DOM interface
+ */
+ parseCSS: function ( css ) {
+ var doc = document.implementation.createHTMLDocument(
'' ),
+ style = doc.createElement( 'style' );
+ style.textContent = css;
+ doc.body.appendChild( style );
+ return $.makeArray( style.sheet.rules );
+ },
+
+ /**
+ * Given CSS source, count both the total number of selectors it
+ * contains and the number which match some element in the
current
+ * document.
+ *
+ * @param {string} css CSS source
+ * @return Selector counts
+ * @return {number} return.selectors Total number of selectors
+ * @return {number} return.matched Number of matched selectors
+ */
+ auditSelectors: function ( css ) {
+ var count = { total: 0, matched: 0 };
+
+ $.each( inspect.parseCSS( css ), function ( index, rule
) {
+ var selectors = rule.selectorText.split( ',' );
+ $.each( selectors, function ( index, selector )
{
+ count.total++;
+ if ( $( selector ).length !== 0 ) {
+ count.matched++;
+ }
+ } );
+ } );
+ return count;
+ },
+
+ /**
* Get a list of all loaded ResourceLoader modules.
*
* @return {Array} List of module names
@@ -57,13 +112,51 @@
},
/**
- * Print a breakdown of all loaded modules and their size in
kilobytes
- * to the debug console. Modules are ordered from largest to
smallest.
+ * Print tabular data to the console, using console.table,
console.log,
+ * or mw.log (in declining order of preference).
+ *
+ * @param {array} data Tabular data represented as an array of
objects
+ * with common properties.
*/
- inspectModules: function () {
- var console = window.console;
+ dumpTable: function ( data ) {
+ try {
+ console.table( data );
+ return;
+ } catch (e) {}
+ try {
+ console.log( JSON.stringify( data, null, 2 ) );
+ return;
+ } catch (e) {}
+ mw.log( data );
+ },
- $( function () {
+ /**
+ * Generate and print one more reports. When invoked with no
arguments,
+ * print all reports.
+ *
+ * @param {string} [reports] Space-separated report names to
run, or
+ * unset to print all available reports.
+ */
+ report: function ( reports ) {
+ reports = reports ?
+ reports.split( ' ' )
+ : $.map( inspect.reports, function ( v, k ) {
return k; } );
+
+ $.each( reports, function ( index, name ) {
+ inspect.dumpTable( inspect.reports[name]() );
+ } );
+ },
+
+ /**
+ * @class mw.inspect.reports
+ * @singleton
+ */
+ reports: {
+ /**
+ * Generate a breakdown of all loaded modules and their
size in
+ * kilobytes. Modules are ordered from largest to
smallest.
+ */
+ size: function () {
// Map each module to a descriptor object.
var modules = $.map(
inspect.getLoadedModules(), function ( module ) {
return {
@@ -73,9 +166,7 @@
} );
// Sort module descriptors by size, largest
first.
- modules.sort( function ( a, b ) {
- return b.size - a.size;
- } );
+ modules = sort( modules, 'size' );
// Convert size to human-readable string.
$.each( modules, function ( i, module ) {
@@ -83,23 +174,40 @@
( module.size / 1024 ).toFixed(
2 ) + ' KB' :
( module.size !== null ?
module.size + ' B' : null );
} );
+ return modules;
+ },
- if ( console ) {
- if ( console.table ) {
- console.table( modules );
- } else {
- $.each( modules, function ( i,
module ) {
- console.log( [
module.name, module.size ].join( '\t' ) );
- } );
- }
- }
- } );
+ /**
+ * For each module with styles, count the number of
selectors, and
+ * count how many match against some element currently
in the DOM.
+ */
+ css: function () {
+ var modules = [];
+
+ $.each( inspect.getLoadedModules(), function (
index, name ) {
+ var css, stats, module =
mw.loader.moduleRegistry[name];
+
+ try {
+ css = module.style.css.join();
+ } catch (e) { return; } // skip
+
+ stats = inspect.auditSelectors( css );
+ modules.push( {
+ module: name,
+ allSelectors: stats.total,
+ matchedSelectors: stats.matched,
+ percentMatched: stats.total !==
0 ?
+ ( stats.matched /
stats.total * 100 ).toFixed( 2 ) + '%'
+ : null
+ } );
+ } );
+ return sort( modules, 'allSelectors' );
+ },
}
};
if ( mw.config.get( 'debug' ) ) {
- inspect.getModuleSize = function () { return null; };
- mw.log( 'mw.inspect: Module sizes are not available in debug
mode.' );
+ mw.log( 'mw.inspect: reports are not available in debug mode.'
);
}
mw.inspect = inspect;
--
To view, visit https://gerrit.wikimedia.org/r/90742
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I0e7a47b5a93a66ecb103fe30a3de8a2ca8a4eb84
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Ori.livneh <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits