Modules allow you to organize functionality into separate blocks, which can then be used in other applications.
The difference between modules and regular scripts:
- CORS policy is applied to load modules. The page must be located on some web server.
- Modules always run in strict mode
- Modules are loaded asynchronously by default.
- Modules are loaded and executed only once.
- Modules allow you to use top-level await expressions without defining and calling an asynchronous function.
- Modules can import functionality from other modules and in turn export their functionality to other modules.
- Modules do not run in the global context, but in their own scope. That is, variables, constants, functions, classes, etc. defined inside a module are not accessible from outside until they are explicitly exported. And in order for another module to use them, it must import them.
If a file contains import or export statements, it is treated as a module. So, to make a module out of a simple script, just add to the file:
export { };
Module export
To create the simplest module, let’s create a separate file – for example, let’s call it test.js.
Let’s add the following code to this file:
export function sayHello() { console.log("Hello World"); }
A regular function has been added to the file that prints a message to the console.
But it is defined with the export keyword, which means that this file represents a module, and the sayHello() function can be imported into other modules.
In order for some module components (variables/constants/functions/classes) of the module to be connected and to use in other modules, they must be exported.
We can export each component separately. To do this, the export keyword is specified before the component definition:
//variable export export let welcome = "Welcome"; // constant export export const hello = "Hello"; //function export export function sayHello() { console.log("Hello World"); } //class export export class Messenger { send(text) { console.log("Sending message:", text); } }
We can export all components together as a list:
let welcome = "Welcome"; const hello = "Hello"; function sayHello() { console.log("Hello World"); } class Messenger { send(text) { console.log("Sending message:", text); } } export { welcome, hello, sayHello, Messenger }
Named import of module components
We can connect all imported components separately. To do this, after the import statement in curly braces, the names of the connected components-variables/constants/functions/functions are indicated. Then, after the from statement, the module from which the import comes is indicated.
import { component 1, component 2, ...componentN } from "path_to_module";
Import module
Now let’s include this function in another file. To do this, take the main.js file:
import { sayHello } from "./example.js"; sayHello();
To connect functionality from another module, the import keyword is used, followed by the names of the plug-in components. All components connected from the module are placed in curly braces: import {sayHello} – in this case, the sayHello function is connected.
Then, after the from statement, the module from which the import comes is indicated.
To import a module, specify only the path to the module in full:
import "path_to_module";
For example, let’s we have the following send.js module
Code in the module:
let messageText = "Sendingtext"; console.log(messageText);
In fact, this module looks like a regular script that defines a variable and prints its value to the console using the console.log() function.
Now let’s create the main.js file in which we will connect this module:
import "./example.js";
!Both modules are in the same folder
Let’s say we have an index.html html page that includes the main.js file:
<head> <meta charset="utf-8" /> <title>Example</title> </head> <body> <script type="module" src="main.js"></script> </body>
!With this connection, all calls to the functions of the send.js module will be executed,
Loading modules
To load modules, define the index.html web page in the folder with compiled files:
However, all defined and non-exported components in this module will not be accessible from outside.
We cannot write in main.js like this:
console.log(messageText); // ReferenceError: messageText is not defined
!Although we included the example.js module, its messageText variable is not available to us.
This way of importing may seem pointless. However, we can take advantage of the module,
for example, the ability to use await expressions without defining asynchronous functions. For example, let’s change the example.js module as follows:
const sum = (x, y) => Promise.resolve(x + y); const value = await sum(5, 3); console.log("Result:", value);
For simplicity, the constant sum is defined here, which represents a promise that calculates the sum of two numbers. and module allows us to use top-level await expressions to get the result from a promise without defining and calling an async function.
<head> <meta charset="utf-8" /> <title>Simple page</title> </head> <body> <script type="module" src="main.js"></script> </body>
To load the main application module – main.js, the script element is defined, for which the attribute is set type=”module”
!Modules are loaded via AJAX.
That is, we will not be able to simply throw the page into a web browser and load modules on it. This web page should be hosted on a web server.
Import the entire module
If there are a lot of components in a plug-in and we are going to use all the features of the plug-in, then listing all the plug-ins can be tedious. In this case, we can connect all the functionality of the module in the form:
import * as module_alias from "module_path";
The import statement is followed by an asterisk, which indicates that all exported components should be included. And after the as statement comes the module alias against which the plug-in will be matched.
!With the help of the as operator, you can assign an alias to the module’s exported/imported components
!Then to use such components, not their direct name is used, but their alias.
For example:
import * as ExampledModule from "./example.js";
Then we can refer to all exported components of the module through the pseudonyms of the module, for example, calling the function sayHello: ExampleModule.sayHello()
Default export and import
When exporting, we can specify a component that will be exported by default using the default statement. For example, let’s define the following
example2.js module:
export default function sayHello() { console.log("Hello World"); }
To make an export the default, follow the export statement with a default statement.
Now let’s import this function:
import sayHello from "./example2.js"; sayHello();
Now let’s import this function:
import sayHello from "./send.js"; sayHello();
To import a default component, it is enough to write the name of this component after the import statement.
export let hello = "Hello"; export const world = "World"; export default function sayHello() { console.log("Hello World"); } export class Messenger { send(text) { console.log("Sending message:", text); } }
All components are exported here, however only the sayHello function is exported by default.
This module definition is also equivalent to the following definition, where the components are exported via a list:
let hello = "Hello"; const world = "World"; function sayHello() { console.log("Hello World"); } class Messenger { send(text) { console.log("Sending message:", text); } } export { hello, world, sayHello as default, Messenger }
Then, to use such components, not their direct name is used, but their alias.
When importing such a module, all components, with the exception of the default component, must be imported individually:
import sayHello, { welcome, Messenger } from "./file.js";
Default export and import of the whole module
It is worth considering that when exporting by default, we can only use the default statement once.
We cannot separately export two components at once by default. However, we can export by default a set of components at once as a whole:
let hello = "Hello"; const world = "World"; function sayHello() { console.log("Hello World"); } class Messenger { send(text) { console.log("Sending message:", text); } } export default { hello, world, sayHello as default, Messenger }
Now we can import the functionality of this module:
import myModule from "./example2.js"; myModule.sayHello();
Through this identifier, you can refer to a specific component using the name of the component
Dynamic module loading
Modules can be dynamically loaded anywhere in another module. In this case, remember that the module is loaded asynchronously, and the result of the import function will be a Promise object, the result of which will actually be the loaded module.
import("module").then((module) { // module actions });
You can also use the await operator to get a module object:
let module = await import("module_path");
For example, let’s say we have the following send.js module defined:
[/js]
export const helloWorld = “Hello Word!”;
export default function sayHello() {
console.log(“Hello new World”);
}
Let's dynamically include this module in another main.js module: [js] console.log("Main module starts"); import("./send.js").then((module) => { module.default(); console.log(module.hello); }); console.log("Main module ends");
If a component is exported by default, then the default keyword is used to refer to it. So, since the sayHello() function is exported by default, the expression:
module.default();
In console:
Main module starts
Main module ends
Hello Word!
Hello new World
Also in this case, you could use the await operator to get the loaded module:
console.log("Main module starts"); const module = await import("./send.js"); module.default(); console.log(module.hello); console.log("Main module ends");
Dynamic loading of modules opens up the possibility for us to load modules in various situations, including functions, cyclic and conditional constructions, and other parts of the program.
const hour = new Date().getHours(); if (hour < 17) { const module = await import("./message.js"); console.log(module.hello); } else { console.log("Go home"); }