YouTip LogoYouTip

Nodejs Module System

The Node.js module system is one of its core features, allowing developers to organize code into small, reusable units called modules. A module is an independent file that encapsulates a specific functionality and can be imported and used in other files. The Node.js module system is a fundamental building block for Node.js applications, enabling developers to split code into reusable, maintainable small blocks. Each module is a separate JavaScript file containing a set of related functions, objects, or variables. This way, Node.js provides a structured approach to managing large applications, making the code clearer and easier to maintain. Every file in Node.js can act as a module and is, by default, in its own independent scope. The module system follows the CommonJS specification but also supports ES modules. ### Module Types Node.js supports the following types of modules: * **Built-in modules**: Modules that come with Node.js, such as `fs`, `http`, `path`, etc. * **User-defined modules**: Modules created by developers. * **Third-party modules**: Modules installed via npm, such as `express`, `lodash`, etc. * * * ## Importing Built-in Modules Built-in modules are modules that come with Node.js and are included in the environment when Node.js is installed, so no additional installation is required. Common built-in modules include fs, http, path, os, crypto, etc. To import a built-in module, you simply use the `require()` function and pass the module name as an argument. For example, to import the file system module `fs`, `path`, and `http`, you can do this: // Import the file system module const fs = require('fs'); // Import the path module const path = require('path'); // Import the HTTP module const http = require('http'); Here, `fs` is a string representing the name of the module to load. Node.js automatically recognizes this as a built-in module and loads the corresponding functionality. ## Example const os = require('os'); console.log('Operating System:', os.platform()); console.log('Total Memory:', os.totalmem()); * * * ## Importing Third-party Modules Third-party modules are modules published by developers or the open-source community and can be installed into a project via npm (Node Package Manager). Common third-party modules include express, lodash, axios, etc. After installing a third-party module, these modules are placed in the project's `node_modules` directory. To import a third-party module, you also use the `require()` function, but pass the module's name. For example, to import the express framework, you can do this: // Import the third-party module express const express = require('express'); Before importing a third-party module, ensure it has been installed via npm. For example, installing express can be done with the following command: npm install express Install the third-party module `lodash` and import it for testing: ## Example const lodash = require('lodash'); const array = [1, 2, 3, 4]; const reversedArray = lodash.reverse(array.slice()); // Use lodash to reverse the array console.log('Reversed Array:', reversedArray); * * * ## Custom Module Export and Import (CommonJS Modules) **1. Exporting a Module:** Use `module.exports` or `exports` to export functions, objects, or variables. **2. Importing a Module:** Use `require()` to import a module. ### Importing a Module In Node.js, importing a module is very simple. Below, we create a **main.js** file and import the `hello` module. The code is as follows: ## main.js File Code: var hello = require('./hello'); hello.world(); In the example above, the code `require('./hello')` imports the **hello.js** file from the current directory (`./` represents the current directory, and Node.js files default to the `.js` extension). Node.js provides two objects: `exports` and `require`. `exports` is the public interface of the module, and `require` is used to obtain the interface of a module from the outside, which is the `exports` object of the obtained module. Next, we will create the `hello.js` file. The code is as follows: ## hello.js File Code: exports.world = function(){ console.log('Hello World'); } In the example above, `hello.js` uses the `exports` object to expose `world` as the module's access interface. In `main.js`, this module is loaded via `require('./hello')`, and then you can directly access the member functions of the **exports** object in `hello.js`. Sometimes you just want to encapsulate an object into a module. The format is as follows: module.exports = function() { // ...} For example: ## hello.js File Code: // hello.js function Hello(){ var name; this.setName = function(thyName){ name = thyName; }; this.sayHello = function(){ console.log('Hello ' + name); }; }; module.exports = Hello; This way, you can directly obtain this object: ## main.js File Code: // main.js var Hello = require('./hello'); hello = new Hello(); hello.setName('BYVoid'); hello.sayHello(); The only change in the module interface is using `module.exports = Hello` instead of `exports.world = function(){}`. When referencing this module externally, the interface object is the `Hello` object itself that is to be output, not the original `exports`. **Difference between `module.exports` and `exports`:** * `module.exports` is the true reference of the exported object. * `exports` is a shortcut for `module.exports`. You cannot assign directly to `exports = ...`, as this will break the reference. * * * ## Custom Module Export and Import (ES Modules) ES modules use `import` and `export` and are the modern JavaScript module specification. * ES modules use the `import` and `export` keywords. You need to set the file extension to `.mjs`, or declare `"type": "module"` in `package.json`. * ES modules support static imports (`import ... from ...`) and dynamic imports (`import()`). ## Example // myModule.mjs export function greet(name) { return `Hello, ${name}!`; } // main.mjs import { greet } from './myModule.mjs'; console.log(greet('Bob')); // Output: Hello, Bob! * * * ## Path Resolution for Loading Modules **1. Core Modules:** Such as `http` and `fs`, they are included when Node.js is installed and can be loaded directly. const http = require('http'); **2. Local File Modules:** Loaded using relative or absolute paths, requiring `./` or `/` to be specified. const myModule = require('./myModule'); **3. Third-party Modules:** Located in the **node_modules** directory, they can be loaded by just entering the module name. const express = require('express'); * * * ## Module Caching **Module Caching Mechanism:** Node.js caches loaded modules to improve performance. When requiring the same module again with `require()`, it directly returns the cached module instead of reloading it. **Refreshing the Cache:** To reload a module, you can delete the cache: delete require.cache[require.resolve('./myModule')]; * * * ## Circular Dependencies When two or more modules import each other, it is called a circular dependency. Node.js can handle simple circular dependencies, but it may result in some exported objects of the modules not being fully initialized. ## Example // a.js const b = require('./b'); console.log('a.js:', b.message); module.exports = { message: 'Hello from a' }; // b.js const a = require('./a'); console.log('b.js:', a.message); module.exports = { message: 'Hello from b' }; // main.js require('./a'); The output explains that when `b.js` imports `a.js`, because `a.js` has not finished executing completely, `a.message` is `undefined`. * * * ## Module Wrapping and Scope Node.js wraps each module in a function, giving each module its own independent scope. Example: // Node.js internally wraps the module in a function like this: (function(exports, require, module, __filename, __dirname) { // Module code goes here }); This means variables defined within a module do not pollute the global scope. * * * ## Where to Put Server-side Modules You may have noticed that we have already used modules in our code. Like this: var http = require("http"); ... http.createServer(...); Node.js comes with a module called **http**. In our code, we request it and assign the returned value to a local variable. This turns our local variable into an object that has all the public methods provided by the http module. The file lookup strategy in Node.js's `require` method is as follows: Since there are 4 types of modules in Node.js (native modules and 3 types of file modules), although the `require` method is extremely simple, the internal loading is very complex, and their loading priorities are also different. As shown in the figure below: !(#) ### Loading from File Module Cache Although native modules and file modules have different priorities, they will both prioritize loading existing modules from the file module cache. ### Loading from Native Modules The priority of native modules is second only to the file module cache. After the `require` method resolves the filename, it first checks if the module is in the list of native modules. Taking the `http` module as an example, even if there is an `http/http.js/http.node/http.json` file in the directory, `require("http")` will not load from these files, but from the native module. Native modules also have a cache area, and similarly, loading from the cache is prioritized. If the module has not been loaded into the cache, the native module's loading method is called to load and execute it. ### Loading from Files When the module is not in the file module cache and is not a native module, Node.js parses the parameters passed to the `require` method and loads the actual file from the file system. The wrapping and compilation details during the loading process have been introduced in the previous section. Here, we will describe in detail the process of finding file modules, and there are some details worth knowing. The `require` method accepts the following types of parameters: * `http`, `fs`, `path`, etc., native modules. * `./mod` or `../mod`, file modules with relative paths. * `/pathtomodule/mod`, file modules with absolute paths. * `mod`, file modules that are not native modules. The execution order when executing `require(X)` in path `Y`: 1. If `X` is a built-in module a. Return the built-in module b. Stop execution 2. If `X` starts with '/' a. Set `Y` as the file root path 3. If `X` starts with './' or '/' or '../' a. LOAD_AS_FILE(Y + X) b. LOAD_AS_DIRECTORY(Y + X) 4. LOAD_NODE_MODULES(X, dirname(Y)) 5. Throw an exception "not found" LOAD_AS_FILE(X) 1. If `X` is a file, load `X` as JavaScript text and stop execution. 2. If `X.js` is a file, load `X.js` as JavaScript text and stop execution. 3. If `X.json` is a file, parse `X.json` as a JavaScript object and stop execution. 4. If `X.node` is a file, load `X.node` as a binary plugin and stop execution. LOAD_INDEX(X) 1. If `X/index.js` is a file, load `X/index.js` as JavaScript text and stop execution. 2. If `X/index.json` is a file, parse `X/index.json` as a JavaScript object and stop execution. 3. If `X/index.node` is a file, load `X/index.node` as a binary plugin and stop execution. LOAD_AS_DIRECTORY(X) 1. If `X/package.json` is a file, a. Parse `X/package.json` and look for the "main" field. b. let M = X + (json main field) c. LOAD_AS_FILE(M) d. LOAD_INDEX(M) 2. LOAD_INDEX(X) LOAD_NODE_MODULES(X, START) 1. let DIRS = NODE_MODULES_PATHS(START) 2. for each DIR in DIRS: a. LOAD_AS_FILE(DIR/X) b. LOAD_AS_DIRECTORY(DIR/X) NODE_MODULES_PATHS(START) 1. let PARTS = path split(START) 2. let I = count of PARTS - 1 3. let DIRS = [] 4. while I >= 0, a. if PARTS = "node_modules" CONTINUE b. DIR = path join(PARTS[0 .. I] + "node_modules") c. DIRS = DIRS + DIR d. let I = I - 1 5. return DIRS > **Using `exports` and `module.exports`** > > > If you want to expose properties or methods, just use **exports**. If you want to expose an object (similar to a class, containing many properties and methods), use **module.exports**.
← Jquery Plugin Password ValidatNodejs Http Server β†’