Overview of Modules in JavaScript

Aditya Narayan Tiwari
5 min readAug 13, 2023

--

Modules are like a pattern developed by developers used for many years in various languages. We can write code without generating or creating modules but it becomes hectic when the code base is very large.

Why Modules?

When the code base starts becoming bigger we see the importance of modules in our workspace.

  • Compose Software: Modules are small building blocks that we put together to build complex applications.
  • Isolate components: Modules can be developed in complete isolation without thinking about the whole codebase. Developers can work on their own modules without even understanding how other module functions. Though that’s not a good practice, know your code base :)
  • Abstract code: Implement low-level code in modules and import these abstractions into other modules.
  • Organized code: Modules naturally lead to a more organized codebase.
  • Reuse code: They allow us to easily reuse the same code even across multiple projects.

Modules in JavaScript are reusable piece of code that encapsulates implementation details of a certain part of our projects. We know that classes and functions too behave like this but the difference is that modules are usually standalone files but not necessarily.

Modules contain a bunch of codes with export and imports.

Simple example depicting a module; imports(dependencies) & exports(public APIs).

Using export we can ‘export’ values out of a module to another module, be it simple values or even entire functions. Whatever is exported from a module is called public API similar to like classes for other code to consume.

Now these public APIs or exports are consumed by importing into a module. These other modules from which we import are called dependencies of importing module as the code in the module which is importing cannot work without the code present inside the module which is exporting.

ES6 Modules:

As of ES6 JS has its own native built-in module system. ES6 Modules are stored in files, exactly one module per file.

  • In ES6 modules all top variables are scoped to the module. Variables are private to modules by default. The only way an outside module can access a value that’s inside of a module is by exporting that value. Without exporting, no one can access or see the variable. (whereas in scripts all top-level variables are global).
  • ES6 modules are always executed in strict mode.
  • Here this keyword points to undefined.
  • Using import and export syntax we can export and import values between modules. Imports and exports need to happen at the top level i.e. outside of any if or function blocks. All imports are hoisted.
  • Importing is always the first thing that happens inside a module.
  • In order to link a module to an HTML file, we set the type attribute to “module” in the script tag:
  • File downloading of module files happens in an asynchronous way.

How are ES6 Modules imported?

Flow diagram explaining the process of import.

Key points to keep in mind from the above flow diagram:

  • The connection between export and import modules is a live collection. Exported values are not copied to imports. Instead is just a reference to the exported value like a pointer. (When the value changes in exporting module, the value also changes in importing module).
  • It is the only importing operation of modules that happens synchronously. The modules are downloaded asynchronously.
  • Imports are hoisted to the top.
  • Exports need to happen in the top level of code i.e. not inside any if block or function.

ES6 Modules have 2 types of exports:

Named Exports:

The simplest way of doing export in JavaScript. Mainly used when we have to export multiple values:

Multiple values can be imported and exported in named exports.

We can also rename the values imported or exported during its import or exportitself:

We can also import all the exports of a module at the same time: Using * notation and creating an object containing every exported value of the exporting module:

Default Exports:

We used default exports when we have to only export one value per module:

You can also have Default & Named imports & exports in the same line:

(This practice is not desired and is discouraged).

Here add is the default import, and others in brackets are named imports.

Top Level Await(ES2022):

With the new ES 2022 version we can now use the await keyword outside of the async function which works only inside modules that we call top-level await. It actually blocks the execution of the entire module.

If say module-1 imports a module-2 which has a top-level await then the importing module-1 will wait for the imported module-2 to finish the blocking code.

--

--