Page MenuHomePhabricator

Optimize how we load OOUI in MediaWiki
Closed, ResolvedPublic

Description

This is to investigate optimizing how we load OOUI in MediaWiki. I have some thoughts I have written down on another machine, that all seemed fairly easy to implement. They don't seem like large gains, but may be worth it.

  • CSS minifier:
    • Remove whitespace around CSS selectors: a + b, a > b, etc.; f.e. example #p-logo + div.portal h3
    • Remove whitespace inside parentheses: ( foo ); f.e. example :lang( ml )
    • Remove " from url() values and attribute selectors: url( "img.src" ), [type="radio"]
    • Remove leading 0 from fractional CSS values: 0.8em T111239
    • Ensure hex colors are output in shorthand notation: #fff (LESS compiler sets them back to 6-digit notation in contrast to f.e. Sass)

Related T178867: [EPIC] Unify and optimize SVG markup across Foundation products

  • ResourceLoader:
    • Do something magical to avoid double-loading 'oojs-ui.styles' and friends due to T87871.

Event Timeline

matmarex claimed this task.
matmarex raised the priority of this task from to Medium.
matmarex updated the task description. (Show Details)
matmarex added subscribers: matmarex, ori.

CSS minifier:

  • Remove whitespace around CSS selectors: a + b, a > b, etc.
  • Remove whitespace inside parentheses: ( foo )
  • Remove leading '0.' from CSS values

Icons and stuff:

  • Remove domain from URLs like //xx.wikipedia.org/w/load.php?...
  • Remove whitespace and ids from embedded SVG files

ResourceLoader:

  • Do something magical to avoid double-loading 'oojs-ui.styles' and friends due to T87871.

Adding to possible (micro) optimizations by CSS minifier:

  • Ensure hex colors are output in shorthand notation: #fff (Less compiler sets them back to 6-digit notation in contrast to f.e. Sass)

Another tiny gain would be to resolve T110051, which would shave off a few bytes for each icon.

Change 267794 had a related patch set uploaded (by Bartosz Dziewoński):
Work around T87871 to avoid double-loading OOjs UI PHP styles

https://gerrit.wikimedia.org/r/267794

Change 267794 merged by jenkins-bot:
Work around T87871 to avoid double-loading OOjs UI PHP styles

https://gerrit.wikimedia.org/r/267794

Jdforrester-WMF edited projects, added OOUI; removed Patch-For-Review.
Jdforrester-WMF set Security to None.

I wrote a quick one-off Ruby script to try to see how much applying these optimizations would help. It just does some regex replacements with utter disregard for CSS syntax. I eyeballed the diff, but didn't actually test if the "optimized" styles still work the same.


For the OOjs UI style modules: https://en.wikipedia.org/w/load.php?modules=oojs-ui.styles%7Coojs-ui.styles.icons%7Coojs-ui.styles.indicators%7Coojs-ui.styles.textures&only=styles

BytesBytes when gzipped
Currently14350715338
With additional optimizations13189214756

And for comparison, for other stuff – this URL is based on the modules that were loaded on a random en.wikipedia page I looked at: https://en.wikipedia.org/w/load.php?modules=ext.cite.styles%7Cext.gadget.DRN-wizard%2CReferenceTooltips%2CWatchlistBase%2CWatchlistGreenIndicators%2Ccharinsert%2Cfeatured-articles-links%2CrefToolbar%2Cswitcher%2Cteahouse%7Cext.tmh.thumbnail.styles%7Cext.uls.nojs%7Cext.visualEditor.desktopArticleTarget.noscript%7Cext.wikimediaBadges%7Cmediawiki.legacy.commonPrint%2Cshared%7Cmediawiki.raggett%2CsectionAnchor%7Cmediawiki.skinning.interface%7Cskins.vector.styles%7Cwikibase.client.init&only=styles

BytesBytes when gzipped
Currently5954912262
With additional optimizations5758612095

So I guess we can trim off around 0.5 K from the weight of the base OOjs UI styles. (Most of this seems to be from the embedded SVG optimization.) I'm not sure if it's worth the time it would take to implement the optimizations in a way that is less likely to break things when given arbitrary input.

[edited with corrected numbers and script because I forgot that newlines are whitespace]

Added: Remove " from url() values and attribute selectors: url( "img.src" ), [type="radio"]

Change 281055 had a related patch set uploaded (by Krinkle):
resourceloader: Remove wfExpandUrl() from ResourceLoaderImage

https://gerrit.wikimedia.org/r/281055

CSS property order would be another option. It brings, apart from better readability and code clarity, file size advantages in gzipping. Although the differences are close to zero:
themes/mediawiki/widgets.less compiled oojs-ui-widgets-mediawiki.css

BytesBytes when gzipped
Currently279823858
With unified CSS property order279823855
With unified CSS property order and 1 selector unified*279883850
  • Replaced 1 occurrence of background with background-color (as anywhere else), which was always the beginning property of the selectors.

Change 281055 merged by jenkins-bot:
resourceloader: Remove wfExpandUrl() from ResourceLoaderImage

https://gerrit.wikimedia.org/r/281055

And more CSS jungle camp survival games:
I've made a few manual comparison test to see what a few of my ideas could save us, without starting long refactoring yet. As foundation for my test I've been using compiled oojs-ui-mediawiki.css out of master at this point in time (grunt quick-build SVG-&LTR- only), starting at 110.731 bytes on disk:

  • Simplifying nesting (architectural, and Less induced), caring about simplification of selectors like:

.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {} or
.oo-ui-selectFileWidget-dropTarget .oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-label > .oo-ui-selectFileWidget-fileType {}
A very safe, foreseeably non-breaking approach resulted in

BytesBytes when gzipped
Currently11073111298
Simplified selectors107148
  • We're facing very verbose CSS class names in OOjs UI, could we do this less verbose before building the tower higher (some of those might not be possible at all any more; still out of curiosity, don't take some of those too seriously!):
BytesBytes when gzipped
Currently11073111298
Simplified selectors107148
all above & replaced oo-ui by ooui104982
all above & replaced Element by El100870
all above & replaced ooui-widget-enabled by ooui-is-on && ooui-widget-disabled by ooui-is-off99070
all above & replaced El- by BEM notation* as in __ for child elements9837911070

button is used 385 times, icon 229 times, label 205 times, I couldn't resist to replace button with btn which resulted in 97224 bytes. That's 87.82% of the original file size.

But after gzipping it doesn't gain us a lot, more like just a little – probably not worth any trouble if we're not taking into account easier readability for developers. ;)
Comparing from above
.ooui-btn--frameless.ooui-is-on.ooui-flagged--constructive.ooui-is-on.ooui-btn--pressed > .ooui-btn__btn > .ooui-label__label {}


(*) So .ooui-iconEl-icon becomes .ooui-icon__icon or .ooui-buttonEl-button becomes .ooui-button__button and
ooui-buttonEl-pressed becomes ooui-button--pressed for a modifier state of button.

Volker_E renamed this task from Optimize how we load OOjs UI in MediaWiki to Optimize how we load OOUI in MediaWiki.Jan 10 2018, 1:11 AM
Volker_E updated the task description. (Show Details)
Volker_E updated the task description. (Show Details)
Volker_E updated the task description. (Show Details)

As of writing, there are two remaining ideas in the task description:

  • Remove whitespace around CSS selectors: a + b, a > b, etc.; f.e. example #p-logo + div.portal h3.

This optimisation would turn + and > into unspaced + and >. This is effectively the same in terms of compression as it is still the same two logical tokens.

  • Ensure hex colors are output in shorthand notation: #fff (LESS compiler expands these to long-form).

This optimisation would be limited to color codes that are produced by LESS (assuming stylelint to use the short form where possible in source), but more importantly is limited to color codes that actually two identical digits in each of the three color channels. That is, while #AA00FF can be shortened to #A0F, a realistic and nuanced color (https://design.wikimedia.org/style-guide/visual-style_colors.html) such as #FEF6E7 can't be shortened. I expect this to have little to no impact on decompressed size, and possibly negative impact on compressed size due to less common shapes and patterns in color codes.

Both of these are very minor and the big gains laid out in the various comments on this task were achieved. The last few are non-trivial to do in the current CSSMin implementation, and without evidence of a gain that is worth the additional server-side complexity and time investment, I think we can consider this solved.

Separate tasks can be filed for these by interested parties, preferably with an estimate of what the benefit would to our key frontend metrics, such a page load time using transfer size as deterministic proxy for measuring the impact on that.

Krinkle assigned this task to matmarex.