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?

Daily short news for you
  • For a long time, I have been thinking about how to increase brand presence, as well as users for the blog. After much contemplation, it seems the only way is to share on social media or hope they seek it out, until...

    Wearing this shirt means no more worries about traffic jams, the more crowded it gets, the more fun it is because hundreds of eyes are watching 🤓

    (It really works, you know 🤭)

    » Read more
  • A cycle of developing many projects is quite interesting. Summarized in 3 steps: See something complex -> Simplify it -> Add features until it becomes complex again... -> Back to a new loop.

    Why is that? Let me give you 2 examples to illustrate.

    Markdown was created with the aim of producing a plain text format that is "easy to write, easy to read, and easy to convert into something like HTML." At that time, no one had the patience to sit and write while also adding formatting for how the text displayed on the web. Yet now, people are "stuffing" or creating variations based on markdown to add so many new formats that… they can’t even remember all the syntax.

    React is also an example. Since the time of PHP, there has been a desire to create something that clearly separates the user interface from the core logic processing of applications into two distinct parts for better readability and writing. The result is that UI/UX libraries have developed very robustly, providing excellent user interaction, while the application logic resides on a separate server. The duo of Front-end and Back-end emerged from this, with the indispensable REST API waiter. Yet now, React doesn’t look much different from PHP, leading to Vue, Svelte... all converging back to a single point.

    However, the loop is not bad; on the contrary, this loop is more about evolution than "regression." Sometimes, it creates something good from something old, and people rely on that goodness to continue the loop. In other words, it’s about distilling the essence little by little 😁

    » Read more
  • Alongside the official projects, I occasionally see "side" projects aimed at optimizing or improving the language in some aspects. For example, nature-lang/nature is a project focused on enhancing Go, introducing some changes to make using Go more user-friendly.

    Looking back, it resembles JavaScript quite a bit 😆

    » Read more

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.

AMD modules

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.

Premium
Hello

5 profound lessons

Every product comes with stories. The success of others is an inspiration for many to follow. 5 lessons learned have changed me forever. How about you? Click now!

Every product comes with stories. The success of others is an inspiration for many to follow. 5 lessons learned have changed me forever. How about you? Click now!

View all

Subscribe to receive new article notifications

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

Comments (0)

Leave a comment...