There are some syntactical rules that we shall briefly look at. Given that the previous chapter's examples work, they conformed to those rules.
import {waldo} from 'https://dkexit.eu/libs/fred.mjs';
import {waldo} from '/libs/fred.mjs';
import {waldo} from './fred.mjs';
import {waldo} from '../fred.mjs';
Rules are that there must be a path prefix in the url referencing the module file. Non observance will result in some error message on the log. The first example above may reference any url on the internet. The latter three examples are all referencing the filesystem of the server providing the page.
Using modules allows JavaScript files to work with code defined in other JavaScript files as long as these other files share something. In turn this takes the burdon of knowing the internal structure of the JavaScript from the shoulders of the HTML5 writer.
The modular JavaScript may grow out of a concrete project, but if it is deemed useful enough to be used in other projects as well it is best placed in a more general place on the developer platform.
In all our examples so far in the web programming section of our program, we have been working with an event listener deferring all JavaScript action to the point in time when the DOM is fully created ie the document has finished loading. Where has that gone? How come our code above works anyway? These two questions will be answered now.
index3.html
We have seen the following or equivalent code
<!doctype html>
<html>
<head>
<title>NMLs JS Class</title>
<meta charset='utf-8'/>
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
<script>
let output = function(txt) {
console.log(txt);
}
</script>
<script src='js0.js'></script>
<script src='js1.js'></script>
<script src='js2.js'></script>
<script src='js3.js'></script>
</head>
<body>
<h1>The Page</h1>
<script>output('Call from the body');</script>
<p>Check the log, please.</p>
</body>
</html>
(Click here!)
many times. An HTML5 page references four JavaScript files.
The Browser handles each JavaScript file in turn, as it
meets a script
element.
Nothing new, and nothing strange in that. It has a side
effect though, the building of the page is blocked while
the browser handles the script
content.
The log shows:
greetings from js0 index0.html:9:23 greetings from js1 index0.html:9:23 greetings from js2 index0.html:9:23 greetings from js3 index0.html:9:23 Call from the body index0.html:9:23
index4.html
In order to let the DOM be built before the JavaScript is
active, we have either issued a load
event listener on the window, or we have placed the
JavaScript code at the end of the body
element.
With regular scripts we may use
defer
to prevent blocking. Interestingly, modules are
deferred by default.
For at closer look at defer
and async
please refer to
https://flaviocopes.com/javascript-async-defer/.
Take a close look at this:
<!doctype html>
<html>
<head>
<title>NMLs JS Class</title>
<meta charset='utf-8'/>
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
<script>
let output = function(txt) {
console.log(txt);
}
</script>
<script type='module' src='js0.js'></script> <!-- module -->
<script src='js1.js'></script> <!-- normal script -->
<script defer src='js2.js'></script> <!-- normal but deferred -->
<script src='js3.js'></script> <!-- normal script -->
</head>
<body>
<h1>The Page</h1>
<script>output('Call from the body');</script> <!-- normal script -->
<p>Check the log, please.</p>
</body>
</html>
Click here and open the log.
What went on here? You will find that normal script,
normal as in not modules, are handled the old
fashioned way when the browser reads the script
element. Modules, and scripts that are
explicitly deferred are not blocking the building of
the page, but instead they await completion of page
building, and then they are handled in the order
they are presented to the browser. The log content
confirms:
greetings from js1 index0.html:9:23 greetings from js3 index0.html:9:23 Call from the body index0.html:9:23 greetings from js0 index0.html:9:23 greetings from js2 index0.html:9:23
index5.html
<!doctype html>
<html>
<head>
<title>NMLs JS Class</title>
<meta charset='utf-8'/>
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
<script>
let output = function(txt) {
console.log(txt);
}
</script>
<script type='module'>output('inline module says hi')</script>
<script src='js1.js'></script>
<script defer>output('inline script says hi')</script>
<script defer src='js3.js'></script>
</head>
<body>
<h1>The Page</h1>
<script>output('Call from the body');</script>
<p>Check the log, please.</p>
</body>
</html>
Click here and open the log.
Inline scripts that are not modules ignore defer
.
Inline modules behave as all modules. They are deferred.
Verify here:
greetings from js1 index5.html:9:23 inline script says hi index5.html:9:23 Call from the body index5.html:9:23 inline module says hi index5.html:9:23 greetings from js3 index5.html:9:23
It is quite common that several modules depend on some
utility module of your own. This means that these modules
all have an import
of that module. We shall
check what happens in suach a situation.
<!doctype html>
<html>
<head>
<title>NMLs JS Class</title>
<meta charset='utf-8'/>
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
<script>
let output = function(txt) {
console.log(txt);
}
</script>
<script type="module" src="js0.js"></script> <!-- modules one import -->
<script type="module" src="js0.js"></script> <!-- modules one import -->
<script type="module">import "./js0.js";</script> <!-- modules one import -->
<script type="module">import "./js0.js";</script> <!-- modules one import -->
<script src="js1.js"></script> <!-- normal repeat -->
<script src="js1.js"></script> <!-- normal repeat -->
</head>
<body>
<h1>The Page</h1>
<script>output('Call from the body');</script>
<p>Check the log, please.</p>
</body>
</html>
Click here and open the log, resulting in:
greetings from js1 index6.html:9:23 greetings from js1 index6.html:9:23 Call from the body index6.html:9:23 greetings from js0 index6.html:9:23
The module is actually only imported once although there are many references to it. It is of course deferred. The normal script is executed as often as it is sourced.