Understanding Modules in Node.js. Why are there so many types of modules?

Understanding Modules in Node.js. Why are there so many types of modules?

Issues

When building Vue.js or React.js applications, you often use the import syntax to use a component or module. However, with plain JS Node.js applications, you typically use require:

const fs = require('fs'); // CommonJS
// or
import { Component } from 'React'; // ES6 module

Or sometimes you may come across the case where modules are declared using AMD (Asynchronous Module Definition) syntax as shown below:

define(['jquery'] , function ($) {
    return function () {};
});

From these examples, have you ever wondered why sometimes you can use import, sometimes use require, or even why you can't use import syntax normally when starting a Node.js application?

// file index.js
import * as fs from "fs";
fs.mkdir('/temp/temp', () => console.log("success"));

Running:

$ node index.js
(node:2912) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.  
/Users/hoaitx/index.js:1
import * as fs from "fs";
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at wrapSafe (internal/modules/cjs/loader.js:931:16)
    at Module._compile (internal/modules/cjs/loader.js:979:27)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1035:10)
    at Module.load (internal/modules/cjs/loader.js:879:32)
    at Function.Module._load (internal/modules/cjs/loader.js:724:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:60:12)
    at internal/main/run_main_module.js:17:47

Then an error will be thrown as shown above! So what is the difference between them and why are there these differences? This article hopes to help answer those questions.

1. CommonJS and AMD

For those who don't know, require is the syntax of CommonJS, which is used to create a module system for Node.js from the early days. The goal of CommonJS is to provide a module system for Node.js applications. Since JavaScript did not have an official module system at that time, CommonJS was designed to fill that gap. One characteristic of CommonJS is that it is designed for "loading" modules synchronously, and this is not suitable for browser environments, as synchronously loading modules will significantly decrease page loading performance.

On the contrary, AMD is designed to be more suitable for browser environments. RequireJS is a famous implementation of AMD. The new feature in AMD is the define() function, which allows declaring a module's dependencies before it is loaded.

define('module/id/string', ['module', 'dependency', 'array'], 
function(module, factory function) {
    return ModuleContents;  
});

The module loading in AMD can be done asynchronously, which improves page loading performance compared to synchronous loading.

banner

In summary, CommonJS and AMD are different JavaScript module specifications with different implementations. CommonJS is used more frequently in server-side applications (Node.js) while AMD is used more frequently in client-side applications (browsers).

AMD was initially a draft specification for the module format of CommonJS, but it did not achieve consensus among the development community, so it was transferred to the amdjs group. The arguments mainly revolved around finding a better format, and in the end, CommonJS was created for server-side application development due to its synchronous nature, while AMD was more suitable for client-side development (browsers) with its asynchronous nature. Reference.

2. ES6 Module (ESM)

And since ES6 was introduced, it brought the official module system for JavaScript. So is everything about modules now resolved? The syntax of ESM mainly revolves around the import and export keywords:

import * as fs from "fs"; // import
export * from "fs"; // export

ECMAScript (ES) is just a specification, and the adoption of these specifications depends on software developers (web browsers, Node.js, etc.), or even older applications that have stopped receiving updates (IE browsers) and have no ability to handle the latest ES features. That's why nowadays we have many tools that support running JS code in different Node.js versions, older browsers. This helps us write code in the latest syntax but behind the scenes, it is converted to older ES versions to be compatible with most browsers and older Node.js versions.

Some tools like Babel, Webpack integrate tools that help us transpile code from higher versions of ES down to lower ES versions that most browsers can understand.

To keep up with the trend, Node.js has added support for ESM starting from version 12 LTS. However, up to the present (v14 LTS), ESM is still an experimental feature. There are several ways to "legitimize" the use of ESM in Node.js versions 12 and above, including:

  • Naming the file with the .mjs extension
  • Adding a "type" attribute with a value of "module" in the package.json file
  • Or using the --input-type flag in the command.
// file index.mjs
import * as fs from "fs";
fs.mkdir('/temp/temp', () => console.log("success"));
$ node index.mjs
(node:3933) ExperimentalWarning: The ESM module loader is experimental.  
success

3. Conclusion

CommonJS and AMD are module specifications that were established before ESM was introduced in ES6. ESM is the "real deal," but the popularity of CommonJS has made it the default module system of Node.js.

Nowadays, with the development of tools that support transpiling code from higher ES versions to lower ES versions, we can write JavaScript code using new syntax but behind the scenes, it is transpiled to older versions to be compatible with most browsers and older Node.js versions.

or
* The summary newsletter is sent every 1-2 weeks, cancel anytime.
Author

Hello, my name is Hoai - a developer who tells stories through writing ✍️ and creating products 🚀. With many years of programming experience, I have contributed to various products that bring value to users at my workplace as well as to myself. My hobbies include reading, writing, and researching... I created this blog with the mission of delivering quality articles to the readers of 2coffee.dev.Follow me through these channels LinkedIn, Facebook, Instagram, Telegram.

Did you find this article helpful?
NoYes

Comments (0)