Page MenuHomePhabricator

Omit `<link rel="mw-deduplicated-inline-style">` from page view HTML
Open, Needs TriagePublic

Description

From T168333: CSS is duplicated on each template usage.

For the deduplicated styles, do we really need the <link> tags? Couldn't we completely remove the tag?

It doesn’t do anything bad to keep them, the only thing that might be interested in removing them is probably mobile version (since every byte seems to count there).

I don't see any particular reason to do this specifically in MobileFrontend. More generally, this is a matter of distinguishing between canonical HTML and presentation mode.

When editing in VisualEditor, or when rendering partials of pages on mobile web or mobile apps, it is important that the client can keep the stylesheet around, even if it removed the section it was a part of, as long as there is another section that had a reference to it. Likewise, when a section if viewed without any references to that template, it can be omitted.

However, for page views as output by a skin (Vector, Minerva, MobileFrontend), they are indeed not needed. It seems like this falls in the same category as a lot of Parsoid attributes not needed that we strip on rendering. Except this is the first (obvious) instance of such concept for the PHP parser output.

Event Timeline

Krinkle created this task.Jul 23 2018, 3:11 PM
Restricted Application added a subscriber: Aklapper. · View Herald TranscriptJul 23 2018, 3:11 PM
Anomie added a subscriber: Anomie.Jul 23 2018, 3:14 PM

I note TemplateStyles has no control over this, the code doing it lives in core.

Od1n removed a subscriber: Od1n.Jul 23 2018, 3:49 PM
Tgr added a subscriber: Tgr.Jul 23 2018, 6:54 PM

Should we create a hook for post-processing rendered HTML, called with different arguments in canonical and presentation mode? (Although not sure what is canonical in this case? action=render?)

Can't the <style> tags be moved to some centralized place altogether? Their scattered presence in HTML causes problems like mentioned here, in T186965 and in T200704 (I opened the last task just recently).

Tgr added a comment.Jul 30 2018, 9:32 PM

They could but it would probably negatively impact time to first paint.

Pikne added a subscriber: Pikne.Aug 15 2018, 11:42 AM

I came across another use case where omitting <link/> could be desirable. English Wikipedia has style .navbox+.navbox{margin-top:-1px} that merges borders for adjacent boxes {{navbox}}{{navbox}}. Using <templatestyles/> at the top of this template, before <div class="navbox">...</div> that the content is enclosed in, however ensures that given style is not applied since <link/> sits between the boxes.

Can't the <style> tags be moved to some centralized place altogether?

That was considered during discussion of T155813: Decide on storage and delivery method for TemplateStyles CSS, but was rejected for client-side performance reasons: the one centralized place would have to be before all the content, which would mean that clients would have to download all the styles before getting to the actual content.

I came across another use case where omitting <link/> could be desirable. English Wikipedia has style .navbox+.navbox{margin-top:-1px} that merges borders for adjacent boxes {{navbox}}{{navbox}}. Using <templatestyles/> at the top of this template, before <div class="navbox">...</div> that the content is enclosed in, however ensures that given style is not applied since <link/> sits between the boxes.

You could move the <templatestyles> tag to just inside the <div class="navbox"> (a noticeable FOUC seems unlikely to me since it'd just be an unstyled div, although I'm no expert on FOUC), or you could change the style rule to .navbox + link + .navbox.

[...] or you could change the style rule to .navbox + link + .navbox.

This might be a use case for the general sibling combinator, which would look like .navbox ~ .navbox.

stjn added a comment.Aug 15 2018, 3:46 PM

You could move the <templatestyles> tag to just inside the <div class="navbox"> (a noticeable FOUC seems unlikely to me since it'd just be an unstyled div, although I'm no expert on FOUC), or you could change the style rule to .navbox + link + .navbox.

Just in this case it is also preferred because without this navbox will be removed from mobile view, but its styles will still be loaded. (But in other ones, it is a sound argument for removing these tags.)

Restricted Application added a subscriber: Masumrezarock100. · View Herald TranscriptDec 5 2019, 12:15 PM
Krinkle moved this task from Up next to External on the TemplateStyles board.
Krinkle moved this task from Limbo to Perf recommendation on the Performance-Team (Radar) board.
Od1n added a comment.EditedDec 6 2019, 6:46 PM

We had a related issue on frwiki (see talk, involving template Liste éléments):

A parent template, containing a child template, was expecting this child template to return no content, but the child template was still returning the style/link tag, thus interpreted as non-empty content.
Basically we were encountering this: {{#if: {{child}} | gotten result | expected result }}

Ideally the style/link tag shouldn't be considered as content, but I doubt this is doable (or even advisable, actually).

Verdy_p added a subscriber: Verdy_p.EditedMay 5 2020, 6:05 PM

Ideally, this would mean that Mediawiki would not generate only one content, but two in parallel: the content to transclude (and that can be tested with #if:) and separately the metadata which will be inserted elsewhere.

And may be we could have a #ifmeta: to test the expanded value of this metadata).

Then the metadata ill be used to generate the page header:; it would contain "links", or other special accessibility elements.

It would also resolve the current expansion cost caused by the inline insertion of the "link" tag everywhere the template is used, even if only one will be finally kept dring the deduplication: there's been a case where the current expansion caused a page to explode in size: the whole size of the stylesheet was multiplied by the number of occurence, later it was replaced by the size of the minified "link" element containing a unique id, but in fact this minitag is still too large

(e.g. on a page where the stylesheet was included more than a few thousands times, via more than a few thousands inclusion of a template using these templated stylesheets; to solve it, I had to modify the templates to specifiy if we should include or not the stylesheet -- the inclusion being the default, but being suppressable contextually by the caller)

Basically this means that instead of returning a single string object, many API would be allowed to return an array, whose index 0 would be the string content and other keys would be used for the collection of metadata; that array could have a get-accessor that would return or set the string content of key 0.

Many templates, or parserfunctions could then generate their own metadata, using specific keys. All their input parameters would not be only strings, but such objects, and these parserfuntions could recombine the metadata of parameters or create new metadata in the return object.

Finally, Medawiki would use only some keys of the object: the default key 0 for the content, other keys for specific metadata that can be placed in the organized output (e.g in the HTML "head"), or at top of page or footnotes, or additional tools generated in the side bar; other keys would be dropped. It would facilitate the integration of sitewide features, personal features, and the general organization of the page (which could then be templated as well, with parts cachable or not cachable, or using separate caches where appropriate for privacy).

Ideally the style/link tag shouldn't be considered as content, but I doubt this is doable (or even advisable, actually).

One way of doing this, if only one content is returned, would be to encapsulate it in an ignorable tag with the unique id (like "nowiki" tags) whose presence can be easily filtered out by "#if:"; its actual hidden value would be in some external collection keyed by the unique id.

The ignorable tag inside the string countent should be clearly distinctable from other content (it can be safely delimited by using characters that are forbidden in HTML, such as ASCII C0 controls (STX/ETX, DEL) because they are very compact.

Some parserfuntions (notably those extracting substrings or computing the "visible" length) need revision to avoid breaking these hidden contents: I would just return the string content, terminated by a DEL control before the meta data which can have its own local encoding for a collection of keyed items.

The collection would include for each keyed item a "scoped region", i.e. the index position in the initial part of the string and its length for which it applies: taking a "substring" from the text content would also append the applicable keyed metadata that have a matching region. Regions would need special length values for 0-length regions, to mean "before position n" or "after position n", or "include this keyed meta if the meta encoded at position n is included" (so groups of metadata could be managed for successive ranges of content fragments could be managed)

The alternative is just to allow functions to return a DOM-like tree instead of just a single string, recursively mixing parts that are basic string contents, and parts that are keyed arrays (my opinion is that it would be more efficient than having to reparse a string format with a complex structure). In PHP, Lua and Javascript, this is very trivial (and such format is trivially serializable and cachable in JSON format) !