kubetail-org / loadjs

A tiny async loader / dependency manager for modern browsers (899 bytes)
MIT License
2.57k stars 149 forks source link

Usage question #79

Closed batata004 closed 5 years ago

batata004 commented 5 years ago

Hi,

A third party plugin inside my site needs to know if certain CSS file was already loaded. On my website I use this code below to load CSS styles:

loadjs(
    ["https://cdn.jsdelivr.net/npm/semantic-ui@2.3.1/dist/semantic.min.css","css!//fonts.googleapis.com/css?family=Montserrat|Raleway:400,700|Abel|Libre+Baskerville:400i","estilos.css"],
    {
        success:function(){

        },
        async:true
    }

);

I know I can use the success callback to make sure the CSS were loaded HOWEVER this third party plugin has no access to my code and I dont it to have any access. So using the success callback is out of the way.

Then, after searching A LOT, I discovered that the code below would tell me if the CSS was already loaded:

$("link[href*='semantic.min.css']").length == 0 ? alert('not loaded'); : alert('loaded');

BUT I am not sure how LOADJS library works! I would like to know if LOADJS library would only place the LINK element at the DOM after the script is downloaded OR if it places the LINK element at the DOM before downloading it.

If it's the first scenario I should be fine, but if it's the second I should keep searching to find a better way!

Thanks!

amorey commented 5 years ago

CSS downloads are triggered by adding a <link> tag to the DOM which means that the tag will be present before the file is fully downloaded and loaded. Is there a way you could set a global flag from the success function?

batata004 commented 5 years ago

@amorey The global solution you told would be the best approach but we dont want to add support for third party, I mean, we dont want to change anything on our end/code simply for third party usage.

I did some tests here and I think that the link is only being available at the DOM when the CSS is already loaded. I made a test loading the page 100 times with different connection speeds and in all cases when the link was noticed at the DOM by the JQUERY selector, it looks like everything was fine!

amorey commented 5 years ago

Are you running the test before/after the DOMContentLoaded event has fired? Depending on how you're running the test you might be not be testing for the general case.

batata004 commented 5 years ago

@amorey you are 100% right! I was checking it on domcontentloaded. I will have to find a workaround so.

I would like to make you a final question. In the code below, despite using "async:false" I can clearly see that loadjs is creating all the link tags immediatly after the code below is executed. It's not waiting the first CSS to be loaded so it moves on to the next. I am pretty sure of that because on teste1.php script below I placed a code that hangs for 20 seconds so I can simulate a slow load. Despite the 20 seconds, loadjs is not waiting 20 seconds to place the others link tags. It clearly looks like that using async:false or async:true has the same exactly result!


loadjs(
    ["css!https://www.quemfazsite.com.br/temp/teste1.php","https://cdn.jsdelivr.net/npm/semantic-ui@2.3.1/dist/semantic.min.css","https://cdn.jsdelivr.net/combine/npm/vegas@2.4.0/dist/vegas.min.css,npm/animate.css@3.7.0/animate.min.css","css!//fonts.googleapis.com/css?family=Montserrat|Raleway:400,700|Abel|Libre+Baskerville:400i"],
    {
        success:function(){

        },
        async:false
    }

);
amorey commented 5 years ago

Async refers to the async property on <script> tags. When async=false, the browser will download files in parallel and execute them in series so you would expect tags to get added to the DOM immediately even if execution is delayed.

<link> tags don't have an async property so setting the LoadJS async option has no effect on them. However this doesn't matter because the CSS style rules are applied in order of <link> tags in the DOM regardless of when the files loaded.

Please note that the LoadJS success callback won't execute until all the files are finished downloading so if one of your CSS files takes 20 seconds to download, the callback won't execute until then even if the other files have already been loaded in the DOM.

batata004 commented 5 years ago

Alright! I thought that maybe loadJS would download the files with ajax and only after each one is loaded is that it would append the link tags to the DOM.

Anyway, I just want to share with you a solution that I came up to check whether a specific stylesheet has been loaded and it's pretty easy and reliable! In a particular stylesheet that I want to know that it is already loaded, there is a class named "foo-bar" that changes the color of the font of the element to red.

On my HTML I have only <div class="foo-bar">Test</div> so if any script on the page tries to get the color of this element it will be black initially (cause it inherits this color from the parents). However when the styesheet is loaded, the color is gonna chane to red! So to check if a particular stylesheet has been loaded you just have to keep checking once in a while if the color of the element is read, if not, keep checking, if it is red, then stop checking!

Thanks for you help my friend!

amorey commented 5 years ago

Ajax gives you more control over file download and execution time but it only works for files hosted on the same domain or with appropriate CSP headers set.