Skip to content

Modules : modules CommonJS

[Stable : 2 - Stable]

Stable : 2 Stabilité : 2 - Stable

Les modules CommonJS constituent la méthode originale d’empaquetage du code JavaScript pour Node.js. Node.js prend également en charge la norme des modules ECMAScript utilisée par les navigateurs et autres environnements d’exécution JavaScript.

Dans Node.js, chaque fichier est traité comme un module distinct. Par exemple, considérons un fichier nommé foo.js :

js
const circle = require('./circle.js')
console.log(`L’aire d’un cercle de rayon 4 est ${circle.area(4)}`)

Sur la première ligne, foo.js charge le module circle.js qui se trouve dans le même répertoire que foo.js.

Voici le contenu de circle.js :

js
const { PI } = Math

exports.area = r => PI * r ** 2

exports.circumference = r => 2 * PI * r

Le module circle.js a exporté les fonctions area() et circumference(). Les fonctions et les objets sont ajoutés à la racine d’un module en spécifiant des propriétés supplémentaires sur l’objet exports spécial.

Les variables locales au module seront privées, car le module est encapsulé dans une fonction par Node.js (voir encapsulation de module). Dans cet exemple, la variable PI est privée pour circle.js.

La propriété module.exports peut se voir assigner une nouvelle valeur (telle qu’une fonction ou un objet).

Dans le code suivant, bar.js utilise le module square, qui exporte une classe Square :

js
const Square = require('./square.js')
const mySquare = new Square(2)
console.log(`L’aire de mySquare est ${mySquare.area()}`)

Le module square est défini dans square.js :

js
// L’affectation à exports ne modifiera pas le module, il faut utiliser module.exports
module.exports = class Square {
  constructor(width) {
    this.width = width
  }

  area() {
    return this.width ** 2
  }
}

Le système de modules CommonJS est implémenté dans le module principal module.

Activation

Node.js possède deux systèmes de modules : les modules CommonJS et les modules ECMAScript.

Par défaut, Node.js traitera ce qui suit comme des modules CommonJS :

  • Les fichiers avec une extension .cjs ;
  • Les fichiers avec une extension .js lorsque le fichier package.json parent le plus proche contient un champ de niveau supérieur "type" avec la valeur "commonjs".
  • Les fichiers avec une extension .js ou sans extension, lorsque le fichier package.json parent le plus proche ne contient pas de champ de niveau supérieur "type" ou qu’il n’y a pas de package.json dans un dossier parent ; sauf si le fichier contient une syntaxe qui génère des erreurs à moins qu’il ne soit évalué comme un module ES. Les auteurs de packages doivent inclure le champ "type", même dans les packages où toutes les sources sont CommonJS. Être explicite sur le type du package facilitera la tâche des outils de construction et des chargeurs pour déterminer comment les fichiers du package doivent être interprétés.
  • Les fichiers avec une extension autre que .mjs, .cjs, .json, .node ou .js (lorsque le fichier package.json parent le plus proche contient un champ de niveau supérieur "type" avec la valeur "module", ces fichiers ne seront reconnus comme des modules CommonJS que s’ils sont inclus via require(), pas lorsqu’ils sont utilisés comme point d’entrée en ligne de commande du programme).

Voir Détermination du système de modules pour plus de détails.

L’appel de require() utilise toujours le chargeur de modules CommonJS. L’appel de import() utilise toujours le chargeur de modules ECMAScript.

Accéder au module principal

Lorsqu'un fichier est exécuté directement depuis Node.js, require.main est défini sur son module. Cela signifie qu'il est possible de déterminer si un fichier a été exécuté directement en testant require.main === module.

Pour un fichier foo.js, cela sera true s'il est exécuté via node foo.js, mais false s'il est exécuté par require('./foo').

Lorsque le point d'entrée n'est pas un module CommonJS, require.main est undefined, et le module principal est inaccessible.

Conseils pour les gestionnaires de paquets

La sémantique de la fonction require() de Node.js a été conçue pour être suffisamment générale pour prendre en charge des structures de répertoires raisonnables. Les programmes de gestion de paquets tels que dpkg, rpm et npm devraient pouvoir créer des paquets natifs à partir de modules Node.js sans modification.

Dans ce qui suit, nous donnons une structure de répertoire suggérée qui pourrait fonctionner :

Supposons que nous voulions que le dossier /usr/lib/node/\<some-package\>/\<some-version\> contienne le contenu d'une version spécifique d'un paquet.

Les paquets peuvent dépendre les uns des autres. Pour installer le paquet foo, il peut être nécessaire d'installer une version spécifique du paquet bar. Le paquet bar peut lui-même avoir des dépendances, et dans certains cas, celles-ci peuvent même entrer en conflit ou former des dépendances cycliques.

Comme Node.js recherche le realpath de tous les modules qu'il charge (c'est-à-dire qu'il résout les liens symboliques) puis recherche leurs dépendances dans les dossiers node_modules, cette situation peut être résolue avec l'architecture suivante :

  • /usr/lib/node/foo/1.2.3/ : Contenu du paquet foo, version 1.2.3.
  • /usr/lib/node/bar/4.3.2/ : Contenu du paquet bar dont dépend foo.
  • /usr/lib/node/foo/1.2.3/node_modules/bar : Lien symbolique vers /usr/lib/node/bar/4.3.2/.
  • /usr/lib/node/bar/4.3.2/node_modules/* : Liens symboliques vers les paquets dont dépend bar.

Ainsi, même si un cycle est rencontré, ou s'il y a des conflits de dépendances, chaque module sera capable d'obtenir une version de sa dépendance qu'il peut utiliser.

Lorsque le code du paquet foo effectue require('bar'), il obtient la version qui est liée symboliquement dans /usr/lib/node/foo/1.2.3/node_modules/bar. Ensuite, lorsque le code du paquet bar appelle require('quux'), il obtient la version qui est liée symboliquement dans /usr/lib/node/bar/4.3.2/node_modules/quux.

De plus, pour rendre le processus de recherche de module encore plus optimal, plutôt que de placer les paquets directement dans /usr/lib/node, nous pourrions les placer dans /usr/lib/node_modules/\<name\>/\<version\>. Node.js ne se donnera alors pas la peine de rechercher les dépendances manquantes dans /usr/node_modules ou /node_modules.

Afin de rendre les modules disponibles pour l'interpréteur de commandes Node.js, il pourrait être utile d'ajouter également le dossier /usr/lib/node_modules à la variable d'environnement $NODE_PATH. Comme les recherches de modules utilisant les dossiers node_modules sont toutes relatives et basées sur le chemin réel des fichiers effectuant les appels à require(), les paquets eux-mêmes peuvent se trouver n'importe où.

Chargement des modules ECMAScript à l'aide de require()

[Historique]

VersionModifications
v23.5.0Cette fonctionnalité n'émet plus d'avertissement expérimental par défaut, bien que l'avertissement puisse toujours être émis par --trace-require-module.
v23.0.0Cette fonctionnalité n'est plus derrière l'indicateur CLI --experimental-require-module.
v23.0.0Prise en charge de l'exportation interop 'module.exports' dans require(esm).
v22.0.0, v20.17.0Ajouté dans : v22.0.0, v20.17.0

[Stable : 1 - Expérimental]

Stable : 1 Stabilité : 1.2 - Candidat à la sortie

L'extension .mjs est réservée aux modules ECMAScript. Consultez la section Détermination du système de modules pour plus d'informations sur les fichiers analysés en tant que modules ECMAScript.

require() ne prend en charge que le chargement des modules ECMAScript répondant aux exigences suivantes :

  • Le module est entièrement synchrone (ne contient aucun await de niveau supérieur) ; et
  • L'une de ces conditions est remplie :

Si le module ES chargé répond aux exigences, require() peut le charger et renvoyer l'objet d'espace de noms du module. Dans ce cas, il est similaire à import() dynamique, mais s'exécute de manière synchrone et renvoie directement l'objet d'espace de noms.

Avec les modules ES suivants :

js
// distance.mjs
export function distance(a, b) {
  return (b.x - a.x) ** 2 + (b.y - a.y) ** 2
}
js
// point.mjs
export default class Point {
  constructor(x, y) {
    this.x = x
    this.y = y
  }
}

Un module CommonJS peut les charger avec require() :

js
const distance = require('./distance.mjs')
console.log(distance)
// [Module: null prototype] {
//   distance: [Function: distance]
// }

const point = require('./point.mjs')
console.log(point)
// [Module: null prototype] {
//   default: [class Point],
//   __esModule: true,
// }

Pour l'interopérabilité avec les outils existants qui convertissent les modules ES en CommonJS, qui pourraient ensuite charger de vrais modules ES via require(), l'espace de noms renvoyé contiendrait une propriété __esModule: true s'il possède une exportation default afin que le code consommateur généré par les outils puisse reconnaître les exportations par défaut dans les vrais modules ES. Si l'espace de noms définit déjà __esModule, celui-ci ne sera pas ajouté. Cette propriété est expérimentale et peut changer à l'avenir. Elle ne doit être utilisée que par les outils convertissant les modules ES en modules CommonJS, suivant les conventions existantes de l'écosystème. Le code écrit directement en CommonJS doit éviter d'en dépendre.

Lorsqu'un module ES contient des exportations nommées et une exportation par défaut, le résultat renvoyé par require() est l'objet d'espace de noms du module, qui place l'exportation par défaut dans la propriété .default, de manière similaire aux résultats renvoyés par import(). Pour personnaliser ce qui doit être renvoyé directement par require(esm), le module ES peut exporter la valeur souhaitée en utilisant le nom de chaîne "module.exports".

js
// point.mjs
export default class Point {
  constructor(x, y) {
    this.x = x
    this.y = y
  }
}

// `distance` est perdue pour les consommateurs CommonJS de ce module, sauf si elle est
// ajoutée à `Point` en tant que propriété statique.
export function distance(a, b) {
  return (b.x - a.x) ** 2 + (b.y - a.y) ** 2
}
export { Point as 'module.exports' }
js
const Point = require('./point.mjs')
console.log(Point) // [class Point]

// Les exportations nommées sont perdues lorsque 'module.exports' est utilisé
const { distance } = require('./point.mjs')
console.log(distance) // undefined

Notez que dans l'exemple ci-dessus, lorsque le nom d'exportation module.exports est utilisé, les exportations nommées seront perdues pour les consommateurs CommonJS. Pour permettre aux consommateurs CommonJS de continuer à accéder aux exportations nommées, le module peut s'assurer que l'exportation par défaut est un objet auquel les exportations nommées sont attachées en tant que propriétés. Par exemple, avec l'exemple ci-dessus, distance peut être attachée à l'exportation par défaut, la classe Point, en tant que méthode statique.

js
export function distance(a, b) {
  return (b.x - a.x) ** 2 + (b.y - a.y) ** 2
}

export default class Point {
  constructor(x, y) {
    this.x = x
    this.y = y
  }
  static distance = distance
}

export { Point as 'module.exports' }
js
const Point = require('./point.mjs')
console.log(Point) // [class Point]

const { distance } = require('./point.mjs')
console.log(distance) // [Function: distance]

Si le module require() contient un await de niveau supérieur, ou si le graphe de modules qu'il import contient un await de niveau supérieur, ERR_REQUIRE_ASYNC_MODULE sera levée. Dans ce cas, les utilisateurs doivent charger le module asynchrone à l'aide de import().

Si --experimental-print-required-tla est activé, au lieu de lever ERR_REQUIRE_ASYNC_MODULE avant l'évaluation, Node.js évaluera le module, tentera de localiser les attentes de niveau supérieur et affichera leur emplacement pour aider les utilisateurs à les corriger.

La prise en charge du chargement des modules ES à l'aide de require() est actuellement expérimentale et peut être désactivée à l'aide de --no-experimental-require-module. Pour afficher l'emplacement d'utilisation de cette fonctionnalité, utilisez --trace-require-module.

Cette fonctionnalité peut être détectée en vérifiant si process.features.require_module est true.

Tous ensemble

Pour obtenir le nom de fichier exact qui sera chargé lors de l'appel de require(), utilisez la fonction require.resolve().

En rassemblant tout ce qui précède, voici l'algorithme de haut niveau en pseudo-code de ce que fait require() :

text
require(X) depuis le module au chemin Y
1. Si X est un module principal,
   a. renvoyer le module principal
   b. STOP
2. Si X commence par '/'
   a. définir Y comme étant la racine du système de fichiers
3. Si X commence par './' ou '/' ou '../'
   a. LOAD_AS_FILE(Y + X)
   b. LOAD_AS_DIRECTORY(Y + X)
   c. LANCER "non trouvé"
4. Si X commence par '#'
   a. LOAD_PACKAGE_IMPORTS(X, dirname(Y))
5. LOAD_PACKAGE_SELF(X, dirname(Y))
6. LOAD_NODE_MODULES(X, dirname(Y))
7. LANCER "non trouvé"

MAYBE_DETECT_AND_LOAD(X)
1. Si X est analysé comme un module CommonJS, charger X comme un module CommonJS. STOP.
2. Sinon, si le code source de X peut être analysé comme un module ECMAScript en utilisant
  <a href="esm#resolver-algorithm-specification">DETECT_MODULE_SYNTAX défini dans
  le solveur ESM</a>,
  a. Charger X comme un module ECMAScript. STOP.
3. LANCER l'erreur SyntaxError résultant de la tentative d'analyse de X comme CommonJS en 1. STOP.

LOAD_AS_FILE(X)
1. Si X est un fichier, charger X selon le format de son extension. STOP
2. Si X.js est un fichier,
    a. Trouver la portée de package SCOPE la plus proche de X.
    b. Si aucune portée n'a été trouvée
      1. MAYBE_DETECT_AND_LOAD(X.js)
    c. Si le champ SCOPE/package.json contient le champ "type",
      1. Si le champ "type" est "module", charger X.js comme un module ECMAScript. STOP.
      2. Si le champ "type" est "commonjs", charger X.js comme un module CommonJS. STOP.
    d. MAYBE_DETECT_AND_LOAD(X.js)
3. Si X.json est un fichier, charger X.json en tant qu'objet JavaScript. STOP
4. Si X.node est un fichier, charger X.node comme extension binaire. STOP

LOAD_INDEX(X)
1. Si X/index.js est un fichier
    a. Trouver la portée de package SCOPE la plus proche de X.
    b. Si aucune portée n'a été trouvée, charger X/index.js comme un module CommonJS. STOP.
    c. Si le champ SCOPE/package.json contient le champ "type",
      1. Si le champ "type" est "module", charger X/index.js comme un module ECMAScript. STOP.
      2. Sinon, charger X/index.js comme un module CommonJS. STOP.
2. Si X/index.json est un fichier, analyser X/index.json en un objet JavaScript. STOP
3. Si X/index.node est un fichier, charger X/index.node comme extension binaire. STOP

LOAD_AS_DIRECTORY(X)
1. Si X/package.json est un fichier,
   a. Analyser X/package.json, et rechercher le champ "main".
   b. Si "main" est une valeur fausse, aller en 2.
   c. soit M = X + (champ principal json)
   d. LOAD_AS_FILE(M)
   e. LOAD_INDEX(M)
   f. LOAD_INDEX(X) DÉPRECIE
   g. LANCER "non trouvé"
2. LOAD_INDEX(X)

LOAD_NODE_MODULES(X, START)
1. soit DIRS = NODE_MODULES_PATHS(START)
2. pour chaque DIR dans DIRS :
   a. LOAD_PACKAGE_EXPORTS(X, DIR)
   b. LOAD_AS_FILE(DIR/X)
   c. LOAD_AS_DIRECTORY(DIR/X)

NODE_MODULES_PATHS(START)
1. soit PARTS = division de chemin(START)
2. soit I = nombre de PARTS - 1
3. soit DIRS = []
4. tant que I >= 0,
   a. si PARTS[I] = "node_modules", aller en d.
   b. DIR = joindre chemin(PARTS[0 .. I] + "node_modules")
   c. DIRS = DIR + DIRS
   d. soit I = I - 1
5. renvoyer DIRS + GLOBAL_FOLDERS

LOAD_PACKAGE_IMPORTS(X, DIR)
1. Trouver la portée de package SCOPE la plus proche de DIR.
2. Si aucune portée n'a été trouvée, renvoyer.
3. Si SCOPE/package.json "imports" est nul ou indéfini, renvoyer.
4. Si `--experimental-require-module` est activé
  a. soit CONDITIONS = ["node", "require", "module-sync"]
  b. Sinon, soit CONDITIONS = ["node", "require"]
5. soit MATCH = PACKAGE_IMPORTS_RESOLVE(X, pathToFileURL(SCOPE),
  CONDITIONS) <a href="esm#resolver-algorithm-specification">défini dans le solveur ESM</a>.
6. RESOLVE_ESM_MATCH(MATCH).

LOAD_PACKAGE_EXPORTS(X, DIR)
1. Essayer d'interpréter X comme une combinaison de NAME et SUBPATH où le nom
   peut avoir un préfixe @scope/ et le sous-chemin commence par une barre oblique (`/`).
2. Si X ne correspond pas à ce modèle ou si DIR/NAME/package.json n'est pas un fichier,
   renvoyer.
3. Analyser DIR/NAME/package.json, et rechercher le champ "exports".
4. Si "exports" est nul ou indéfini, renvoyer.
5. Si `--experimental-require-module` est activé
  a. soit CONDITIONS = ["node", "require", "module-sync"]
  b. Sinon, soit CONDITIONS = ["node", "require"]
6. soit MATCH = PACKAGE_EXPORTS_RESOLVE(pathToFileURL(DIR/NAME), "." + SUBPATH,
   `package.json` "exports", CONDITIONS) <a href="esm#resolver-algorithm-specification">défini dans le solveur ESM</a>.
7. RESOLVE_ESM_MATCH(MATCH)

LOAD_PACKAGE_SELF(X, DIR)
1. Trouver la portée de package SCOPE la plus proche de DIR.
2. Si aucune portée n'a été trouvée, renvoyer.
3. Si SCOPE/package.json "exports" est nul ou indéfini, renvoyer.
4. Si SCOPE/package.json "name" n'est pas le premier segment de X, renvoyer.
5. soit MATCH = PACKAGE_EXPORTS_RESOLVE(pathToFileURL(SCOPE),
   "." + X.slice("name".length), `package.json` "exports", ["node", "require"])
   <a href="esm#resolver-algorithm-specification">défini dans le solveur ESM</a>.
6. RESOLVE_ESM_MATCH(MATCH)

RESOLVE_ESM_MATCH(MATCH)
1. soit RESOLVED_PATH = fileURLToPath(MATCH)
2. Si le fichier à RESOLVED_PATH existe, charger RESOLVED_PATH selon le format de son extension. STOP
3. LANCER "non trouvé"

Mise en cache

Les modules sont mis en cache après leur premier chargement. Cela signifie (entre autres) que chaque appel à require('foo') retournera exactement le même objet s'il est résolu vers le même fichier.

À condition que require.cache ne soit pas modifié, plusieurs appels à require('foo') n'entraîneront pas l'exécution multiple du code du module. C'est une fonctionnalité importante. Grâce à cela, des objets « partiellement terminés » peuvent être retournés, permettant ainsi le chargement des dépendances transitives même lorsqu'elles provoquent des cycles.

Pour qu'un module exécute du code plusieurs fois, exportez une fonction et appelez cette fonction.

Avertissements concernant la mise en cache des modules

Les modules sont mis en cache en fonction du nom de fichier résolu. Étant donné que les modules peuvent être résolus vers un nom de fichier différent en fonction de l'emplacement du module appelant (chargement à partir des dossiers node_modules), il n'est pas garanti que require('foo') retournera toujours exactement le même objet s'il est résolu vers des fichiers différents.

De plus, sur les systèmes de fichiers ou les systèmes d'exploitation ne respectant pas la casse, différents noms de fichiers résolus peuvent pointer vers le même fichier, mais le cache les traitera toujours comme des modules différents et rechargera le fichier plusieurs fois. Par exemple, require('./foo') et require('./FOO') retournent deux objets différents, indépendamment du fait que ./foo et ./FOO soient ou non le même fichier.

Modules intégrés

[Historique]

VersionModifications
v16.0.0, v14.18.0Ajout de la prise en charge de l'importation node: à require(...).

Node.js possède plusieurs modules compilés dans le binaire. Ces modules sont décrits plus en détail ailleurs dans cette documentation.

Les modules intégrés sont définis dans la source Node.js et se trouvent dans le dossier lib/.

Les modules intégrés peuvent être identifiés à l'aide du préfixe node:, auquel cas il contourne le cache require. Par exemple, require('node:http') retournera toujours le module HTTP intégré, même s'il existe une entrée require.cache de ce nom.

Certains modules intégrés sont toujours chargés de préférence si leur identificateur est passé à require(). Par exemple, require('http') retournera toujours le module HTTP intégré, même s'il existe un fichier de ce nom. La liste des modules intégrés pouvant être chargés sans utiliser le préfixe node: est exposée dans module.builtinModules, listés sans le préfixe.

Modules intégrés avec préfixe node: obligatoire

Lorsqu'ils sont chargés par require(), certains modules intégrés doivent être demandés avec le préfixe node:. Cette exigence existe pour empêcher les nouveaux modules intégrés d'entrer en conflit avec les paquets de l'espace utilisateur qui ont déjà pris le nom. Actuellement, les modules intégrés qui nécessitent le préfixe node: sont :

La liste de ces modules est exposée dans module.builtinModules, y compris le préfixe.

Cycles

Lorsqu'il y a des appels require() circulaires, un module peut ne pas avoir fini de s'exécuter lorsqu'il est renvoyé.

Considérez cette situation :

a.js:

js
console.log('a starting')
exports.done = false
const b = require('./b.js')
console.log('in a, b.done = %j', b.done)
exports.done = true
console.log('a done')

b.js:

js
console.log('b starting')
exports.done = false
const a = require('./a.js')
console.log('in b, a.done = %j', a.done)
exports.done = true
console.log('b done')

main.js:

js
console.log('main starting')
const a = require('./a.js')
const b = require('./b.js')
console.log('in main, a.done = %j, b.done = %j', a.done, b.done)

Lorsque main.js charge a.js, puis a.js charge à son tour b.js. À ce moment-là, b.js essaie de charger a.js. Afin d'éviter une boucle infinie, une copie incomplète de l'objet exports de a.js est renvoyée au module b.js. b.js termine ensuite le chargement, et son objet exports est fourni au module a.js.

Au moment où main.js a chargé les deux modules, ils sont tous les deux terminés. La sortie de ce programme serait donc :

bash
$ node main.js
main starting
a starting
b starting
in b, a.done = false
b done
in a, b.done = true
a done
in main, a.done = true, b.done = true

Une planification minutieuse est nécessaire pour permettre aux dépendances de modules cycliques de fonctionner correctement au sein d'une application.

Modules de fichiers

Si le nom de fichier exact n'est pas trouvé, Node.js tentera de charger le nom de fichier requis avec les extensions ajoutées : .js, .json, et enfin .node. Lors du chargement d'un fichier ayant une extension différente (par exemple, .cjs), son nom complet doit être passé à require(), y compris son extension de fichier (par exemple, require('./file.cjs')).

Les fichiers .json sont analysés comme des fichiers texte JSON, les fichiers .node sont interprétés comme des modules d'extension compilés chargés avec process.dlopen(). Les fichiers utilisant une autre extension (ou aucune extension) sont analysés comme des fichiers texte JavaScript. Reportez-vous à la section Détermination du système de modules pour comprendre quel objectif d'analyse sera utilisé.

Un module requis préfixé par / est un chemin absolu vers le fichier. Par exemple, require('/home/marco/foo.js') chargera le fichier situé à /home/marco/foo.js.

Un module requis préfixé par './' est relatif au fichier appelant require(). C'est-à-dire que circle.js doit se trouver dans le même répertoire que foo.js pour que require('./circle') le trouve.

Sans un préfixe /, './' ou '../' pour indiquer un fichier, le module doit être soit un module principal, soit chargé à partir d'un dossier node_modules.

Si le chemin donné n'existe pas, require() lèvera une erreur MODULE_NOT_FOUND.

Dossiers comme modules

[Stable : 3 - Hérité]

Stable : 3 Stabilité : 3 - Hérité : Utilisez plutôt les exportations de sous-chemins ou les importations de sous-chemins.

Il existe trois manières dont un dossier peut être passé à require() comme argument.

La première consiste à créer un fichier package.json à la racine du dossier, qui spécifie un module main. Un exemple de fichier package.json pourrait ressembler à ceci :

json
{ "name": "some-library", "main": "./lib/some-library.js" }

Si cela se trouvait dans un dossier à ./some-library, alors require('./some-library') tenterait de charger ./some-library/lib/some-library.js.

S'il n'y a pas de fichier package.json présent dans le répertoire, ou si l'entrée "main" est manquante ou ne peut pas être résolue, alors Node.js tentera de charger un fichier index.js ou index.node à partir de ce répertoire. Par exemple, s'il n'y avait pas de fichier package.json dans l'exemple précédent, alors require('./some-library') tenterait de charger :

  • ./some-library/index.js
  • ./some-library/index.node

Si ces tentatives échouent, Node.js signalera que le module entier est manquant avec l'erreur par défaut :

bash
Error: Cannot find module 'some-library'

Dans les trois cas ci-dessus, un appel import('./some-library') entraînerait une erreur ERR_UNSUPPORTED_DIR_IMPORT. L'utilisation des exportations de sous-chemins ou des importations de sous-chemins des packages peut fournir les mêmes avantages d'organisation du confinement que les dossiers en tant que modules, et fonctionner pour require et import.

Chargement depuis les dossiers node_modules

Si l'identificateur de module passé à require() n'est pas un module intégré, et ne commence pas par '/', '../', ou './', alors Node.js commence par le répertoire du module courant, ajoute /node_modules, et tente de charger le module depuis cet emplacement. Node.js n'ajoutera pas node_modules à un chemin se terminant déjà par node_modules.

S'il n'est pas trouvé là, alors il se déplace vers le répertoire parent, et ainsi de suite, jusqu'à ce que la racine du système de fichiers soit atteinte.

Par exemple, si le fichier situé à '/home/ry/projects/foo.js' appelle require('bar.js'), alors Node.js recherchera aux emplacements suivants, dans cet ordre :

  • /home/ry/projects/node_modules/bar.js
  • /home/ry/node_modules/bar.js
  • /home/node_modules/bar.js
  • /node_modules/bar.js

Cela permet aux programmes de localiser leurs dépendances, afin qu'elles ne soient pas en conflit.

Il est possible de requérir des fichiers spécifiques ou des sous-modules distribués avec un module en incluant un suffixe de chemin après le nom du module. Par exemple, require('example-module/path/to/file') résoudrait path/to/file par rapport à l'emplacement de example-module. Le chemin suffixé suit la même sémantique de résolution de module.

Chargement depuis les dossiers globaux

Si la variable d'environnement NODE_PATH est définie sur une liste de chemins absolus séparés par des deux-points, alors Node.js recherchera ces chemins pour les modules s'ils ne sont pas trouvés ailleurs.

Sous Windows, NODE_PATH est délimité par des points-virgules (;) au lieu de deux-points.

NODE_PATH a été initialement créé pour prendre en charge le chargement de modules à partir de chemins variés avant que l'algorithme actuel de résolution de module ne soit défini.

NODE_PATH est toujours pris en charge, mais est moins nécessaire maintenant que l'écosystème Node.js s'est stabilisé sur une convention pour localiser les modules dépendants. Parfois, les déploiements qui reposent sur NODE_PATH présentent un comportement surprenant lorsque les personnes ignorent que NODE_PATH doit être défini. Parfois, les dépendances d'un module changent, ce qui provoque le chargement d'une version différente (ou même d'un module différent) lors de la recherche de NODE_PATH.

De plus, Node.js recherchera dans la liste suivante de DOSSIERS_GLOBAUX :

  • 1: $HOME/.node_modules
  • 2: $HOME/.node_libraries
  • 3: $PREFIX/lib/node

$HOME est le répertoire personnel de l'utilisateur, et $PREFIX est le node_prefix configuré par Node.js.

Ceci est principalement dû à des raisons historiques.

Il est fortement recommandé de placer les dépendances dans le dossier node_modules local. Celles-ci seront chargées plus rapidement et de manière plus fiable.

L'enveloppe du module

Avant l'exécution du code d'un module, Node.js l'enveloppe dans une fonction qui ressemble à ceci :

js
;(function (exports, require, module, __filename, __dirname) {
  // Le code du module se trouve ici
})

En procédant ainsi, Node.js accomplit plusieurs choses :

  • Il maintient les variables de niveau supérieur (définies avec var, const ou let) dans l'étendue du module plutôt que dans l'objet global.
  • Il permet de fournir des variables ayant une apparence globale mais qui sont en réalité spécifiques au module, telles que :
    • Les objets module et exports que l'implémenteur peut utiliser pour exporter des valeurs depuis le module.
    • Les variables de commodité __filename et __dirname, contenant respectivement le nom de fichier absolu et le chemin d'accès au répertoire du module.

L'étendue du module

__dirname

Ajouté dans : v0.1.27

Le nom du répertoire du module courant. Il s'agit de la même chose que path.dirname() de __filename.

Exemple : exécution de node example.js depuis /Users/mjr

js
console.log(__dirname)
// Affiche : /Users/mjr
console.log(path.dirname(__filename))
// Affiche : /Users/mjr

__filename

Ajouté dans : v0.0.1

Le nom de fichier du module courant. Il s'agit du chemin absolu du fichier du module courant, avec les liens symboliques résolus.

Pour un programme principal, ce n'est pas forcément le même que le nom de fichier utilisé dans la ligne de commande.

Voir __dirname pour le nom du répertoire du module courant.

Exemples :

Exécution de node example.js depuis /Users/mjr

js
console.log(__filename)
// Affiche : /Users/mjr/example.js
console.log(__dirname)
// Affiche : /Users/mjr

Étant donné deux modules : a et b, où b est une dépendance de a et il existe une structure de répertoires :

  • /Users/mjr/app/a.js
  • /Users/mjr/app/node_modules/b/b.js

Les références à __filename dans b.js renverront /Users/mjr/app/node_modules/b/b.js tandis que les références à __filename dans a.js renverront /Users/mjr/app/a.js.

exports

Ajouté dans : v0.1.12

Une référence à module.exports plus courte à taper. Consultez la section sur le raccourci exports pour plus de détails sur quand utiliser exports et quand utiliser module.exports.

module

Ajouté dans : v0.1.16

Une référence au module courant, consultez la section sur l'objet module. En particulier, module.exports est utilisé pour définir ce qu'un module exporte et met à disposition via require().

require(id)

Ajouté dans : v0.1.13

Utilisé pour importer des modules, JSON et des fichiers locaux. Les modules peuvent être importés depuis node_modules. Les modules locaux et les fichiers JSON peuvent être importés en utilisant un chemin relatif (par exemple : ./, ./foo, ./bar/baz, ../foo) qui sera résolu par rapport au répertoire nommé par __dirname (s'il est défini) ou le répertoire de travail courant. Les chemins relatifs de style POSIX sont résolus de manière indépendante du système d'exploitation, ce qui signifie que les exemples ci-dessus fonctionneront sous Windows de la même manière que sous les systèmes Unix.

js
// Importation d'un module local avec un chemin relatif à `__dirname` ou au répertoire de travail courant. (Sous Windows, cela correspondrait à .\path\myLocalModule.)
const myLocalModule = require('./path/myLocalModule')

// Importation d'un fichier JSON :
const jsonData = require('./path/filename.json')

// Importation d'un module depuis node_modules ou un module intégré Node.js :
const crypto = require('node:crypto')

require.cache

Ajouté dans : v0.3.0

Les modules sont mis en cache dans cet objet lorsqu'ils sont requis. En supprimant une paire clé-valeur de cet objet, le prochain require rechargera le module. Cela ne s'applique pas aux modules natifs, pour lesquels un rechargement entraînera une erreur.

L'ajout ou le remplacement d'entrées est également possible. Ce cache est vérifié avant les modules intégrés et si un nom correspondant à un module intégré est ajouté au cache, seules les appels require préfixés par node: vont recevoir le module intégré. À utiliser avec précaution !

js
const assert = require('node:assert')
const realFs = require('node:fs')

const fakeFs = {}
require.cache.fs = { exports: fakeFs }

assert.strictEqual(require('fs'), fakeFs)
assert.strictEqual(require('node:fs'), realFs)

require.extensions

Ajouté dans : v0.3.0

Déprécié depuis : v0.10.6

[Stable : 0 - Déprécié]

Stable : 0 Stabilité : 0 - Déprécié

Instruit require sur la façon de gérer certaines extensions de fichiers.

Traiter les fichiers avec l'extension .sjs comme .js :

js
require.extensions['.sjs'] = require.extensions['.js']

Déprécié. Par le passé, cette liste a été utilisée pour charger des modules non JavaScript dans Node.js en les compilant à la demande. Cependant, en pratique, il existe de bien meilleures façons de procéder, telles que le chargement de modules via un autre programme Node.js ou leur compilation en JavaScript à l'avance.

Évitez d'utiliser require.extensions. Son utilisation peut entraîner des bogues subtils et la résolution des extensions devient plus lente à chaque extension enregistrée.

require.main

Ajouté dans : v0.1.17

L'objet Module représentant le script d'entrée chargé lors du lancement du processus Node.js, ou undefined si le point d'entrée du programme n'est pas un module CommonJS. Voir "Accès au module principal".

Dans le script entry.js :

js
console.log(require.main)
bash
node entry.js
js
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' ] }

require.resolve(request[, options])

[Historique]

VersionModifications
v8.9.0L'option paths est désormais prise en charge.
v0.3.0Ajouté dans : v0.3.0
  • request <chaîne de caractères> Le chemin du module à résoudre.

  • options <Objet>

    • paths <tableau de chaînes de caractères> Chemins pour résoudre l'emplacement du module à partir de. Si présents, ces chemins sont utilisés à la place des chemins de résolution par défaut, à l'exception des DOSSIERS_GLOBALS comme $HOME/.node_modules, qui sont toujours inclus. Chacun de ces chemins est utilisé comme point de départ pour l'algorithme de résolution de module, ce qui signifie que la hiérarchie node_modules est vérifiée à partir de cet emplacement.
  • Retourne : <chaîne de caractères>

Utilisez le mécanisme interne require() pour rechercher l'emplacement d'un module, mais au lieu de charger le module, retournez simplement le nom de fichier résolu.

Si le module est introuvable, une erreur MODULE_NOT_FOUND est levée.

require.resolve.paths(request)

Ajouté dans : v8.9.0

Retourne un tableau contenant les chemins parcourus lors de la résolution de request ou null si la chaîne request fait référence à un module principal, par exemple http ou fs.

L'objet module

Ajouté dans : v0.1.16

Dans chaque module, la variable libre module est une référence à l'objet représentant le module courant. Pour plus de commodité, module.exports est également accessible via le module global exports. module n'est pas réellement un global, mais plutôt local à chaque module.

module.children

Ajouté dans : v0.1.16

Les objets module requis pour la première fois par celui-ci.

module.exports

Ajouté dans : v0.1.16

L'objet module.exports est créé par le système Module. Parfois, ce n'est pas acceptable ; beaucoup veulent que leur module soit une instance d'une certaine classe. Pour ce faire, affectez l'objet d'exportation souhaité à module.exports. L'affectation de l'objet souhaité à exports se contentera de relire la variable locale exports, ce qui n'est probablement pas ce qui est souhaité.

Par exemple, supposons que nous créions un module appelé a.js :

js
const EventEmitter = require('node:events')

module.exports = new EventEmitter()

// Effectuez un certain travail, et après un certain temps, émettez
// l'événement 'ready' depuis le module lui-même.
setTimeout(() => {
  module.exports.emit('ready')
}, 1000)

Ensuite, dans un autre fichier, nous pourrions faire :

js
const a = require('./a')
a.on('ready', () => {
  console.log('le module "a" est prêt')
})

L'affectation à module.exports doit être effectuée immédiatement. Cela ne peut pas être fait dans les rappels. Cela ne fonctionne pas :

x.js :

js
setTimeout(() => {
  module.exports = { a: 'hello' }
}, 0)

y.js :

js
const x = require('./x')
console.log(x.a)

Raccourci exports

Ajouté dans : v0.1.16

La variable exports est disponible dans la portée de niveau fichier d’un module et se voit assigner la valeur de module.exports avant l’évaluation du module.

Elle permet un raccourci, de sorte que module.exports.f = ... puisse s’écrire plus succinctement exports.f = .... Cependant, sachez que, comme toute variable, si une nouvelle valeur est assignée à exports, elle n’est plus liée à module.exports :

js
module.exports.hello = true // Exporté depuis require du module
exports = { hello: false } // Non exporté, seulement disponible dans le module

Lorsque la propriété module.exports est complètement remplacée par un nouvel objet, il est courant de réassigner également exports :

js
module.exports = exports = function Constructor() {
  // ... etc.
}

Pour illustrer le comportement, imaginez cette implémentation hypothétique de require(), qui est assez similaire à ce qui est réellement fait par require() :

js
function require(/* ... */) {
  const module = { exports: {} }
  ;((module, exports) => {
    // Code du module ici. Dans cet exemple, définir une fonction.
    function someFunc() {}
    exports = someFunc
    // À ce stade, exports n’est plus un raccourci vers module.exports, et
    // ce module exportera toujours un objet par défaut vide.
    module.exports = someFunc
    // À ce stade, le module exportera maintenant someFunc, au lieu de
    // l’objet par défaut.
  })(module, module.exports)
  return module.exports
}

module.filename

Ajouté dans : v0.1.16

Le nom de fichier entièrement résolu du module.

module.id

Ajouté dans : v0.1.16

L’identifiant du module. Typiquement, il s’agit du nom de fichier entièrement résolu.

module.isPreloading

Ajouté dans : v15.4.0, v14.17.0

  • Type : <boolean> true si le module s’exécute pendant la phase de préchargement Node.js.

module.loaded

Ajouté dans : v0.1.16

Indique si le module a fini de se charger ou est en cours de chargement.

module.parent

Ajouté dans : v0.1.16

Déprécié depuis : v14.6.0, v12.19.0

[Stable : 0 - Déprécié]

Stable : 0 Stabilité : 0 - Déprécié : Veuillez utiliser require.main et module.children à la place.

Le module qui a d'abord requis celui-ci, ou null si le module courant est le point d'entrée du processus courant, ou undefined si le module a été chargé par quelque chose qui n'est pas un module CommonJS (par exemple : REPL ou import).

module.path

Ajouté dans : v11.14.0

Le nom du répertoire du module. Ceci est généralement identique à path.dirname() de module.id.

module.paths

Ajouté dans : v0.4.0

Les chemins de recherche pour le module.

module.require(id)

Ajouté dans : v0.5.1

La méthode module.require() fournit un moyen de charger un module comme si require() avait été appelé depuis le module d'origine.

Pour ce faire, il est nécessaire d'obtenir une référence à l'objet module. Puisque require() retourne module.exports, et que le module est généralement uniquement disponible dans le code d'un module spécifique, il doit être explicitement exporté pour pouvoir être utilisé.

L'objet Module

Cette section a été déplacée vers Modules : module principal module.

Prise en charge de Source map v3

Cette section a été déplacée vers Modules : module principal module.