In the new backend template the scripts are loaded at the end of the document, right before the body closing tag. While this was a good practice in the old days, it is not anymore. Read below why.
Having the scripts loaded at the end of the page makes both defer and async attributes useless. Using those attributes can improve the performance of the page.
Move the scripts back to head and use the defer attribute when required. This way the browser will be able to start downloading the scripts earlier without blocking the HTML parsing. And when the document is completely parsed the scripts are executed. In the current implementation, since the scripts are located at the bottom, browser will start downloading and executing the scripts when the document parsing is (almost) completed.
Any inline scripts that depend on the scripts loaded in head using the defer attribute will have to listen to the DOMContentLoaded event. But this should not be considered as an issue because it is also a requirement with the current implementation.
Labels |
Added:
?
|
Labels |
Added:
?
|
@dgrammatiko Can you please clarify? DOMContentLoaded is not triggered until all scripts are downloaded and executed. So inline scripts using DOMContentLoaded should be safe.
Regarding your other recommendations, I couldn't agree more.
DOMContentLoaded is not triggered until all scripts are downloaded and executed.
In theory you're right it shouldn't. rAF is also supposed to run at the start of the paint cycle (or whatever name has this js loop) but safari and edge are firing the event at the end of the cycle...
Although Evergreen browsers are way better than the ones in the browser war years there are still hiccups that we as devs need to test and find solutions to work around them. FWIW I haven't tested lately the consistency of the event as I moved away for using it as an initiator on my js (make everything async or totally sync it doesn't really matter as far as all the scripts are at the end of the body tag)
Status | New | ⇒ | Discussion |
@dgrammatiko Thanks for clarifying. I am using async/defer in really high traffic web sites and I have no reports for issues. It seems that the issues you are describing have been resolved already.
In any case, shipping a backend template which does not allow the developers to add scripts to the head is not acceptable. The scripts should go back to head and if we want to mimic the "scripts at the bottom" behaviour we can always use defer.
Hi, we have started adapting our code for J4 compatibility and we have run into the script execution race issue, we have a lot of scripts depending on jQuery which until now was synchronous loaded in the head. While we agree that it is not the best practice we don't see any reasonable decision to making this braking change in J4.
As kavadas points out, rendering scripts in the body is not anylonger considered a good practice and it should be done instead using async/defer. Furthermore, gaining discusable speed loading times at the expenses of consistency and stability on a backend area doesn't seems to help anybody.
@miljan-aleksic make sure that you’re using the cms’ API for your scripts!!! If you do then there is no breaking change. If you’re not then you have to respect the cms’ guidelines, in short “use the API”
@dgrammatiko could you link to the documentation for this please as I'm sure it will really help
@dgrammatiko There is breaking change, any inline scripts that depend on others will stop working. However, this is not the point of this suggestion. The point is that the defer and async attributes turn useless and that developers are not able to place scripts in the head.
There is breaking change, any inline scripts that depend on others will stop working
No there is not any B/C break as long as you're using the CMS' API If you have <script>
tags echoed in your output then yes there is a break! BUT you should respect the API of the system you are programming against...
@brianteeman sure, here you go: https://docs.joomla.org/Adding_JavaScript
@dgrammatiko @brianteeman, I know about the CMS API and even though Joomla it self is not using it all the times (maybe that changed now) I would agree on the consense of using it.
What I don't understand is the motivation behind the decision of forcing it use now which will definitely break the majority of extensions and most worrying make the developers spend a considerable time to first, understand what is going on, and then apply a major fix on their code.
The braking changes are already large, why introducing this one? There are literally no advantages except forcing everying to use the API.
will definitely brake the majority of extensions and most worrying make the developers spend a considerable time to first, understand what is going on, and then apply a major fix on their code
You mean wrap your inline script with a $document->addScriptDeclaration('Script goes here');
is too much work?
Anyways I'm in favour of respecting the hosting platform API...
@dgrammatiko the scripts most of the times are dynamic with php parts on it <?php echo ... ?>
. Remember they are part of the HTML layout, they could even rely on that specific layout execution logic to render the script.
Moving that syntax to a more abstracted and restricted scenario, yes, it is a lot of work.
@miljan-aleksic if your using PHP to create your javascript scripts you're doing it wrong. Both javascript and css are static assets!!! If you want to pass data from PHP to your javascript use either the html elements with some data attributes OR use the Joomla's API addScriptOption
. You're using very old programming patterns there...
I agree @dgrammatiko, it's a very old and bad pattern. But if Joomla 4 is going to force updating those, at least it should not do it by introducing new bad patterns (the topic of this issue). The issues with the current approach are significant:
As pointed out previously, J4 is introducing unnecessary braking changes plus a new bad pattern without any reasoning behind. Or at least any reasoning so far that anybody was able to explain.
No there is not any B/C break as long as you're using the CMS' API If you have
<script>
tags echoed in your output then yes there is a break! BUT you should respect the API of the system you are programming against...
The core installer is still using inline scripts:
https://github.com/joomla/joomla-cms/blob/staging/administrator/components/com_installer/views/install/tmpl/default.php#L84-L97
In real life scenarios there are cases where you do need inline scripts. Scripts that are required to run right after some markup is available.
We are trying to solve the problem the wrong way. If we want to improve performance we need to use defer/async instead of making them completely unusable.
Not allowing developers to place a script at the document head is not acceptable.
The last two are really important I think.
A suggestion...
The default script positioning can be at the bottom of the document.
But since we've been ordering <head>
includes in Joomla for over a decade, we could still do this for J4, albeit a bit different to allow for script positioning.
E.g. add an API parameter/flag to allow loading JS scripts inside the <head>
. A developer could choose which libs to move there (e.g. jQuery, if it's bundled with J4).
So this JHtml::_('jquery.framework');
could be changed to JHtml::_('jquery.framework', 'head');
for example and enforce the core JS lib to move to the <head>
.
Similarly, doing something like $document->addScript('some.js', 'head');
would allow devs to position their scripts at the <head>
.
The 'head' flag would obviously need to be ordered after any other parameter that can now go in the JHtml::_(), addScript() and addScriptDeclaration() methods.
As a sidenote, although loading scripts at the bottom would make a "traditional" page appear faster to the user, there may also be a flash of unstyled content, especially if the backend component UI and/or data are augmented with JS.
And in any case, allowing script positioning (as suggested above) is not a mega change to the J core that takes days to implement.
P.S. The Joomla core team should be friendly to developers and not alienate them to other platforms like cough WordPress cough which carries backwards compatibility as their flag. That is, of course, if you still care about Joomla not being a hobby toy for a select few people...
And in any case, allowing script positioning (as suggested above) is not a mega change to the J core that takes days to implement.
so why don't you propose a PR ?
Cause I value my time - in case there is unanimous negative response, that's a waste of time. Imagine if we did a pull request for every idea suggested...
filling an issue when having a proposal and don't send a PR is a waste of volunteer's times which probably are valuable like your
a) I didn't file the issue.
b) Your comment does not add anything productive to the discussion.
Please read the entire thread before commenting just for the sake of commenting...
FWIW as all my responses here sounded like I'm defending someone else's decision to move the scripts to the bottom of the page (without even an agreement from the PT, iirc), I need to clear things up a bit here:
<script type="module"
for them and a tag <script nomodule
for the legacy ES5 files (that enables both world to coexist happily).type=module/nomodule
trick (kinda industry standard these days) introduces some challenges, eg modules are by default deferred thus in order to don't break the order of the scripts execution everything needs to move at the bottom.What @fevangelou (additional parameter/flag for a location, where you want put your script) proposed would be really nice to have. Otherwise in cases, where you need to put script in the head, users will not use CMS API and this is what we don't want to.
Another very useful parameter/flag would be "weight", which would represent the number defining the order in which the JavaScript is added to the page (honestly I don't know, how scripts ordering is covered in current API).
Another very useful parameter/flag would be "weight", which would represent the number defining the order in which the JavaScript is added to the page (honestly I don't know, how scripts ordering is covered in current API).
Manual weighting should not be an API feature. If the web asset API would have been designed right instead of turning into the hot mess it is now, that API would have allowed proper declaration of dependencies between assets. Whereas what you have with the various scripts and stylesheets stuff in the Document today and over the last 10+ years is "first in first out" logic. But, seems getting the asset management API into a state that makes Joomla more than a "hobby toy for a select few people" isn't high on the priority list either.
And anyone who's seen the WP API will know that execution order (for hooks - similar to Joomla's plugin events) is misused all the time.
I consider the current state of "framework goes first, then everything else" is just fine. And for plugins that usually inject CSS/JS in pages where other extensions may also render, we can simply re-order them in the plugin manager and resolve any CSS/JS conflicts (unlike WP).
I also just stumbled across this issue (and yes, our extension in question does use "inline js-scripting" for certain functionality). Having to redesign all of these instances where we use this, is much more work than just
$document->addScriptDeclaration('Script goes here');
I agree with the overall concept, but I would actually prefer to have an intermediate solution like
$document->addScript('some.js', 'head');
so we can step by step reduce this "old behaviour", without having to "rush-in" in order to be ready for J4 when it launches...
unless I am very much mistaken scripts in the admin are not currently
loaded at the end of the document, right before the body closing tag.
and this issue can be closed.
Status | Discussion | ⇒ | Closed |
Closed_Date | 0000-00-00 00:00:00 | ⇒ | 2021-05-22 13:04:17 |
Closed_By | ⇒ | kavadas |
@brianteeman Not sure when this changed, but just checked and scripts are indeed loaded in the head right now:
https://github.com/joomla/joomla-cms/blob/4.0-dev/administrator/templates/atum/index.php#L94
So I am closing this. Thank you everyone.
There is one small detail here: inline scripts cannot be deferred, so even if script tags with
src
can be deferred, inline script tags will always execute as soon as they're parsed (blame IE for this). This can lead to race conditions as an inline script could have a dependency on a file that needs to be fetched/parsed/executed but the timing (even if theDOMContentLoaded
event is used in the inline script) could be seriously messed up.All and all:
addScriptOption()
onclick="someFunction"
but rather handle everything in the js file.