There are currently no guidelines on MediaWiki.org around how to load JS on the page.
I had a useful conversation with Timo today but would love to see this documented.
[11:28 AM] @Krinkle wrote:
Jdlrobson: It's generally either addModules on page load, or mw.loader.using() to lazy load upon user interaction. There's no other strategies afaik needed currently.
these two are documeted at https://www.mediawiki.org/wiki/ResourceLoader/Developing_with_ResourceLoader#Loading_modules
How to detect MobileFrontend is imho out of scope for RL. That's part of core conventions for ExtensionRegistry (in PHP) and based on what promises/public stable interfaces MF wants to expose/maintain client-side.
Any kind of conditional is fine imho.
[11:33 AM] @Krinkle wrote:
Right, that's less about how to implement a certain direction, but what direction to pick overall.
When something is needed on page load, it's addModules(). There's only one way to do that really, and that's documented. To lazy-load, you use mw.loader.using().
I don't see how it ties in with desktop/mobile target stuff. Why are we looking to change how existing code is loaded as part of that?
I agree we can use better docs around that, and will try to find it and/or write it. In general, later is better. And loading Vue.js on page load is imho a no-go no matter what.
requestIdleCallback was a one-off experiment for Popups and shuld be removed, not recommended for any circumstance.
(There's a task about that)
[11:55 AM] @Krinkle wrote:
Yeah, I'll see what I can do, but ultimately it comes down to budgetting and performance review per-feature. I don't think we can describe clearly when it is fine to load on the page and when it isn't. In general, nothing should load on the page, unless it has to do something on that page and that it has to do it immediately when the page loads. That in itself is generally already something that should be avoided as it will not arrive for all users (on slow devices they can comfortably read a paragraph and move on to another page before it arrives), so whenever possible first try pure CSS-only etc. But if it has to be client-side, and has to be on page load, and doesn't result in bad UX, then loading the minimum needed on the pages right away is probably fine, but that still depends on where we are in our budget and how computationally expensive the code is, and how large it is.
(Feel free to ignore this, I'm just drafting out loud)
Things that fall under this is: "init" code that adds event handlers to the Edit button click event, to the Search input focus event. Code that makes the reserved space for sortable icons in tables filled in with an actual button and makes those buttons work. (Slight contradiction, why is it okay to not lazy-load jquery.tablesorter? This is a trade-off in size of the code, overhead of having yet another init module, and latency when the user clicks it given there is nothing to hide that latency behind, it is just sorting. Whereas search and edit do more things behind the scenes that already involve the network, so loading the code async is fine there. This is why the "init" code of VE isn't just a click handler, it also includes very minimal CSS to make that click result in the page looking like it is "loading".
also, I have a proposal to kill all "init" modules in favour of a standard attribute that will do this for you. E.g. you have an attribute in the HTML, when that is clicked, it will add a class that allows your CSS to make it look like however it should look when it is loading, and then when the code arrives it will call a certain method. The logic for this would be generic and only written once. See more at https://phabricator.wikimedia.org/T183720
This would mean we can remove almost all JS from page load, except for stuff that does non-user facing things (like navtiming metrics), and init code for which the loading state is very complex (more than a simple class name switch can do).
also, this will encourage use of "delegate event handlers". right now, a very common pattern (albeit a bad one) is to load JS that waits for dom-ready and then selects all of something and calls on(). This is problematic for many reasons. 1) It's poor UX because it means that when the JS has arrived, and most of the page is there and painted, the JS just sits there idle and the user can't click stuff. It waits for the whole page to be there below the fold, until 2) it selects all the relevent elements which is expensive and slow, and 3) allocates many event handlers, again expensive. Whereas if we use a delegate handler like $(document.body).on('click', '.my-stuff') you can run that right away without waiting for dom-ready, and allocates only 1 event handler, and any elements that exist now or in the future that match will just work, because we check it at click-time, instead of at select-time.
If I recall correctly, we adopted this in a few places last year around the Cite instrumentation that reading was involved with.