Comments (35)
AFAIK loading the scripts in the head asynchronously is much better than loading them in the footer synchronously. Async should allow more parallelism and doesn’t block the domready event.
I found an article that describes how to load scripts asynchronously and keep the desired execution order: https://www.html5rocks.com/en/tutorials/speed/script-loading/. IMO that would be the best option for our use-case.
from contao.
Maybe we should promote the use of Symfony Encore (and possibly add an option to include assets in the layout) instead of trying to improve on legacy implementations?
from contao.
Most blocking scripts are CSS files and not JS files according to my experience.
from contao.
👍 I agree that the synchronous (blocking) loading of JS in the <head>
is a big performance issue and that it should be solved out-of-the-box.
But I see several issues with it:
- Events that get registered too late, don’t get executed: If you call
addEventListener('contao-script-loaded')
after the script was loaded (which could easily happen for cached scripts) the event listener will never get executed. - Execution order: The execution order of dynamically added scripts is undefined, so it could happen that a script that requires jQuery gets executed before jQuery was loaded.
The first issue could be solved by using a custom function instead of an event I think. But the second one will be hard to solve... We probably don’t want to use a module loader and require every script to be a module.
from contao.
Most blocking scripts are CSS files and not JS files according to my experience.
Yeah CSS is blocking too, especially the stuff that is considered to be not critical. But the difference here is that I feel like webdesigners can handle CSS and they know where it is blocking and where it's not. They can also split files if needed, reorganize etc.
For JS, however, it needs a bit more knowledge and for many files you cannot really influence the way they're loaded. It's also not true that JS is not an issue. For the homepage of the official demo we already have 5 blocking JS scripts.
But I see several issues with it:
Of course, there are more issues with it. For example we would need multiple events to be fired when we combine multiple scripts into one 😄 That's why this is an RFC issue. I would like to find a solution and I'm sure there is one. If Contao cannot fix it out-of-the-box, to me that means 99% of all users won't be able to fix it either. That's why I think this is a really relevant topic.
Coming back to your remarks:
1 & 2 sort of go together, I agree. Is there maybe a library that does all of that and is reasonably small?
from contao.
Something like https://github.com/muicss/loadjs could maybe help?
from contao.
I totally don't understand your approach. The scripts are loaded in header because we do have inline code all over the document to render modules. If that would not be the case, we could simply place everything in the footer. That's why I stopped adding javascript to templates, or better said use $GLOBALS['TL_BODY']
for my script tags. But that will only work if everyone does, and that most likely won't happen soon. I don't see how an event would solve that problem?
from contao.
Obviously all inline code needs to be adjusted from using domready events to the new solution. Templates are not covered by the BC promise so there's no issue with that.
from contao.
So why would we need anything and an event in the header at all? Just add everything to body?
from contao.
Please elaborate on how your solution would work, please.
from contao.
$GLOBALS['TL_BODY'][] = '<script src="jquery"></script>';
You could also add async
and just keep it in the header. But again, it will break like all pages…
from contao.
And how do inline gallery scripts wait until this is loaded?
from contao.
well they don't. Same as with the event, they must be added after the initial scripts. Basically, do not inline. Use TL_BODY
for all scripts.
from contao.
An alternative would be to introduce a real module loader, not sure how that would work with such a setup though. But we sure should not invent our own loading system…
from contao.
Use TL_BODY for all scripts.
That doesn't work for combined scripts that's why I wanted to move all $GLOBALS['TL_JAVASCRIPT']
registered files into the body and invent an event/callback based system that makes sure dependencies are considered and loaded accordingly. In best case all a developer has to do is adjust their inline scripts from the "domready" or no event to some custom one.
from contao.
Why would that not work for combined scripts? Where's the difference between loading in header and footer if the order is correct?
from contao.
What about running the whole rendered html through a filter that moves all script tags to the bottom while keeping their order? I have such a solution working in Magento systems: https://github.com/bobbyshaw/magento-footer-js
from contao.
That would certainly work somehow but it's a slow and possibly unreliable solution (especially when you use regular expressions the way magento-footer-js does instead of DOM traversal) and I would like to see if there are other options first :) So that would be my last resort. But maybe still better than nothing at all, we'll see :)
from contao.
Doesn't Theme+ do this?
from contao.
There are quite a few extensions that apply stuff on the resulting HTML and I think we don't need this.
from contao.
None of them are perfect though imho.
from contao.
from contao.
Is that article from 2013 still valid?
BTW I liked the part where he writes:
I find this article depressing.
The situation is depressing and you should feel depressed. There’s no non-repetitive yet declarative way to download scripts quickly and asynchronously while controlling the execution order.
;)
Four years later "subresource" is still not supported by all browsers and so scripts may be hidden from preloaders. It's a trade-off.
Well, at the moment I manually extract scripts, process them via task runner and add one resulting script as async. I include basic critical CSS to style e. g. slides before the actual slider is loaded (which is also done async).
At least I can confirm that the above mentioned method to automatically move everything to the bottom is working on production sites and saves me some time as long as it's running smoothly.
from contao.
I stumble upon this
@Toflar The problem is that almost all of our scripts are loaded in
head
. This is especially complicated for dynamically loaded scripts (when you include a gallery, an accordion etc.) so it's very hard to fix for non-devs and I think it should work better out-of-the-box.
But colorbox, accordion ... are not loaded in the head? Can you explain what you mean?
from contao.
What's the status of this one?
from contao.
Maybe we should promote the use of Symfony Encore (and possibly add an option to include assets in the layout) instead of trying to improve on legacy implementations?
@aschempp We have an bundle doing exactly this: https://github.com/heimrichhannot/contao-encore-bundle . Maybe it can act as a first approach for having a contao core-supported way?
from contao.
Looks pretty interesting! Have you considered creating a pull request to have something merged to the core?
from contao.
Why building an own script loader?
HTML script attributes async
and defer
already offer non blocking script loading.
defer
also takes care of the execution order.
Only thing that has to be changed this way, is inline script.
This way inline scripts should contain only data variables but not the functions (like an accordeon initialization) that rely on loaded scripts. those functions should also be loaded deferred / non blocking.
an example
<script>
const myCustomAccordeon = {
'foo':'bar'
}
</script>
<script src="assets/jquery.js" defer></script>
<script src="assets/contaoCustomAccordeon.js" defer></script>
myCustomAccordeon.js can than just use the inline data.
from contao.
defer
also takes care of the execution order.
That is correct but defer
also delays script execution until the full HTML is downloaded and parsed.
Using async = false
as in #1489 keeps execution order while allowing the scripts to execute as soon as possible.
from contao.
That is correct but defer also delays script execution until the full HTML is downloaded and parsed.
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-defer
This Boolean attribute ( defer
) is set to indicate to a browser that the script is meant to be executed after the document has been parsed (when the DOM is ready), but before firing DOMContentLoaded.
true, it is delayed a little ... but in a way I usually want.
I want the DOM to be ready as soon as possible. And only after this I want JS to do its thing, like DOM manipulations.
In most cases I do not want JS to be executed just as soon as possible.
I think, sticking to default HTML script defer
would keeps things simpler, too.
Of course all this is just my opinion.
The above PR would be a major improvement anyway.
from contao.
In most cases I do not want JS to be executed just as soon as possible.
You want that with above the fold content, e.g. click event handlers for menu buttons, and sliders.
from contao.
You want that with above the fold content, e.g. click event handlers for menu buttons, and sliders.
Hm I thought you can not register a click handler on a dom element that is not ready, yet.
So would you not have to wait for the dom ready for doing this?
from contao.
No, you can initialize it directly after or even within the element.
from contao.
No, you can initialize it directly after or even within the element.
Ah, good to know this.
I would still prefer the default HTML defer approach.
While inline JS would not block the loading, it would still block the UI Threat (DOM construction ):
https://developers.google.com/speed/docs/insights/BlockingJS?hl=de#deferJS
But both (above PR and defer) would be much better than the current way.
from contao.
FYI, we have discussed this again at the developer's meeting in February, 2020, and we have agreed that it does not have a high priority at the moment. Also, before we can implement the feature, we have to get rid of the MooTools and jQuery dependencies in the front end.
from contao.
Related Issues (20)
- OPCache preloading issues HOT 1
- Problems with event reader in combination with newslist HOT 4
- Problem with empty newsletter recipients HOT 1
- Error when trying to add elements to the new element-group element (as non-admin) in news or events HOT 2
- `Input::get()` no longer works to retrieve passed parameters in the `{{file::*}}` insert tag HOT 1
- Empty session check misses data HOT 2
- Question regarding the new JavaScript pagination within content elements HOT 12
- Firefox does not display the line lines in lists, e.g. for members HOT 6
- Dropdown to select a stylesheet file for the syntax highlighting in a code content element HOT 2
- Wrong single quote encoding on email (') HOT 3
- Inserttag {{link_url::7}} gets the wrong output if the page (with id 7) has 'Require an item' enabled HOT 6
- Concept of AutoFallbackTransport flawed HOT 4
- Install tool: Page Not Found after update to 4.13.44 HOT 8
- Large number of old files in `assets/images/deferred/` HOT 3
- Orphaned temporary ini files in /tmp, when using workers via contao:cron HOT 23
- Spanish backend language files are not loaded HOT 5
- Feature request : exclude /api routes from being stored as referrer HOT 4
- Add raw numbers to Pagination template HOT 1
- Feature Request: Place multiple customized swiper elements on a page HOT 6
- 2FA - guest and logged in at same time
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from contao.