Inline script defer

Kamal Mustafa - Jan 4 - - Dev Community

Problem when using defer to load external script is when you have inline script that depends on the external script. This because inline script is executed immediately while deferred script is loaded after the whole page has beed parsed.

Take this script for example:-

<!doctype html>
<html>
<head>
    <script>
        console.log('Start ...');
    </script>
    <script defer src="https://unpkg.com/htmx.org@1.9.10" integrity="sha384-D1Kt99CQMDuVetoL1lrYwg5t+9QdHe7NLX/SoJYkXDFfX37iInKRy5xLSi8nO7UC" crossorigin="anonymous"></script>
    <script>
    htmx.logger = function(elt, event, data) {
    if(console) {
        console.log(event, elt, data);
        }
    }   
    </script>
    <script>
        htmx.logger("Inside head");
    </script>
</head>

<body>
    <h1>Javascript DOMContentLoaded</h1>
    <script type="module">
        htmx.logger("Inside body");
    </script>

    <script>
        window.addEventListener('DOMContentLoaded', function() {
            console.log('Inline JS');
        });
    </script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

The inline script will failed:-

Start ... localhost:9000:5:17
Uncaught ReferenceError: htmx is not defined
    <anonymous> http://localhost:9000/:9
localhost:9000:9:5
Uncaught ReferenceError: htmx is not defined
    <anonymous> http://localhost:9000/:16
localhost:9000:16:9
Uncaught TypeError: htmx.logger is not a function
    <anonymous> http://localhost:9000/:23
localhost:9000:23:14
Inline JS localhost:9000:28:21
GET
http://localhost:9000/favicon.ico
[HTTP/1 404 File not found 1ms]
Enter fullscreen mode Exit fullscreen mode

Fortunately script of type module is deferred automatically. This will work as expected:-

<!doctype html>
<html>
<head>
    <script>
        console.log('Start ...');
    </script>
    <script defer src="https://unpkg.com/htmx.org@1.9.10" integrity="sha384-D1Kt99CQMDuVetoL1lrYwg5t+9QdHe7NLX/SoJYkXDFfX37iInKRy5xLSi8nO7UC" crossorigin="anonymous"></script>
    <script type="module">
    htmx.logger = function(elt, event, data) {
    if(console) {
        console.log(event, elt, data);
        }
    }   
    </script>
    <script type="module">
        htmx.logger("Inside head");
    </script>
</head>

<body>
    <h1>Javascript DOMContentLoaded</h1>
    <script type="module">
        htmx.logger("Inside body");
    </script>

    <script>
        window.addEventListener('DOMContentLoaded', function() {
            console.log('Inline JS');
        });
    </script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode
Start ... localhost:9000:5:17
undefined Inside head undefined localhost:9000:11:17
undefined Inside body undefined localhost:9000:11:17
htmx:beforeProcessNode 
<body>

Object { elt: body }
localhost:9000:11:17
Inline JS localhost:9000:28:21
GET
http://localhost:9000/favicon.ico
[HTTP/1 404 File not found 1ms]

htmx:load 
<body>

Object { elt: body }
localhost:9000:11:17
Enter fullscreen mode Exit fullscreen mode

Browsers support is 96.81% so I think it's pretty good.

Original code taken from https://cylab.be/blog/188/defer-async-and-inline-javascript

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .