modules

Modules in Node.js

What are modules?

A module is a file that contains a collection of functions, objects, or other data that can be used in other programs. In Node.js, each file is considered a separate module.

CommonJS modules

CommonJS modules are the original way to package JavaScript code for Node.js. They are similar to JavaScript modules in web browsers, but there are some important differences.

How do CommonJS modules work?

When you load a CommonJS module, it is wrapped in a function by Node.js. This function creates a private scope for the module, so that variables declared in the module cannot be accessed from outside the module.

The module can export functions, objects, or other data by assigning them to the exports object. For example, the following module exports a square function:

// square.js
exports.square = function (x) {
  return x * x;
};

To use the square function in another module, you can load the module using the require() function:

// main.js
const square = require("./square.js");
console.log(square(2)); // 4

ES modules

ES modules are the newer way to package JavaScript code. They are based on the ECMAScript 2015 specification, and they are supported by Node.js starting with version 13.

ES modules are similar to CommonJS modules, but there are some important differences. First, ES modules are not wrapped in a function by Node.js. This means that variables declared in an ES module can be accessed from outside the module.

Second, ES modules use the import and export keywords to import and export functions, objects, and other data. For example, the following ES module exports a square function:

// square.js
export function square(x) {
  return x * x;
}

To use the square function in another ES module, you can import the module using the import keyword:

// main.js
import { square } from "./square.js";
console.log(square(2)); // 4

Which module system should I use?

If you are developing a new project, it is recommended to use ES modules. ES modules are more modern and they have some advantages over CommonJS modules, such as:

  • They are not wrapped in a function, so variables declared in an ES module can be accessed from outside the module.

  • They use the import and export keywords, which are more concise and easier to read than the require() and exports keywords.

However, if you are working on an existing project that uses CommonJS modules, you can continue to use CommonJS modules. CommonJS modules are still supported by Node.js, and they will continue to be supported for the foreseeable future.

Real-world applications of modules

Modules are used in a wide variety of real-world applications, including:

  • Web development: Modules can be used to organize and reuse code in web applications. For example, a web application might have a module for handling user authentication, a module for handling database interactions, and a module for handling user input validation.

  • Server-side development: Modules can be used to organize and reuse code in server-side applications. For example, a server-side application might have a module for handling HTTP requests, a module for handling database interactions, and a module for handling user authentication.

  • Desktop development: Modules can be used to organize and reuse code in desktop applications. For example, a desktop application might have a module for handling the user interface, a module for handling data processing, and a module for handling file I/O.


Node.js Modules

Node.js has two ways of organizing code into modules: CommonJS modules and ECMAScript modules.

CommonJS Modules

These are the traditional way of organizing code in Node.js. They use a require() function to import other modules.

Example:

// main.js
const math = require("./math.js");

console.log(math.add(1, 2)); // 3
// math.js
function add(a, b) {
  return a + b;
}

module.exports = {
  add,
};

ECMAScript Modules

ECMAScript modules are a newer way of organizing code in Node.js. They use an import statement to import other modules.

Example:

// main.js
import { add } from "./math.js";

console.log(add(1, 2)); // 3
// math.js
export function add(a, b) {
  return a + b;
}

Determining which Module System to Use

Node.js will automatically determine which module system to use based on the file extension.

  • CommonJS: .js, .cjs

  • ECMAScript: .mjs

Calling require() and import()

  • require() always uses CommonJS modules.

  • import() always uses ECMAScript modules.

Real-World Applications

  • CommonJS: Used in older Node.js projects, legacy code, and projects that need to support older Node.js versions.

  • ECMAScript: Used in newer Node.js projects, projects that require more modern features, and projects that want to take advantage of the benefits of ECMAScript modules.


Accessing the Main Module

What is a Main Module?

When you run a JavaScript file using Node.js, the file itself becomes the main module. It's like the starting point of your program.

The require.main Object

Node.js has a special object called require.main that stores information about the main module.

  • require.main === module: If you're running the file directly, this will be true.

  • require.main !== module: If you're requiring the file from another file, this will be false.

Real-World Example

Imagine you have two files: main.js and helper.js.

  • main.js is your main program.

  • helper.js contains helper functions used by main.js.

If you run node main.js, then require.main will point to the module object of main.js.

However, if you run const helper = require('./helper'), then require.main will point to the require.main of the file that required helper.js.

Potential Applications

  • Determining the entry point of your program: You can check if require.main === module to determine if your file is being run as the main program or as a dependency.

  • Restricting functionality to the main module: You can write code that only runs if the file is being run as the main module. For example:

if (require.main === module) {
  // Code that should only run when the file is run directly
}

Simplified Code Snippets

main.js:

// This is the main module
console.log("This is the main module");

helper.js:

// This is a helper module
module.exports = {
  // Helper functions
};

When you run node main.js, the console output will be:

This is the main module

Package Manager Tips

What is a package manager?

A package manager is a tool that helps you install, update, and manage software packages. In the Node.js ecosystem, the most popular package manager is called npm.

Why you might want to create your own package

  • To share your code with others

  • To use shared code across multiple projects

  • To organize your code into reusable modules

Creating a package directory structure

When you create a package, it's important to follow a consistent directory structure. This will make it easier for others to find and use your code.

The recommended directory structure is as follows:

/usr/lib/node/<package-name>/<version>/

For example, if you have a package called "my-package" and it's version is 1.0.0, the directory structure would be:

/usr/lib/node/my-package/1.0.0/

Package dependencies

Packages can depend on other packages. This means that in order to use a package, you also need to install the packages that it depends on.

For example, if your package depends on the "request" package, you would need to install the "request" package before you can use your package.

Node.js's require() function

The require() function is used to load modules in Node.js. When you call require(), Node.js will look for the module in the following locations:

  • In the current directory

  • In the node_modules folder in the current directory

  • In the node_modules folder in the parent directory

  • ...

  • In the node_modules folder in the root directory

Symlinks and node_modules folders

To avoid dependency conflicts, you can use symlinks to link to different versions of packages.

For example, if you have a package that depends on the "bar" package, you can create a symlink from the node_modules folder in the "foo" package to the "bar" package.

This will allow the "foo" package to use the specific version of the "bar" package that it depends on, even if there are other versions of the "bar" package installed in the system.

NODE_PATH environment variable

The NODE_PATH environment variable can be used to add additional directories to the search path for modules. This can be useful for making modules available to the Node.js REPL.

For example, if you have a package called "my-package" installed in the "/usr/lib/node_modules" directory, you can add the "/usr/lib/node_modules" directory to the NODE_PATH environment variable.

This will allow you to require() the "my-package" module without specifying the full path to the module.

Real-world examples

There are many real-world applications for package managers. Here are a few examples:

  • Sharing code with others: You can publish your packages to the npm registry so that others can use them in their projects.

  • Using shared code across multiple projects: You can create packages for shared code that you use across multiple projects. This can help to keep your code organized and consistent.

  • Organizing your code into reusable modules: You can create packages for reusable modules of code. This can help to make your code more modular and easier to maintain.


Simplified Explanation of .mjs Extension

Q: What is the .mjs extension? A: .mjs is a special file extension for JavaScript files that use the ES Module (ECMAScript Module) format.

Difference between require() and import()

Q: What is require()? A: Node.js's require() function is used to load and run JavaScript files.

Q: What is import()? A: import() is a special keyword used to load ES Modules in Node.js.

Q: Why can't require() be used with .mjs files? A: require() is designed to work with older JavaScript code that uses the CommonJS module format. ES Modules use a different format and cannot be loaded with require().

Potential Applications in Real World

Q: When might you use .mjs files? A: You would use .mjs files when you want to use the latest features of JavaScript and write code in the ES Module format.

Code Implementation Examples

Example 1: Loading a .mjs file with import()

my-module.mjs:

// This is an ES Module

export function greet(name) {
  console.log(`Hello, ${name}!`);
}

index.js:

// This is a CommonJS module

import { greet } from "./my-module.mjs";

greet("John"); // Output: Hello, John!

Example 2: Creating a .mjs file and exporting an object

my-object.mjs:

// This is an ES Module

export const person = {
  name: "Jane Doe",
  age: 30,
};

index.js:

// This is a CommonJS module

import { person } from "./my-object.mjs";

console.log(person); // Output: { name: 'Jane Doe', age: 30 }

Simplified Explanation of Node.js Modules

What are Modules?

Imagine you're building a Lego house. You don't want to make every single brick by yourself, so you buy different sets of bricks (modules) that already have pre-made pieces, like windows, doors, and walls.

Modules are similar in Node.js. They are pre-built pieces of code that you can add to your program to add functionality. For example, you can use a module to connect to a database, send emails, or handle file uploads.

How to Load Modules

To use a module, you need to first load it into your program using the require() function. This function takes the name of the module as an argument.

For example, to load the fs module, which provides functions for working with files, you would write:

const fs = require('fs');

Types of Modules

Node.js supports two types of modules:

  • Core modules: These come pre-installed with Node.js. Examples include fs, http, and crypto.

  • Third-party modules: These are modules that you need to install separately from the Node.js website or a package manager like npm. Examples include express, mongoose, and react.

Module Paths and Resolution

When you load a module, Node.js follows a specific algorithm to find the file that contains the module's code. This algorithm is summarized below:

  1. Core modules: Node.js knows where to find core modules, so it loads them directly.

  2. Absolute paths: If the module name starts with a forward slash (/), Node.js treats it as an absolute path and loads it from that location.

  3. Relative paths: If the module name starts with a dot (.), Node.js interprets it as a relative path and looks for the module in the same directory as the current file.

  4. Package paths: Node.js checks if the module is installed in any of the paths specified in the NODE_PATH environment variable or the package.json file's paths property.

  5. Node.js core paths: If the module is not found in the above locations, Node.js searches for it in a few predefined core paths.

  6. Not found: If the module is not found anywhere, Node.js throws an error.

Package.json and Modules

Many modules come with a package.json file. This file contains information about the module, including its name, version, dependencies, and a main property. The main property specifies the file that contains the main module code.

When loading a module from a package, Node.js first tries to load the file specified in the main property. If the main property is not present or is set to a falsy value, Node.js tries to load the index.js file from the package directory.

Real-World Examples

Here are some real-world examples of how modules can be used:

  • To connect to a database using the mysql module:

const mysql = require('mysql');

const connection = mysql.createConnection({
  host: 'localhost',
  user: 'root',
  password: 'password',
  database: 'database_name'
});

connection.connect(function(err) {
  if (err) {
    console.log('Error connecting to the database');
  } else {
    console.log('Connected to the database');
  }
});
  • To send an email using the nodemailer module:

const nodemailer = require('nodemailer');

const transporter = nodemailer.createTransport({
  service: 'gmail',
  auth: {
    user: 'username@gmail.com',
    pass: 'password'
  }
});

const mailOptions = {
  from: 'username@gmail.com',
  to: 'recipient@email.com',
  subject: 'Test email',
  text: 'Hello, this is a test email.'
};

transporter.sendMail(mailOptions, function(err, info) {
  if (err) {
    console.log('Error sending email');
  } else {
    console.log('Email sent: ' + info.response);
  }
});
  • To process and respond to HTTP requests using the express module:

const express = require('express');

const app = express();

app.get('/', function(req, res) {
  res.send('Hello, world!');
});

app.listen(3000, function() {
  console.log('App is listening on port 3000');
});

Potential Applications

Modules can be used in a wide variety of applications, including:

  • Developing web applications

  • Automating tasks

  • Building command-line tools

  • Interfacing with hardware devices

  • Creating reusable code libraries


Caching in Modules

What is caching?

Caching is like keeping a copy of something you frequently use, so you don't have to go and get it again and again. In node.js, modules are like small programs that we can use in our code.

How does caching work with modules?

When you first use a module, node.js loads it into memory and stores it in a "cache". This means that the next time you use the same module, node.js will just use the copy from the cache instead of loading it again.

Why is caching useful?

Caching makes our code faster because it saves time loading modules. It also allows us to create objects that can be shared between different parts of our code, which can be very useful.

How to disable caching

If you want to disable caching for a module, you can delete it from the require.cache object. However, this is not recommended, as it can make your code slower.

Real-world example

Let's say we have a module called myModule that we use in our code. The following code will load the module and store it in the cache:

const myModule = require('./myModule');

The next time we use myModule, node.js will use the copy from the cache instead of loading it again:

const anotherModule = require('./myModule');

This can save us a lot of time, especially if myModule is a large or complex module.

Potential applications of caching

Caching can be used in a variety of applications, such as:

  • Speeding up web applications: By caching frequently used data, web applications can respond to requests more quickly.

  • Reducing database load: By caching database queries, we can reduce the load on our database server.

  • Improving user experience: By caching frequently used data, we can make our applications more responsive and enjoyable to use.


Module Caching Caveats

Resolved Filename

When Node.js loads a module, it first searches for the module's file using a specific set of rules. The path to the file that is found is called the "resolved filename."

// Require the 'foo' module
const foo = require('foo');

In this example, Node.js will search for a file called foo.js in various directories, and the resolved filename will be the path to the file that it finds.

Module Caching

Node.js caches modules based on their resolved filename. This means that if you require the same module twice with the same resolved filename, you will get the same object.

However, if you require the same module with different resolved filenames, you will get different objects.

// Require the 'foo' module from the current directory
const foo1 = require('./foo');

// Require the 'foo' module from the 'node_modules' directory
const foo2 = require('foo');

In this example, foo1 and foo2 will be different objects, because they have different resolved filenames.

Case-Insensitive File Systems

On some file systems, filenames are case-insensitive. This means that files with different names, but the same characters in a different case, are treated as the same file.

// Require the 'foo' module from the current directory
const foo1 = require('./foo');

// Require the 'FOO' module from the current directory
const foo2 = require('./FOO');

In this example, foo1 and foo2 will be the same object, even though they have different filenames. This is because the file system treats foo and FOO as the same file.

Potential Applications

Module caching can be used to improve the performance of your application by reducing the number of times that Node.js has to load a module. This can be especially beneficial for large modules or modules that are used frequently.

Real-World Example

One potential application of module caching is in a web application. When a user visits a page, the web server can require all of the necessary modules and cache them. This means that if the user visits another page that uses the same modules, the server can simply retrieve them from the cache instead of loading them again. This can significantly improve the performance of the application.


Core Modules in Node.js

What are Core Modules?

Core modules are special modules that come built into Node.js. They are like building blocks that you can use to create your own programs.

Identifying Core Modules

Core modules have a special prefix: node:. When you use this prefix, Node.js knows to load the built-in module instead of looking for it in your code.

Loading Core Modules

Core modules can be loaded in two ways:

  1. With the node: prefix: This is the most direct way to load a core module. For example, to load the HTTP module, you would use:

const http = require("node:http");
  1. Without the node: prefix: Some core modules can also be loaded without the prefix. For example, the following code will also load the HTTP module:

const http = require("http");

Examples of Core Modules

Here are some examples of core modules:

  • HTTP: Allows you to create and use HTTP servers and clients.

  • FS (File System): Provides access to the file system, allowing you to read, write, and manipulate files.

  • Path: Helps you work with file paths, such as combining different parts of a path or getting the extension of a file.

  • OS: Gives you information about the operating system, such as the current user or the platform.

Applications in Real World

Core modules are essential for building almost any kind of Node.js application. Here are some examples:

  • HTTP: Can be used to create web servers or send requests to other servers.

  • FS: Can be used to store and retrieve data from files.

  • Path: Can be used to create and manipulate file paths.

  • OS: Can be used to check system information or execute commands.


Cycles

What are Cycles?

Imagine a bunch of kids playing a game. They're all running around, trying to catch each other. But what if one of them gets caught and becomes the "it" kid? Well, that kid has to run around and try to catch the others. But wait! What if one of the other kids gets caught? Now that kid becomes the "it" kid and has to run around and try to catch the others.

This is what happens when there are circular require() calls in Node.js. One module might not have finished executing when it is returned to another module. This can lead to problems, because the module that is returned might not have all of the data or functionality that the other module needs.

A Real-World Example

Let's say we have two modules, a.js and b.js. a.js requires b.js, and b.js requires a.js. When a.js loads b.js, it might not have finished executing yet. So, when b.js tries to access a.js's exports object, it might not get all of the data or functionality that it needs.

This can lead to problems, such as:

  • Errors. If b.js tries to access a property on a.js's exports object that hasn't been set yet, it will get an error.

  • Unexpected results. If b.js uses data from a.js's exports object that hasn't been set yet, it could get unexpected results.

How to Avoid Cycles

The best way to avoid cycles is to plan your module dependencies carefully. You should try to avoid creating circular dependencies, or at least minimize the number of circular dependencies that you have.

If you do have to create circular dependencies, you need to be careful about how you use the exports object. You should only export data or functionality that is complete and ready to be used.

Potential Applications

Cycles can be used in a variety of applications, such as:

  • Creating a game where multiple players can interact with each other.

  • Creating a system where multiple components can communicate with each other.

  • Creating a library that can be used by multiple applications.

Real-World Complete Code Implementation

Here is a real-world example of how cycles can be used:

// a.js
const b = require('./b.js');

// Do something with b.
// b.js
const a = require('./a.js');

// Do something with a.

In this example, a.js requires b.js, and b.js requires a.js. This creates a circular dependency. However, it is a safe circular dependency because a.js and b.js only use data or functionality that is complete and ready to be used.

Code Snippets

Example 1: Safe Circular Dependency

// a.js
const b = require('./b.js');

// Do something with b.
// b.js
const a = require('./a.js');

// Do something with a.

Example 2: Unsafe Circular Dependency

// a.js
const b = require('./b.js');

// Do something with b that uses data that hasn't been set yet.
// b.js
const a = require('./a.js');

// Do something with a that uses data that hasn't been set yet.

Example 3: How to Avoid Cycles

// a.js
const b = require('./b.js');

// Only use data or functionality from b that is complete and ready to be used.
// b.js
const a = require('./a.js');

// Only use data or functionality from a that is complete and ready to be used.

File Modules

In Node.js, you can load files as modules to use them in your code.

Filename Search

When you use require() to load a file, Node.js searches for the file with different extensions:

  1. .js - JavaScript file

  2. .json - JSON file

  3. .node - Compiled module file

If the filename you provide doesn't include an extension, Node.js will search for it with all three extensions.

Example:

// Require a JavaScript file
const circle = require('./circle');

// Require a JSON file
const data = require('./data.json');

// Require a compiled module file
const addon = require('./addon.node');

Module Paths

The path of the file you want to load can be:

  1. Absolute - Starts with a slash (/) and points to the exact location of the file. Example: /home/marco/foo.js.

  2. Relative - Starts with a dot (.) and specifies the file's location relative to the current file. Example: ./circle.js.

  3. Core - A built-in module that doesn't need a path. Example: require('fs').

  4. Node_modules - A folder inside the current directory where modules can be installed. Example: require('lodash').

Example:

// Require a file in the same directory
const square = require('./square');

// Require a file in a subdirectory
const triangle = require('./shapes/triangle');

// Require a core module
const util = require('util');

// Require a module installed in node_modules
const express = require('express');

Error Handling

If Node.js can't find the file you're requiring, it will throw a MODULE_NOT_FOUND error.

Real-World Applications

File modules allow you to split your code into smaller, manageable pieces, making it easier to organize and maintain your applications. Here are some examples:

  • Modular Design: Create separate modules for different functionalities, such as database access, data processing, and user authentication.

  • Reusable Code: Share common code between multiple files using modules.

  • Dependency Management: Install external libraries (modules) from the npm registry to add features to your application.

  • Unit Testing: Test individual modules in isolation to ensure their correctness.


Folders as Modules

In the world of JavaScript, we can organize our code into folders, which are like special containers. We can also treat these folders as modules, which are like building blocks for our code.

Loading Modules from Folders

There are three ways to load a module from a folder:

1. package.json File:

  • Create a file named package.json inside the folder.

  • In this file, specify a main property that points to the main module file inside the folder.

  • For example:

{ "name": "my-module", "main": "./src/index.js" }

This means that when we try to load the my-module folder, it will actually load the index.js file inside the src folder.

2. index.js or index.node File:

  • If there's no package.json file or the main property is missing, Node.js will look for an index.js or index.node file inside the folder.

  • For example:

// index.js
module.exports = { message: "Hello from my-module!" };

3. Error:

  • If neither of the above files are found, Node.js will report an error saying that the module cannot be found.

Benefits of Folders as Modules

Folders as modules help us:

  • Keep our code organized and structured.

  • Easily load modules by specifying a folder path.

Real-World Examples:

Suppose we have a folder called e-commerce that contains all the files related to an e-commerce website. Inside this folder, we have subfolders for different sections like products, orders, customers, etc. We can treat each of these subfolders as separate modules, allowing us to easily import the functionality we need for a specific task.

For instance, if we need to display a list of products, we can use the require() function to load the products module from the e-commerce folder:

const products = require("./e-commerce/products");

This will load the products module and give us access to its functionality.


Modules in Node.js

Node.js provides a way to organize and reuse code through modules.

Loading Modules from node_modules

When you call require('module-name') in your code, Node.js will first look for a module with that name in the node_modules folder of your current directory. If it doesn't find it there, it will look in the node_modules folder of the parent directory, and so on, until it reaches the root of your file system or finds the module.

Example

Let's say you have a file called script.js that looks like this:

const myModule = require('some-module');

console.log(myModule);

When you run this script, Node.js will first look for a folder called node_modules in the same directory as script.js. If it finds one, it will look for a module called some-module inside it.

If it doesn't find some-module in the same directory, it will look for a node_modules folder in the parent directory, and then in the parent directory of that, and so on, until it finds the module or reaches the root of your file system.

Real-World Applications

Using node_modules allows you to easily share and reuse code between projects and applications. For example, you could create a module that provides a set of utility functions, and then use that module in any of your other projects.

Complete Code Implementation

// my-module.js
function greet(name) {
  return `Hello, ${name}!`;
}

module.exports = greet;
// script.js
const greet = require('my-module');

const name = 'John';
console.log(greet(name)); // Output: Hello, John!

Loading Modules from Global Folders

What are global folders?

Global folders are special directories where Node.js looks for modules that it can't find in its usual location (called the node_modules folder).

Which global folders are there?

There are three global folders:

  1. $HOME/.node_modules: This folder is located in your home directory and is typically used for global modules that you want to use in all your projects.

  2. $HOME/.node_libraries: This folder is also located in your home directory and is typically used for older versions of global modules.

  3. $PREFIX/lib/node: This folder is typically used for global modules that are installed with Node.js itself.

How do I use global folders?

You can use global folders by setting the NODE_PATH environment variable to a colon-delimited list of paths to the global folders. For example, if you want to use the $HOME/.node_modules and $HOME/.node_libraries folders, you would set NODE_PATH to:

NODE_PATH=$HOME/.node_modules:$HOME/.node_libraries

Why use global folders?

Global folders can be useful for:

  • Sharing modules between multiple projects

  • Installing modules that are not available in the npm registry

  • Installing older versions of modules

Potential applications:

  • A team of developers working on a large project can use global folders to share common modules between their individual projects.

  • A developer can use global folders to install a module that is not available in the npm registry.

  • A developer can use global folders to install an older version of a module that is no longer available in the npm registry.

Code implementations:

To install a module globally, you can use the npm install -g command. For example, to install the lodash module globally, you would run:

npm install -g lodash

To use a globally installed module, you can require it using the require() function. For example, to require the lodash module, you would run:

const _ = require('lodash');

Simplified explanation:

Imagine you have a toolbox full of tools. If you can't find the tool you need in your toolbox, you can go to three special tool chests in the garage to look for it. These tool chests are like global folders.

You can tell Node.js to look in these tool chests by writing a note (called NODE_PATH) that tells it where the tool chests are located.

Global folders can be useful for finding tools that you use in many different projects, or for finding old tools that you can't find in your toolbox.


Module Wrapper (Concept)

When Node.js executes a module's code, it wraps it in a special function called a "module wrapper." This wrapper serves multiple purposes:

1. Variable Scoping:

The module wrapper creates a "local scope" within the module. Any variables declared within the wrapper are visible only within that module and cannot be accessed from outside. This prevents potential conflicts with global variables and ensures privacy.

2. Global Variables within Modules:

Within the module wrapper, Node.js provides some "global-like" variables that are specific to each module:

  • module Object: Represents the current module itself. Its properties include exports, which is used to export values from the module.

  • exports Object: An empty object that you can use to add exported values to the module.

  • __filename Variable: Contains the absolute path to the module file.

  • __dirname Variable: Contains the absolute path to the directory where the module is located.

Real-World Example: (simplified)

Imagine you have a module called myModule.js that exports a function for calculating the area of a circle.

// myModule.js
(function (exports) {
  exports.calculateArea = function (radius) {
    return Math.PI * radius ** 2;
  };
})(module.exports);

Here, the module wrapper defines the exports object and then adds the calculateArea function to it. This function can be accessed from other modules using the require() function:

// anotherModule.js
const myModule = require("./myModule");
const area = myModule.calculateArea(5); // 78.54

Applications in Real World:

  • Modularity: Modules allow developers to organize and reuse code easily, enhancing maintainability and reducing redundancy.

  • Encapsulation: They enforce privacy and prevent outside interference with module variables, improving security and reducing bugs.

  • Code Sharing: Modules facilitate the sharing of reusable code across different applications and projects, promoting collaboration and efficiency.


1. The Module Scope

Explanation: The module scope is the space where variables, functions, and objects declared in a module are visible. It's like a private room where only code within that module can access those things.

Code Snippet:

// file: module1.js
let secretVariable = "shhh";

// file: module2.js
console.log(secretVariable); // Error! secretVariable is not visible here

Application: This helps in keeping code organized and secure. For example, a module handling database connections can have its credentials hidden within its scope.

2. Exporting Variables

Explanation: To make a variable accessible outside of its module, you can "export" it. This means sharing it with other modules.

Code Snippet:

// file: module1.js
export const publicVariable = "everyone can see this";

// file: module2.js
import { publicVariable } from "./module1";
console.log(publicVariable); // "everyone can see this"

Application: Exporting allows modules to communicate and share information. For instance, a module providing a utility function could export that function.

3. Importing Modules

Explanation: To access variables or functions from another module, you "import" it into your current module.

Code Snippet:

// file: module1.js
export function multiply(a, b) {
  return a * b;
}

// file: module2.js
import { multiply } from "./module1";
const result = multiply(2, 5); // result will be 10

Application: Importing enables code reusability and modularity. You can create small, specialized modules and import them where needed.

4. The CommonJS Module Pattern

Explanation: This is a popular module definition pattern used in Node.js. It exposes an "exports" object where you can assign variables or functions.

Code Snippet:

// file: module1.js
const multiply = (a, b) => a * b;
module.exports.multiply = multiply;

// file: module2.js
const module1 = require("./module1");
const result = module1.multiply(3, 4); // result will be 12

Application: The CommonJS pattern is compatible with many Node.js libraries. It's often used in server-side JavaScript applications.

5. ES6 Module Syntax

Explanation: This is the newer and preferred module definition syntax in JavaScript. It uses export and import keywords directly.

Code Snippet:

// file: module1.js
export const publicVariable = "accessible everywhere";

// file: module2.js
import { publicVariable } from "./module1.js";
console.log(publicVariable); // "accessible everywhere"

Application: ES6 module syntax is cleaner and more concise. It's supported by modern JavaScript engines.


What is __dirname?

__dirname is a special variable within Node.js that stores the current directory (folder) of the JavaScript file you're running.

Example:

Imagine you have a script called hello.js that you're running on your computer. If hello.js is located in the "my_scripts" folder, then __dirname will equal "/my_scripts".

How to use __dirname?

You can use __dirname to access files or directories within the current directory of your script.

const fs = require("fs");
const path = require("path");

const filename = path.join(__dirname, "my_data.txt");
fs.readFile(filename, (err, data) => {
  if (err) {
    console.error(err);
  } else {
    console.log(data);
  }
});

In this example, we're using __dirname to specify the path to the file my_data.txt within the same directory as the script.

Applications of __dirname:

  • Reading and writing files in your script's directory

  • Loading additional modules from within the same directory

  • Creating temporary files

  • Configuring paths based on the script's location


__filename

  • Type: String

  • Description: The __filename property is a string that contains the absolute path to the current module file. It includes the filename and the path to the file.

  • How it works:

    • In JavaScript, each file represents a module. Each module has a unique __filename property.

  • Example:

    console.log(__filename);
    • Output: /Users/mjr/example.js

  • Real-world applications:

    • Logging: The __filename property can be used to log the source of an error message.

    try {
      // Some code that may throw an error
    } catch (err) {
      console.error(`Error in ${__filename}: ${err.message}`);
    }

__dirname

  • Type: String

  • Description: The __dirname property is a string that contains the absolute path to the directory that contains the current module file.

  • How it works:

    • The __dirname property is calculated by removing the filename from the __filename property.

  • Example:

    console.log(__dirname);
    • Output: /Users/mjr

  • Real-world applications:

    • Finding related files: The __dirname property can be used to find related files, such as configuration files or data files.

    const configFile = path.join(__dirname, "config.json");

Conclusion:

  • __filename and __dirname are useful properties for accessing information about the current module file and its directory.

  • They can be used for logging, finding related files, and other tasks.


exports

  • What is it?

    • A shorter way to refer to module.exports.

  • When to use it?

    • When you want to export multiple values from a module.

  • How to use it?

    • Assign values to the exports object, like this:

    exports.firstName = "John";
    exports.lastName = "Doe";
  • Example:

    // file: user.js
    exports.firstName = "John";
    exports.lastName = "Doe";
    
    // file: app.js
    const { firstName, lastName } = require("./user");
    
    console.log(firstName, lastName); // John Doe
  • Real-world application:

    • Exporting multiple constants, variables, or functions from a module.

module.exports

  • What is it?

    • A way to define what a module exports.

  • When to use it?

    • When you want to export a single value, function, or object from a module.

  • How to use it?

    • Assign a value to the module.exports object, like this:

    module.exports = {
      firstName: "John",
      lastName: "Doe",
    };
  • Example:

    // file: user.js
    module.exports = {
      firstName: "John",
      lastName: "Doe",
    };
    
    // file: app.js
    const user = require("./user");
    
    console.log(user.firstName, user.lastName); // John Doe
  • Real-world application:

    • Exporting a class or a single function from a module.

When to use exports vs module.exports

  • Use exports when you want to export multiple values from a module.

  • Use module.exports when you want to export a single value, function, or object from a module.


Modules in Node.js

What is a module?

In programming, a module is a self-contained piece of code that can be reused in other programs. In Node.js, modules are used to organize code into smaller, manageable units.

The module Object

Every Node.js module has a special object called module, which contains information about the module. The most important property of the module object is exports, which is used to export the module's functionality.

Exporting a Module

To export a module's functionality, you can assign values to the module.exports object. For example:

// my-module.js
module.exports = {
  // Export a function
  add: (a, b) => a + b,

  // Export a string
  message: "Hello, world!",
};

Importing a Module

To use a module in another program, you can use the require() function. require() takes the name of the module as an argument and returns the module.exports object of that module.

For example, to use the my-module module from above in another program:

// another-program.js
const myModule = require("./my-module");

// Call the add() function
const sum = myModule.add(1, 2);

// Print the message
console.log(myModule.message);

Real-World Applications

Modules are used in a wide variety of applications in Node.js, including:

  • Organizing code into smaller, reusable units

  • Sharing code between different programs

  • Creating libraries of reusable functionality

  • Managing dependencies between different modules


require(id)

What is it?

require() is a function in Node.js that allows you to import modules, JSON files, and local files into your code.

Modules: Modules are like pre-built blocks of code that you can use in your own programs. They allow you to reuse code without having to write it yourself.

JSON Files: JSON (JavaScript Object Notation) files are a way to store data in a text format. They are typically used to store configuration settings or other data that needs to be read and written by a program.

Local Files: Local files are any files that are stored on your computer. You can import these files into your code using a relative path, which is a path that starts from the current directory.

How to use require():

To use require(), you simply pass in the name of the module, JSON file, or local file that you want to import. For example:

// Import a module from node_modules
const crypto = require("node:crypto");

// Import a JSON file
const jsonData = require("./path/filename.json");

// Import a local file
const myLocalModule = require("./path/myLocalModule");

How it works:

When you call require(), Node.js will look for the file that you specified. If the file is found, Node.js will execute the code in the file and return the exported content.

Exported content:

The exported content of a module or JSON file is the data that is made available to other programs that import the module or file. This data can include functions, classes, variables, and other objects.

Real-world applications:

require() can be used in a wide variety of real-world applications, such as:

  • Importing modules to provide common functionality to multiple programs

  • Importing JSON files to store configuration settings

  • Importing local files to reuse code that you have written yourself

Complete code examples:

Here is a complete code example that imports a module, a JSON file, and a local file:

// Import a module
const crypto = require("node:crypto");

// Import a JSON file
const jsonData = require("./path/filename.json");

// Import a local file
const myLocalModule = require("./path/myLocalModule");

// Use the imported data
crypto.createHash("sha256").update(jsonData.data).digest("hex");
myLocalModule.myFunction();

This code example imports a cryptographic module, a JSON file, and a local module. It then uses the imported data to perform a cryptographic operation and call a function in the local module.


require.cache Object

Overview

The require.cache object stores cached copies of Node.js modules that have been loaded using the require() function. This cache helps speed up the loading process for modules that have already been loaded.

How it works

When you require a module, Node.js checks the require.cache object to see if the module has already been loaded. If the module is found in the cache, Node.js returns the cached copy instead of loading the module again. This can save time, especially for modules that are used multiple times in a program.

You can also add or replace entries in the require.cache object. This can be useful for testing purposes, or for creating custom modules that override built-in modules.

However, it's important to note that modifying the require.cache object can have unintended consequences. For example, if you add a module to the cache that has the same name as a built-in module, Node.js will always return the cached module, even if you use the node: prefix to require the built-in module.

Real-world example

Let's say you have a module called my-module.js that you want to use in multiple places in your program. You can add the following code to the top of your program to cache the module:

require.cache["./my-module.js"] = { exports: require("./my-module.js") };

This will ensure that the './my-module.js' module is only loaded once, even if it is required multiple times.

Potential applications

The require.cache object can be used for a variety of purposes, including:

  • Caching modules for faster loading: This can be useful for modules that are used multiple times in a program, or for modules that take a long time to load.

  • Testing: You can use the require.cache object to override built-in modules with custom modules for testing purposes.

  • Creating custom modules: You can use the require.cache object to create custom modules that override built-in modules or that provide additional functionality.


require.extensions

In Node.js, you can use require() to load JavaScript modules (files with a .js extension) into your program.

But what if you want to load a module with a different extension, like .sjs?

You can do this by using the require.extensions object. This object maps file extensions to functions that know how to load and execute modules with those extensions.

For example, to load a .sjs module as if it were a .js module, you could do this:

require.extensions[".sjs"] = require.extensions[".js"];

Now, when you call require() on a file with the .sjs extension, Node.js will use the same function that it uses to load .js files.

Real-world example

Let's say you have a module called my-module.sjs that you want to load into your program.

You can do this by adding the following code to your program:

require.extensions[".sjs"] = require.extensions[".js"];

const myModule = require("./my-module.sjs");

Now, you can use the myModule object in your program as if it were a regular JavaScript module.

Potential applications

The require.extensions object can be used to load modules with any file extension. This can be useful for loading modules that are written in other languages, or for loading modules that have a custom format.

For example, you could use require.extensions to load a module that is written in CoffeeScript. To do this, you would add the following code to your program:

require.extensions[".coffee"] = require("coffee-script").register();

const myModule = require("./my-module.coffee");

Now, you can load and execute CoffeeScript modules in your program.

Deprecated

The require.extensions object is deprecated. This means that it is no longer recommended to use it.

Instead, you should use the import statement to load modules. The import statement is more modern and it supports a wider range of features.

Here is an example of how to use the import statement to load a module:

import myModule from "./my-module.sjs";

The import statement will automatically load the module with the correct file extension. You do not need to worry about manually setting the require.extensions object.

Conclusion

The require.extensions object can be used to load modules with any file extension. However, it is deprecated and you should use the import statement instead.


require.main

Simplified Explanation

require.main is a variable that represents the main module that was loaded when you started your Node.js program. It's like the "main character" of your program.

Detailed Explanation

When you run a Node.js program, the first thing that happens is that a main module is loaded. This module is the entry point of your program and it contains the code that starts everything off.

require.main is a reference to this main module. It's a Module object that contains information about the module, like its filename, path, and exports.

Real-World Example

Here's an example of how you can use require.main to check if a module is the main module:

if (require.main === module) {
  // This code will only run if the module is the main module
}

This code could be used to do something specific in the main module, like loading additional modules or setting up event listeners.

Potential Applications

require.main is useful for tasks like:

  • Identifying the main module of a program

  • Checking if a module is being run as the main module

  • Loading additional modules or setting up event listeners in the main module

Improved Code Snippet

The code snippet from the documentation can be simplified to make it easier to understand:

console.log(require.main);

This code will print the following output:

Module {
  id: '.',
  path: '/absolute/path/to',
  exports: {},
  filename: '/absolute/path/to/entry.js',
  loaded: false,
  children: [],
  paths:
   [ '/absolute/path/to/node_modules',
     '/absolute/path/node_modules',
     '/absolute/node_modules',
     '/node_modules' ] }

This output shows the properties of the main module, including its ID, path, exports, filename, and paths.


require.resolve(request[, options])

This function is used to find the location of a module without actually loading it. It takes a module path as input and returns the resolved filename.

For example, if you have a module called my-module in the node_modules directory, you can use require.resolve to find its location:

const path = require.resolve("my-module");
console.log(path); // '/path/to/my-module'

You can also specify additional paths to search for the module in, using the options parameter. For example, if you have a custom modules directory, you can add it to the search path:

const path = require.resolve("my-module", {
  paths: ["/path/to/custom-modules"],
});
console.log(path); // '/path/to/custom-modules/my-module'

Potential applications:

  • Finding the location of a module before loading it. This can be useful for debugging purposes, or for creating custom module loaders.

  • Checking if a module is installed. You can use require.resolve to check if a module is installed, without actually loading it. This can be useful for determining if a dependency is met, or for checking if a module is available in a specific environment.


require.resolve.paths(request)

Simplified Explanation:

When you use require() to load a module, Node.js searches for that module in several locations. require.resolve.paths() lets you see the list of locations that Node.js will check for a specific module.

Detailed Explanation:

  • request: The name of the module you want to load.

  • Returns: An array of strings representing the search paths for the module.

Real-World Implementation

Let's say you want to see the search paths for the fs module:

const paths = require.resolve.paths("fs");
console.log(paths);

This will output an array of paths, such as:

[
  '/Users/yourusername/node_modules/fs',
  '/Users/yourusername/local-modules/fs',
  '/usr/local/lib/node_modules/fs',
  '/usr/lib/node_modules/fs'
]

This means that Node.js will first check for the fs module in your local node_modules directory, then in any other directories listed in the array.

Potential Applications

  • Debugging: If a module is not loading properly, you can use require.resolve.paths() to see if Node.js is looking in the correct locations.

  • Custom Module Resolution: You can use require.resolve.paths() to create your own custom module resolution algorithm.


Simplified Explanation of the module Object in Node.js

What is the module Object?

Imagine a toolbox filled with different tools. In Node.js, the module object is a toolbox that represents the current code file you're working on. It contains everything you need to build your application.

Accessing the module Object

In each code file, you can access the module object using the module keyword. It's like accessing the toolbox.

module.exports and exports

The module.exports property is like a bucket where you can put the tools (functions, objects, data) you want to share with other code files. You can also access module.exports using the exports variable, which is a shortcut.

How to Use module.exports

To share a function called myFunction from the current code file, you would do this:

// Export the function named 'myFunction'
module.exports.myFunction = function () {
  // Do something...
};

In another code file, you can then import and use myFunction:

// Import the 'myFunction' function
const { myFunction } = require("./my-module.js");

// Call the function
myFunction();

Real-World Applications

The module object is essential for organizing and sharing code in Node.js applications. For example, in a web application, you might have a user.js module that contains functions for managing user data. Other modules could then import and use these functions to interact with the user database.

Additional Notes

  • The module object is created automatically when a file is loaded in Node.js.

  • You can create multiple module objects if a file dynamically loads other files.

  • It's best practice to use module.exports instead of exports directly.


module.children

Simplified Explanation:

module.children is a property of a module object that contains all the modules that the current module has required. In other words, it's a list of all the modules that are directly loaded by the current module.

Real World Example:

Consider a simplified example where you have a JavaScript application with two modules: app.js and utils.js.

// app.js
const utils = require("./utils.js"); // Required the utils module

// Do some stuff with the utils module
// utils.js
module.exports = {
  calculateSum: (a, b) => a + b,
  calculateDifference: (a, b) => a - b,
};

In this example, the app.js module requires the utils.js module. As a result, the module.children property of app.js will contain a single element, which is the utils.js module.

Potential Applications:

  • Module Dependency Management: You can use module.children to understand the dependency tree of your application. This can be helpful for debugging or optimizing your application's performance.

  • Module Isolation: By inspecting the module.children property, you can verify that modules are not interacting with each other unexpectedly. This can help prevent unexpected side effects or errors.

  • Dynamic Module Loading: You can use module.children to dynamically load modules based on runtime conditions or user input. This can provide a more customizable and flexible application architecture.

Code Snippet:

To access the module.children property, use the following syntax:

const children = module.children;

Here's an example that uses module.children to display a list of all the required modules:

const { inspect } = require("util");

const children = module.children;
console.log("Required Modules:");
for (const child of children) {
  console.log(inspect(child, { depth: null }));
}

This code will output a detailed list of all the modules required by the current module, including their paths, dependencies, and exports.


module.exports

  • {Object}

The module.exports object is created by the Module system. Sometimes this is not acceptable; many want their module to be an instance of some class. To do this, assign the desired export object to module.exports. Assigning the desired object to exports will simply rebind the local exports variable, which is probably not what is desired.

  • In simple terms, module.exports is an object that allows you to expose specific variables, functions, or objects from your module to other modules or scripts that import your module.

  • When you create a module in Node.js, you can use module.exports to specify what parts of your module you want to make available to other code.

  • For example, let's say you have a module named myModule.js that contains the following code:

// myModule.js
const message = "Hello, world!";

module.exports = message;
  • In this example, we're exposing the message variable to other code that imports our module.

  • To use this module, you would import it into another script like this:

// anotherScript.js
const myModule = require("./myModule");

console.log(myModule); // Outputs: 'Hello, world!'
  • In this example, we're importing the myModule module and accessing the message property that we exported earlier.

  • Another way to export multiple variables or functions is to use an object literal:

// myModule.js
const message = "Hello, world!";
const sum = (a, b) => a + b;

module.exports = {
  message,
  sum,
};
  • This would allow you to access the message and sum properties in other code like this:

// anotherScript.js
const myModule = require("./myModule");

console.log(myModule.message); // Outputs: 'Hello, world!'
console.log(myModule.sum(1, 2)); // Outputs: 3
  • Assigning to module.exports must be done immediately. It cannot be done in any callbacks. This does not work:

x.js:

setTimeout(() => {
  module.exports = { a: "hello" };
}, 0);

y.js:

const x = require("./x");
console.log(x.a);

Real-World Applications

  • Modules are essential for organizing and reusing code in Node.js applications. They allow you to break your code into smaller, manageable pieces that can be easily shared and reused in different projects.

  • Modules can be used for various purposes, such as:

    • Creating reusable components and libraries

    • Sharing common functionality between different applications

    • Organizing code into logical units

    • Managing dependencies and ensuring that different parts of your application are using compatible versions of external libraries

Improved Examples

Here's an improved example of exporting a class from a module:

// myModule.js
class MyClass {
  constructor(name) {
    this.name = name;
  }

  greet() {
    console.log(`Hello, ${this.name}!`);
  }
}

module.exports = MyClass;

You can then use this class in another script like this:

// anotherScript.js
const MyClass = require("./myModule");

const myInstance = new MyClass("John");
myInstance.greet(); // Outputs: 'Hello, John!'

Conclusion

module.exports is a powerful tool for exporting variables, functions, and objects from your Node.js modules. It's essential for organizing and reusing code in Node.js applications and allows you to share common functionality between different projects.


What is the exports shortcut?

  • In Node.js, every module has an exports object.

  • This object is used to store the values that the module wants to export.

  • The exports object is a shortcut to the module.exports object.

How to use the exports shortcut:

  • To export a value from a module, you can assign it to the exports object.

  • For example:

// example.js

// This will export the value of 'myVariable'
exports.myVariable = 10;
  • You can also export functions, objects, and arrays using the exports shortcut.

When to use the exports shortcut:

  • Use the exports shortcut when you want to export a small number of values from a module.

  • If you are exporting a large number of values, or if you need to export complex data structures, it is better to use the module.exports object directly.

Real-world example:

Here is an example of how the exports shortcut can be used in a real-world application:

// utils.js

// This module exports various utility functions
exports.addNumbers = function (a, b) {
  return a + b;
};

exports.multiplyNumbers = function (a, b) {
  return a * b;
};

exports.divideNumbers = function (a, b) {
  return a / b;
};

main.js:

// main.js

// This module imports the 'utils' module
const utils = require('./utils');

// Use the exported functions from the 'utils' module
const sum = utils.addNumbers(1, 2);
const product = utils.multiplyNumbers(3, 4);

console.log('The sum is:', sum);
console.log('The product is:', product);

Output:

The sum is: 3
The product is: 12

Potential applications:

The exports shortcut can be used in any application where you need to export values from a module.

  • Some common applications include:

    • Exporting utility functions

    • Exporting configuration settings

    • Exporting data structures


Module Filename

Explanation:

In Node.js, every module (like a script file) has a filename that identifies its location on your computer. This filename is stored in the module.filename property.

Simplified Example:

Imagine you have a script file named "my_script.js" that looks like this:

// my_script.js

console.log(`My filename is: ${module.filename}`);

When you run this script using the command node my_script.js, the console will output something like:

My filename: /Users/username/my_script.js

This shows you the full path to the module file.

Real-World Applications:

  • Debugging: The filename can be helpful for debugging errors, as it shows you where the module is located.

  • Module Resolution: Node.js uses the filename to resolve dependencies (other modules that are required).

  • Module Caching: Node.js uses the filename to decide if a module has already been loaded and should be reused from cache.


module.id

  • Simplified Explanation:

    • A unique identifier for the module. It is usually the full path to the file where the module is located.

  • Technical Explanation:

    • A string that represents the unique identifier of the module. In most cases, it is the absolute path to the file where the module is defined.

  • Real-World Example:

    • If a module is located at /path/to/mymodule.js, its module.id would be /path/to/mymodule.js.

  • Potential Applications:

    • Identifying modules in a complex system where multiple modules may have similar names.

    • Debugging purposes to trace the origin of a module or an error.


module.isPreloading

Explanation:

When you run a Node.js program, it goes through different stages:

  1. Preloading: This is where modules, or pieces of code that extend Node's functionality, are loaded into memory. This happens before the user code (your program) runs.

  2. Execution: Now, your program runs and uses the loaded modules.

module.isPreloading tells you if your module is currently being loaded during the preloading phase.

Simplified Example:

Imagine your Node.js program as a car. Preloading is like the car getting ready to drive: it's checking the tires, filling up the gas tank, and so on. When module.isPreloading is true, it's like you're still in the prep phase, getting everything ready for the ride.

Real-World Applications:

  • Logging: You can use module.isPreloading to determine if your module is being loaded during preloading. This can be helpful for logging or debugging purposes.

Code Implementation:

const {unlinkSync} = require('fs');

if (module.isPreloading) {
  // Do something during preloading
} else {
  // Do something else during execution
}

// Delete a file during execution, not preloading
unlinkSync('myfile.txt');

Version Changes:

This property has been available since Node.js version 14.2.0.


module.loaded

  • Whether or not the module is done loading, or is in the process of loading.

Imagine a module as a Lego box. When you open the box, you need to take out all the Lego pieces and follow the instructions to assemble the Lego set. The "module.loaded" property tells you if all the Lego pieces have been taken out of the box and are ready to be assembled. If it's true, then all the pieces are out and you can start assembling. If it's false, then some pieces are still in the box and you need to wait until they are all out before you can start assembling.

// Example

const myModule = require("./my-module.js");

if (myModule.loaded) {
  // All the Lego pieces are out of the box and we can start assembling.
  console.log("Module is loaded");
} else {
  // Some Lego pieces are still in the box and we need to wait.
  console.log("Module is not loaded yet");
}

Real-World Applications

  • Loading data from a database: You can use module.loaded to check if the data from the database is ready to be used. If it's true, then you can start using the data. If it's false, then you need to wait until the data is loaded.

  • Loading a third-party library: You can use module.loaded to check if a third-party library is ready to be used. If it's true, then you can start using the library. If it's false, then you need to wait until the library is loaded.

  • Loading a configuration file: You can use module.loaded to check if a configuration file is ready to be used. If it's true, then you can start using the configuration. If it's false, then you need to wait until the configuration is loaded.


Module.parent

Imagine you have a bunch of recipe books (modules) and each book has instructions for cooking different dishes. The module.parent property is like a recipe book that contains the instructions for the dish that you're currently cooking (module).

Stability: 0 - Deprecated

This means that the module.parent property is no longer recommended for use. It's like an old recipe book that's been replaced by newer, more efficient books.

Use require.main and module.children Instead

Instead of using module.parent, you should use require.main to find the main recipe book (entry point) of the current process. You can also use module.children to find the recipe books that have been created from the current recipe book.

Real-World Example

Let's say you have a recipe book "main.js" that contains the instructions for making a cake.

// main.js
const cake = require("./cake.js"); // Requires the cake recipe book

cake.bake(); // Calls the function to bake the cake

The "cake.js" recipe book is the module.parent of the "main.js" recipe book.

Potential Applications

  • Error handling: You can use module.parent to find the recipe book that caused an error, making it easier to debug your code.

  • Plugin management: You can use module.parent to create plugins that can be loaded into different recipe books, extending their functionality.


module.path

  • Explanation: The module.path property returns the directory name of the module. This is typically the same as the directory name of the file that contains the module's code.

  • Simplified Analogy: Imagine a folder containing all the files for a module. The module.path would be like the name of that folder, which tells you where the module is located within the larger project.

  • Code Snippet:

const path = require("path");
const module = require("./my-module");

console.log(path.dirname(module.id)); // '/path/to/my-module'
  • Real-World Application: The module.path property can be used to locate and access files that are part of a module. For example, the following code loads a JSON file that is located in the same directory as the module:

const fs = require("fs");
const path = require("path");
const module = require("./my-module");

const jsonFile = path.join(module.path, "data.json");
const data = JSON.parse(fs.readFileSync(jsonFile, "utf-8"));

module.paths

Imagine you have a big house with many rooms. Each room is like a module in Node.js, and the module contains your code. To find the right code, Node.js needs to know where to look.

module.paths is a list of "rooms" that Node.js checks when it needs to find your code. Node.js starts in the first room on the list and looks for your code there. If it doesn't find it, it moves to the next room and so on.

Here's an example of module.paths:

[
  '/home/user/node_modules',
  '/usr/local/lib/node_modules',
  '/usr/lib/node_modules'
]

In this example, Node.js will first look for your code in the node_modules folder inside your home directory (/home/user/node_modules). If it doesn't find your code there, it will look in the node_modules folder inside the /usr/local/lib directory. And if it still doesn't find your code, it will look in the node_modules folder inside the /usr/lib directory.

Real-world applications:

module.paths is important because it allows you to organize your code in a modular way. For example, you could have one module for your database logic, another module for your API logic, and another module for your front-end code. This makes it easier to maintain and update your code.

module.paths can also be used to load third-party modules. For example, you could install a module called express that provides functionality for building web applications. To use the express module, you would add it to your module.paths list.

Here's an example of how to load a third-party module:

const path = require('path');

// Add the third-party module's directory to the module paths list
module.paths.push(path.join(__dirname, 'node_modules'));

// Load the third-party module
const express = require('express');

In this example, we add the node_modules directory to the module.paths list. This allows us to load the express module using the require() function.


module.require(id)

Simplified Explanation:

The module.require() method allows you to import another module into your current module code. It's like borrowing a toolbox from another room to use in your own room.

Detailed Explanation:

  • id: This is the name or path of the module you want to import. It's like the address of the toolbox you're borrowing.

  • Returns: The imported module's content, which is usually exported functions or objects. It's like having access to the tools inside the toolbox.

Real-World Example:

Let's say you have a module that calculates the area of a circle. You want to use this function in another module that generates random circles.

Module 1: circle-area.js

// Exports a function to calculate the area of a circle
module.exports = function circleArea(radius) {
  // Calculate and return the area
};

Module 2: random-circles.js

// Import the circleArea function from module 1
const { circleArea } = require("./circle-area");

// Generate a random radius
const radius = Math.random() * 10;

// Calculate and display the area of a random circle using the imported function
console.log(`Area: ${circleArea(radius)}`);

Potential Applications:

  • Code reusability: Import common functions or components from other modules to avoid duplication.

  • Modularity: Split your code into smaller, manageable modules that can be easily imported and used.

  • Library integration: Load external libraries or modules to extend the functionality of your application.


Modules: module core module

module.builtinModules

  • A list of core modules that are built into Node.js and are always available.

  • This list is used internally by Node.js to load core modules quickly without having to search through the file system.

  • Here's a simplified example:

console.log(module.builtinModules);
// Output: [
//   'assert',
//   'buffer',
//   'child_process',
//   ...
// ]

module.createRequire(filename)

  • This function creates a function that can be used to load modules relative to the specified filename.

  • The resulting function can be used to load modules dynamically, without having to specify their full paths.

  • Here's a simplified example:

const require = module.createRequire(__filename);
const fs = require('fs');
// The fs module is now available to use

module.syncBuiltinESMExports()

  • This function synchronously loads all built-in ESM modules and exports them to the global scope.

  • This is useful for applications that need to use ESM modules without having to manually import them.

  • Here's a simplified example:

module.syncBuiltinESMExports();
// The fs module is now available to use as a global variable

1. module.findSourceMap(path)

This function helps you find a source map file for a given module. A source map is a file that maps a compiled, minified version of a module to its original, more readable source code. This can be useful for debugging or understanding how a module works.

Syntax:

static findSourceMap(path: string): SourceMap | null;

Parameters:

  • path: The path to the module for which you want to find a source map.

Returns:

  • A SourceMap object if a source map is found, or null if no source map is found.

Example:

const path = require("path");

const sourceMap = module.findSourceMap(path.join(__dirname, "foo.js"));

if (sourceMap) {
  // Do something with the source map.
}

2. Class: module.SourceMap

This class represents a source map file. A source map file contains metadata that can be used to map a compiled, minified version of a module to its original, more readable source code.

Constructor:

constructor(payload: string | object);

Parameters:

  • payload: The source map payload. This can be a string or an object.

Properties:

  • payload: The source map payload.

Methods:

  • findEntry(lineNumber, columnNumber): Finds the source map entry for the given line and column number.

Example:

const sourceMap = new module.SourceMap('{ "version": 3, ... }');

const entry = sourceMap.findEntry(10, 20);

if (entry) {
  // Do something with the entry.
}