Page MenuHomePhabricator

ResourceLoader / FouC: How to have JavaScript be executed on actual DOM ready?
Closed, DeclinedPublic

Description

When using jQuery UI Tabs some DOM elements (the unselected tab contents) get hidden by JavaScript. To avoid a "flash of unstyled content" this needs to be done as soon as the DOM is ready and before the browser actually displays the page. A normal HEAD script would just use

$(function(){...});

In REL1_23 having such a module's position set to 'top' worked. However in REL1_27 this doesn't work anymore, as scripts (even position 'top') are being loaded async. Therefore the page is shown to the user before all javascript sources are ready.

Is there a way to have JavaScript being loaded synchronously from the HEAD? Are there other ways to aviod a FouC in such a scenario?

Event Timeline

Per T107399, JavaScript was made to load asynchronously for an improved page load performance and overall user experience. Read more about it at https://developers.google.com/web/fundamentals/performance/critical-rendering-path/

In some situations this change introduced a FOUC. These were often caused by pre-existing performance problems. These are typically fixed by using CSS instead of JavaScript where possible. In other situations we moved complex rendering logic to the server-side, leaving JavaScript for interaction and secondary renders only – not the initial render.

I'd recommend the same approach for you. Rendering a page should not require client-side JavaScript. Ensure the server responds with the intended content and HTML structure. Stylesheets are still applied synchronously.

jQuery UI is especially problematic because it is quite a large library. It's optimised for use cases where you an interactive state (e.g. inside a modal dialog that is created as a result of some interaction). Because this makes it unsuitable for theming regular page content and forms, Wikimedia choose to adopt a different library (OOjs UI) for these cases and has removed use jQuery UI for other use cases as well (to provide a consistent user interface).

I would strongly advise against loading all of jQuery core, jQuery UI, their stylesheets, and your own application code synchronously. ResourceLoader no longer supports this.


If the JavaScript is not dependent on other libraries, you can still output small inline scripts via OutputPage::addInlineScript(). We do this, for example, to swap client-nojs with client-js before the first page render.

Thank you for clarification. If you wish, we can close this task.

Closing per last comment.