Normal modules are library code files that explicitly export those (variable, function and class) names
that other modules can use (as implicitly frozen like const
declarations). A module that is to use items from another module needs to
explicitly import them from that other
module using import statements. It is recommended that all JS module files
use the file extension "mjs" for indicating that they are different from
classical script files.
Web pages can load module files, possibly along with classical
script files, with the help of a special type of script
element.
The meaning of ES6 modules is based on the following principles:
A JS library file can be turned into a module by using "export" for all library items. Other modules can "import" its items.
Any ordinary script file that is to use one or more items from a module has itself to be turned into a module ("only modules can use modules"). Since it doesn't export anything, such a module could also be called an "import module".
All modules, no matter if they export anything or are just
"import modules", are separated from the global scope in the following
sense: they have read access to items from the global scope such as
DOM objects (like document
) or other global objects (like
Array
), but they cannot create any names (including
objects and functions) in the global scope. This implies, for
instance, that a JS function defined in a module cannot be assigned to
an onclick
event handler attribute in an HTML
file..
Using modules implies that we can no longer use the global scope for the names of functions/classes, which is a restriction that is considered a good practice in software engineering.
An example of a normal (library) module file is
util.mjs
with the following code:
function isNonEmptyString(x) { return typeof(x) === "string" && x.trim() !== ""; } ... export { isNonEmptyString, ... };
An example of a module that imports certain items from other modules
and then uses them in its own code, and also exports some of its own items
is the model class file Book.mjs
with the following
import/export statements:
import { isNonEmptyString, ... } from "../../lib/util.mjs"; import { NoConstraintViolation, MandatoryValueConstraintViolation, ... } from "../../lib/errorTypes.mjs"; export default function Book( slots) {...}
Since this module only exports one class (Book), a default export us used, allowing simplified imports.
An example of a module that does not export anything, but only
imports certain items, is the view code file
createBook.mjs
with the following import
statements:
import Book from "../../src/m/Book.mjs"; import { fillSelectWithOptions } from "../../lib/util.mjs"; ...
An HTML page (here: createBook.html
) can load
such a module with a special type of script
element:
<script src="src/v/createBook.mjs" type="module"></script>
Notice that this script
element's type
attribute is set to "module".
Alternatively, the code of such a module can be embedded in the HTML page like so:
<script type="module"> import Book from "./src/m/Book.mjs"; const clearButton = document.getElementById("clearData"); // Set event handler for the button "clearData" clearButton.addEventListener("click", function () {Book.clearData();}); </script>.