Système de modules Node.js
Le système de modules Node.js est l'une de ses fonctionnalités principales, permettant aux développeurs d'organiser le code en petites unités réutilisables appelées modules.
Un module est un fichier indépendant qui encapsule une fonctionnalité spécifique et peut être importé et utilisé dans d'autres fichiers.
Le système de modules Node.js est une base importante pour construire des applications Node.js, permettant aux développeurs de diviser le code en éléments réutilisables et maintenables.
Chaque module est un fichier JavaScript séparé contenant un ensemble de fonctions, d'objets ou de variables associés. De cette façon, Node.js fournit une approche structurée pour gérer de grandes applications, rendant le code plus clair et plus facile à maintenir.
Chaque fichier dans Node.js peut agir comme un module et se trouve par défaut dans une portée indépendante.
Le système de modules suit la spécification CommonJS, mais prend également en charge les modules ES.
Types de modules
Node.js prend en charge les types de modules suivants :
- Modules intégrés: Modules fournis avec Node.js, tels que
fs、http、pathetc. - Modules définis par l'utilisateur: Modules créés par les développeurs.
- Modules tiers: Modules installés via npm, tels que
express、lodashetc.
Importation de modules intégrés
Les modules intégrés sont des modules fournis avec Node.js et déjà inclus dans l'environnement lors de l'installation de Node.js, donc aucune installation supplémentaire n'est nécessaire. Les modules intégrés courants incluent fs, http, path, os, crypto, etc.
Pour importer un module intégré, il vous suffit d'utiliser la fonctionrequire()et de passer le nom du module. Par exemple, pour importer le module de système de fichiersfs、path、http, vous pouvez faire ceci :
// 导入文件系统模块
const fs = require('fs');
// 导入路径模块
const path = require('path');
// 导入 HTTP 模块
const http = require('http');Ici, fs est une chaîne représentant le nom du module à charger. Node.js le reconnaît automatiquement comme un module intégré et charge les fonctionnalités correspondantes.
Exemple
console.log('Operating System:', os.platform());
console.log('Total Memory:', os.totalmem());
Importation de modules tiers
Les modules tiers sont des modules publiés par des développeurs ou la communauté open source et peuvent être installés dans un projet via npm (Node Package Manager). Les modules tiers courants incluent express, lodash, axios, etc.
Une fois que des modules tiers sont installés, ils sont placés dans le répertoire node_modules du projet. Pour importer un module tiers, utilisez également la fonctionrequire(), mais passez le nom du module. Par exemple, pour importer le framework express, vous pouvez faire ceci :
// 导入第三方模块 express
const express = require('express');
Avant d'importer un module tiers, assurez-vous de l'avoir installé via npm. Par exemple, l'installation d'express peut se faire avec la commande suivante :
npm install express
Installez le module tiers lodash et importez-le pour le tester :
Exemple
const array = [1, 2, 3, 4];
const reversedArray = lodash.reverse(array.slice()); // Utiliser lodash pour inverser le tableau
console.log('Reversed Array:', reversedArray);
Exportation et importation de modules personnalisés (modules CommonJS)
1. Exportation de modules :Utilisezmodule.exportsouexportspour exporter des fonctions, des objets ou des variables.
2. Importation de modules :Utilisezrequire()pour importer des modules.
Importation de modules
Dans Node.js, l'importation d'un module est très simple. Ci-dessous, nous créons un fichiermain.jset importons le module hello. Le code est le suivant :
Code du fichier main.js :
hello.world();
Dans l'exemple ci-dessus, le coderequire('./hello')importe le fichierhello.jsdans le répertoire courant (./est le répertoire courant, et l'extension par défaut des fichiers Node.js est.js)。
Node.js fournit deux objets, exports et require. exports est l'interface publique d'un module, et require sert à obtenir l'interface d'un module depuis l'extérieur, c'est-à-dire l'objet exports du module requis.
Ensuite, créons le fichier hello.js. Le code est le suivant :
Code du fichier hello.js :
console.log('Hello World');
}
Dans l'exemple ci-dessus, hello.js utilise l'objet exports pour faire de world l'interface d'accès du module. Dans main.js, en utilisantrequire('./hello')pour charger ce module, nous pouvons alors accéder directement aux fonctions membres de l'objetexportsdans hello.js.
Parfois, nous voulons simplement encapsuler un objet dans un module. Le format est le suivant :
module.exports = function() {
// ...
}
Par exemple :
Code du fichier hello.js :
function Hello() {
var name;
this.setName = function(thyName) {
name = thyName;
};
this.sayHello = function() {
console.log('Hello ' + name);
};
};
module.exports = Hello;
De cette façon, vous pouvez directement obtenir cet objet :
Code du fichier main.js :
var Hello = require('./hello');
hello = new Hello();
hello.setName('BYVoid');
hello.sayHello();
Le seul changement dans l'interface du module est l'utilisation demodule.exports = Helloau lieu deexports.world = function(){}. Lorsque le module est référencé de l'extérieur, son objet d'interface est l'objet Hello lui-même à exporter, plutôt que les exports d'origine.
La différence entre module.exports et exports :
module.exportsest la référence réelle à l'objet exporté.exportsOuimodule.exportsest un raccourci pour celui-ci. Vous ne pouvez pas affecter directementexports = ..., sinon la référence sera rompue.
Exportation et importation de modules personnalisés (modules ES)
Les modules ES utilisentimportetexport, ce qui est la spécification moderne des modules JavaScript.
- Les modules ES utilisent le
importetexportmot-clé, et l'extension de fichier doit être définie sur.mjs, ou danspackage.jsondeclare"type": "module"。 - Les modules ES prennent en charge les imports statiques (
import ... from ...) et les imports dynamiques (import())。
Exemple
export function greet(name) {
return `Hello, ${name}!`;
}
// main.mjs
import { greet } from './myModule.mjs';
console.log(greet('Bob')); // Sortie : Hello, Bob!
Résolution des chemins pour le chargement des modules
1. Modules de base :Tels que http et fs, qui sont inclus lors de l'installation de Node.js et peuvent être chargés directement.
const http = require('http');2. Modules de fichiers locaux :Charger à l'aide de chemins relatifs ou absolus ; vous devez spécifier./ou/。
const myModule = require('./myModule');3. Modules tiers :Situés dans lenode_modulesrépertoire ; il vous suffit de saisir le nom du module pour les charger.
const express = require('express');
Mise en cache des modules
Mécanisme de mise en cache des modules :Node.js met en cache les modules chargés pour améliorer les performances. Lorsque require() est appelé à nouveau pour le même module, le module mis en cache est renvoyé directement au lieu d'être rechargé.
Rafraîchissement du cache :Pour recharger un module, vous pouvez supprimer le cache :
delete require.cache[require.resolve('./myModule')];
Dépendances circulaires
Lorsque deux modules ou plus s'importent mutuellement, on parle de dépendance circulaire. Node.js peut gérer les dépendances circulaires simples, mais cela peut entraîner que les objets exportés par certains modules ne soient pas complètement initialisés.
Exemple
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');
La sortie montre que lorsque b.js importe a.js, comme a.js n'a pas été entièrement exécuté, a.message est undefined.
Encapsulation et portée des modules
Node.js encapsule chaque module dans une fonction, ce qui donne à chaque module une portée indépendante. Exemple :
// Node.js 内部将模块包装为类似这样的函数:
(function(exports, require, module, __filename, __dirname) {
// 模块代码在这里
});Cela signifie que les variables définies dans un module ne pollueront pas la portée globale.
Où sont placés les modules côté serveur ?
Vous avez peut-être remarqué que nous avons déjà utilisé des modules dans notre code. Comme ceci :
var http = require("http");
...
http.createServer(...);
Node.js est fourni avec un module appeléhttpNous l'appelons avec require dans notre code et affectons la valeur de retour à une variable locale.
Cela transforme notre variable locale en un objet qui possède toutes les méthodes publiques fournies par le module http.
La stratégie de recherche de fichiers dans la méthode require de Node.js est la suivante :
Parce qu'il existe 4 types de modules dans Node.js (modules natifs et 3 types de modules de fichiers), même si la méthode require est extrêmement simple, le chargement interne est assez complexe et les priorités de chargement diffèrent. Comme le montre le diagramme suivant :

Chargement depuis le cache des modules de fichiers
Bien que les modules natifs et les modules de fichiers aient des priorités différentes, ils chargent tous deux d'abord les modules existants depuis le cache des modules de fichiers.
Chargement depuis les modules natifs
Les modules natifs ont une priorité qui ne vient qu'après le cache des modules de fichiers. Après que la méthode require a résolu le nom de fichier, elle vérifie d'abord si le module se trouve dans la liste des modules natifs. Prenons l'exemple du module http : même si un fichier http/http.js/http.node/http.json existe dans le répertoire, require("http") ne sera pas chargé depuis ces fichiers, mais depuis le module natif.
Les modules natifs disposent aussi d'une zone de cache, qui est également chargée depuis le cache en premier. Si le cache n'a pas été chargé, la méthode de chargement du module natif est appelée pour le charger et l'exécuter.
Chargement depuis des fichiers
Lorsqu'un module de fichier n'est pas dans le cache et n'est pas un module natif, Node.js analyse les paramètres passés à la méthode require et charge le fichier réel à partir du système de fichiers. Les détails d'encapsulation et de compilation pendant le processus de chargement ont été introduits dans la section précédente. Ici, nous décrirons en détail le processus de recherche des modules de fichier, parmi lesquels il y a aussi quelques détails qu'il vaut la peine de connaître.
La méthode require accepte les types suivants de passage de paramètres :
- http, fs, path, etc., modules natifs.
- ./mod ou ../mod, modules de fichier avec des chemins relatifs.
- /pathtomodule/mod, modules de fichier avec des chemins absolus.
- mod, un module de fichier qui n'est pas un module natif.
Ordre d'exécution de l'instruction require(X) exécutée sous le chemin Y :
1. 如果 X 是内置模块 a. 返回内置模块 b. 停止执行 2. 如果 X 以 '/' 开头 a. 设置 Y 为文件根路径 3. 如果 X 以 './' ou '/' or '../' 开头 a. LOAD_AS_FILE(Y + X) b. LOAD_AS_DIRECTORY(Y + X) 4. LOAD_NODE_MODULES(X, dirname(Y)) 5. 抛出异常 "not found" LOAD_AS_FILE(X) 1. 如果 X 是一个文件, 将 X 作为 JavaScript 文本载入并停止执行。 2. 如果 X.js 是一个文件, 将 X.js 作为 JavaScript 文本载入并停止执行。 3. 如果 X.json 是一个文件, 解析 X.json 为 JavaScript 对象并停止执行。 4. 如果 X.node 是一个文件, 将 X.node 作为二进制插件载入并停止执行。 LOAD_INDEX(X) 1. 如果 X/index.js 是一个文件, 将 X/index.js 作为 JavaScript 文本载入并停止执行。 2. 如果 X/index.json 是一个文件, 解析 X/index.json 为 JavaScript 对象并停止执行。 3. 如果 X/index.node 是一个文件, 将 X/index.node 作为二进制插件载入并停止执行。 LOAD_AS_DIRECTORY(X) 1. 如果 X/package.json 是一个文件, a. 解析 X/package.json, 并查找 "main" 字段。 b. let M = X + (json main 字段) 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[I] = "node_modules" CONTINUE b. DIR = path join(PARTS[0 .. I] + "node_modules") c. DIRS = DIRS + DIR d. let I = I - 1 5. return DIRS
Autres extensionsUtilisation de exports et module.exports
Si vous voulez exposer des propriétés ou des méthodes à l'extérieur, utilisezexportsC'est tout. Pour exposer un objet (semblable à une classe, contenant de nombreuses propriétés et méthodes), utilisezmodule.exports。