3

I have the following code in a script.js file that I call in my html file:

function loadScript(url)
{    
    var head = document.getElementsByTagName('head')[0];
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = url;
    script.async = false;
    head.appendChild(script);
}

loadScript('https://polyfill.io/v3/polyfill.min.js?features=es6')
loadScript('https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js')
loadScript('https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.5.0/highlight.min.js')

hljs.initHighlightingOnLoad();

I use this code because I want to call only one .js file in my html instead of multiple .js files.

The first two scripts that I load to call MathJax work fine. The third script to call highlight.js however does not run.

When I paste all the code from the file 'highlight.min.js' into the my script.js file, the javascript does run normally when I open the html.

I don't understand why loading the 'highlight.min.js' file with the loadScript() does not work, or what I can do to get it to work. Any help is appreciated.

Vincent
  • 240
  • 2
  • 10

2 Answers2

2

The script loading is asyncronous, so when hljs.initHighlightingOnLoad() is called the scripts are not loaded yet.

Alternative 1

You can modify your loadScript() function to make it work with promises, which resolve when the script is loaded (taken from here):

function loadScript(url) {    
    return new Promise(function(resolve, reject) {
        var script = document.createElement("script");
        script.onload = resolve;
        script.onerror = reject;
        script.src = url;
        document.getElementsByTagName("head")[0].appendChild(script);
    });
}

Now you can call your code and be sure that all libraries are loaded before calling hljs.initHighlightingOnLoad():

(async function init() {
  await loadScript('https://polyfill.io/v3/polyfill.min.js?features=es6');
  await loadScript('https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js')
  await loadScript('https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.5.0/highlight.min.js')
  
  hljs.initHighlightingOnLoad();
})()

Alternative 2

You can modify your loadScript() function to make it load the scripts using defer and add an optional onload handler that you can use to call hljs.initHighlightingOnLoad():

function loadScript(url, onload)
{    
    var head = document.getElementsByTagName('head')[0];
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = url;
    script.async = false;
    script.onload = onload;
    head.appendChild(script);
}

loadScript('https://polyfill.io/v3/polyfill.min.js?features=es6')
loadScript('https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js')
loadScript('https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.5.0/highlight.min.js', () => {hljs.initHighlightingOnLoad()})
Alvaro Flaño Larrondo
  • 5,516
  • 2
  • 27
  • 46
  • Umm why do I need a promise, can I just use the async attribute on my script element? – Jay Jan 20 '21 at 01:52
  • Thanks for your help. I am clearly doing something wrong, because copying your code into my script.js file is not working, but when I add the following lines to my html , highlight.js runs normally:: – Vincent Jan 20 '21 at 02:12
  • @Jay you are right, you could use the `async = false` to defer loading, and then you could use the `onload` handler to call the function. I'll add this option to the answer. – Alvaro Flaño Larrondo Jan 20 '21 at 05:03
  • Thank you but your answer will still never be as good as mine :) siek nah <3... nice answer! Lose the promise next time, promises are meant to be broken :) – Jay Jan 20 '21 at 05:05
1

Wheres your onload handler?

script.onload = function(){};

Lets not worry about errors for now...

https://developer.mozilla.org/en-US/docs/Web/API/HTMLScriptElement

If the libs require each other then you need to defer because the child may be smaller than the parent.

Jay
  • 3,276
  • 1
  • 28
  • 38