Skip to content

Modules : modules ECMAScript

[Historique]

VersionModifications
v23.1.0Les attributs d'importation ne sont plus expérimentaux.
v22.0.0Abandon du support des assertions d'importation.
v21.0.0, v20.10.0, v18.20.0Ajout du support expérimental des attributs d'importation.
v20.0.0, v18.19.0Les hooks de personnalisation des modules sont exécutés hors du thread principal.
v18.6.0, v16.17.0Ajout du support pour le chaînage des hooks de personnalisation des modules.
v17.1.0, v16.14.0Ajout du support expérimental des assertions d'importation.
v17.0.0, v16.12.0Consolidation des hooks de personnalisation, suppression des hooks getFormat, getSource, transformSource, et getGlobalPreloadCode, ajout des hooks load et globalPreload, autorisation du retour de format depuis les hooks resolve ou load.
v14.8.0Suppression du drapeau Top-Level Await.
v15.3.0, v14.17.0, v12.22.0Stabilisation de l'implémentation des modules.
v14.13.0, v12.20.0Support pour la détection des exportations nommées CommonJS.
v14.0.0, v13.14.0, v12.20.0Suppression de l'avertissement sur les modules expérimentaux.
v13.2.0, v12.17.0Le chargement des modules ECMAScript ne nécessite plus d'indicateur de ligne de commande.
v12.0.0Ajout du support pour les modules ES utilisant l'extension de fichier .js via le champ "type" de package.json.
v8.5.0Ajouté dans : v8.5.0

[Stable : 2 - Stable]

Stable : 2 Stabilité : 2 - Stable

Introduction

Les modules ECMAScript sont le format standard officiel pour encapsuler le code JavaScript afin de le réutiliser. Les modules sont définis à l'aide d'un ensemble d'instructions import et export.

L'exemple suivant d'un module ES exporte une fonction :

js
// addTwo.mjs
function addTwo(num) {
  return num + 2
}

export { addTwo }

L'exemple suivant d'un module ES importe la fonction depuis addTwo.mjs :

js
// app.mjs
import { addTwo } from './addTwo.mjs'

// Affiche : 6
console.log(addTwo(4))

Node.js supporte pleinement les modules ECMAScript tels qu'ils sont actuellement spécifiés et assure l'interopérabilité entre ceux-ci et son format de module original, CommonJS.

Activation

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

Les auteurs peuvent indiquer à Node.js d’interpréter JavaScript comme un module ES via l’extension de fichier .mjs, le champ "type" de package.json avec la valeur "module", ou l’indicateur --input-type avec la valeur "module". Ce sont des marqueurs explicites indiquant que le code est destiné à être exécuté comme un module ES.

Inversement, les auteurs peuvent explicitement indiquer à Node.js d’interpréter JavaScript comme CommonJS via l’extension de fichier .cjs, le champ "type" de package.json avec la valeur "commonjs", ou l’indicateur --input-type avec la valeur "commonjs".

Lorsque le code ne comporte pas de marqueurs explicites pour l’un ou l’autre système de modules, Node.js inspecte le code source d’un module pour rechercher la syntaxe des modules ES. Si une telle syntaxe est trouvée, Node.js exécutera le code comme un module ES ; sinon, il exécutera le module comme CommonJS. Pour plus de détails, voir Détermination du système de modules.

Packages

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

Spécificateurs import

Terminologie

Le spécificateur d’une instruction import est la chaîne de caractères après le mot clé from, par exemple 'node:path' dans import { sep } from 'node:path'. Les spécificateurs sont également utilisés dans les instructions export from, et comme argument d’une expression import().

Il existe trois types de spécificateurs :

  • Spécificateurs relatifs comme './startup.js' ou '../config.mjs'. Ils font référence à un chemin relatif à l’emplacement du fichier importateur. L’extension de fichier est toujours nécessaire pour ceux-ci.
  • Spécificateurs nus comme 'some-package' ou 'some-package/shuffle'. Ils peuvent faire référence au point d’entrée principal d’un package par le nom du package, ou à un module de fonctionnalité spécifique au sein d’un package préfixé par le nom du package selon les exemples respectifs. L’inclusion de l’extension de fichier n’est nécessaire que pour les packages sans champ "exports".
  • Spécificateurs absolus comme 'file:///opt/nodejs/config.js'. Ils font référence directement et explicitement à un chemin complet.

Les résolutions de spécificateurs nus sont gérées par l’algorithme de résolution et de chargement des modules Node.js. Toutes les autres résolutions de spécificateurs sont toujours uniquement résolues avec la sémantique de résolution d’URL relative standard URL.

Comme dans CommonJS, les fichiers de modules au sein des packages peuvent être accessibles en ajoutant un chemin au nom du package, sauf si le fichier package.json du package contient un champ "exports", auquel cas les fichiers au sein des packages ne peuvent être accessibles que via les chemins définis dans "exports".

Pour plus de détails sur ces règles de résolution de package qui s’appliquent aux spécificateurs nus dans la résolution de modules Node.js, consultez la documentation des packages.

Extensions de fichiers obligatoires

Une extension de fichier doit être fournie lors de l'utilisation du mot clé import pour résoudre les spécificateurs relatifs ou absolus. Les index de répertoire (par exemple, './startup/index.js') doivent également être entièrement spécifiés.

Ce comportement correspond à celui d' import dans les environnements de navigateur, en supposant un serveur typiquement configuré.

URLs

Les modules ES sont résolus et mis en cache en tant qu'URL. Cela signifie que les caractères spéciaux doivent être encodés en pourcentage, tels que # avec %23 et ? avec %3F.

Les schémas d'URL file:, node: et data: sont supportés. Un spécificateur comme 'https://example.com/app.js' n'est pas supporté nativement dans Node.js sauf si vous utilisez un chargeur HTTPS personnalisé.

URLs file:

Les modules sont chargés plusieurs fois si le spécificateur import utilisé pour les résoudre a une requête ou un fragment différent.

js
import './foo.mjs?query=1' // charge ./foo.mjs avec la requête "?query=1"
import './foo.mjs?query=2' // charge ./foo.mjs avec la requête "?query=2"

La racine du volume peut être référencée via /, // ou file:///. Étant donné les différences entre URL et la résolution de chemin (telles que les détails de l'encodage en pourcentage), il est recommandé d'utiliser url.pathToFileURL lors de l'importation d'un chemin.

Imports data:

Ajouté dans : v12.10.0

Les URL data: sont prises en charge pour l'importation avec les types MIME suivants :

  • text/javascript pour les modules ES
  • application/json pour JSON
  • application/wasm pour Wasm
js
import 'data:text/javascript,console.log("hello!");';
import _ from 'data:application/json,"world!"' with { type: 'json' };

Les URL data: ne résolvent les spécificateurs nus que pour les modules intégrés et les spécificateurs absolus. La résolution des spécificateurs relatifs ne fonctionne pas car data: n'est pas un schéma spécial. Par exemple, la tentative de chargement de ./foo à partir de data:text/javascript,import "./foo"; échoue car il n'existe aucun concept de résolution relative pour les URL data:.

Imports node:

[Historique]

VersionModifications
v16.0.0, v14.18.0Ajout du support des imports node: à require(...).
v14.13.1, v12.20.0Ajouté dans : v14.13.1, v12.20.0

Les URL node: sont supportées comme moyen alternatif pour charger les modules intégrés de Node.js. Ce schéma d'URL permet aux modules intégrés d'être référencés par des chaînes d'URL absolues valides.

js
import fs from 'node:fs/promises'

Attributs d'import

[Historique]

VersionModifications
v21.0.0, v20.10.0, v18.20.0Passage des assertions d'import aux attributs d'import.
v17.1.0, v16.14.0Ajouté dans : v17.1.0, v16.14.0

[Stable : 2 - Stable]

Stable : 2 Stabilité : 2 - Stable

Les attributs d'import sont une syntaxe en ligne pour les instructions d'import de module afin de transmettre plus d'informations en plus du spécificateur de module.

js
import fooData from './foo.json' with { type: 'json' };

const { default: barData } =
  await import('./bar.json', { with: { type: 'json' } });

Node.js ne supporte que l'attribut type, pour lequel il supporte les valeurs suivantes :

Attribut typeNécessaire pour
'json'Modules JSON

L'attribut type: 'json' est obligatoire lors de l'importation de modules JSON.

Modules intégrés

Les modules intégrés fournissent des exportations nommées de leur API publique. Une exportation par défaut est également fournie, qui est la valeur des exportations CommonJS. L'exportation par défaut peut être utilisée, entre autres, pour modifier les exportations nommées. Les exportations nommées des modules intégrés ne sont mises à jour qu'en appelant module.syncBuiltinESMExports().

js
import EventEmitter from 'node:events'
const e = new EventEmitter()
js
import { readFile } from 'node:fs'
readFile('./foo.txt', (err, source) => {
  if (err) {
    console.error(err)
  } else {
    console.log(source)
  }
})
js
import fs, { readFileSync } from 'node:fs'
import { syncBuiltinESMExports } from 'node:module'
import { Buffer } from 'node:buffer'

fs.readFileSync = () => Buffer.from('Hello, ESM')
syncBuiltinESMExports()

fs.readFileSync === readFileSync

Expressions import()

import() dynamique](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import) est pris en charge dans les modules CommonJS et ES. Dans les modules CommonJS, il peut être utilisé pour charger des modules ES.

import.meta

La méta-propriété import.meta est un Objet qui contient les propriétés suivantes. Elle n'est prise en charge que dans les modules ES.

import.meta.dirname

Ajouté dans : v21.2.0, v20.11.0

[Stable : 1 - Expérimental]

Stable : 1 Stabilité : 1.2 - Candidate à la publication

import.meta.filename

Ajouté dans : v21.2.0, v20.11.0

[Stable : 1 - Expérimental]

Stable : 1 Stabilité : 1.2 - Candidate à la publication

import.meta.url

Ceci est défini exactement de la même manière que dans les navigateurs, fournissant l'URL du fichier du module actuel.

Cela permet des modèles utiles tels que le chargement de fichiers relatifs :

js
import { readFileSync } from 'node:fs'
const buffer = readFileSync(new URL('./data.proto', import.meta.url))

import.meta.resolve(specifier)

[Historique]

VersionModifications
v20.6.0, v18.19.0N'est plus derrière l'indicateur CLI --experimental-import-meta-resolve, sauf pour le paramètre parentURL non standard.
v20.6.0, v18.19.0Cette API ne lève plus d'exception lorsqu'elle cible des URL file: qui ne correspondent pas à un fichier existant sur le système de fichiers local.
v20.0.0, v18.19.0Cette API renvoie désormais une chaîne de caractères de manière synchrone au lieu d'une promesse.
v16.2.0, v14.18.0Ajout de la prise en charge de l'objet URL WHATWG au paramètre parentURL.
v13.9.0, v12.16.2Ajouté dans : v13.9.0, v12.16.2

[Stable : 1 - Expérimental]

Stable : 1 Stabilité : 1.2 - Candidate à la publication

import.meta.resolve est une fonction de résolution relative au module limitée à chaque module, renvoyant la chaîne d'URL.

js
const dependencyAsset = import.meta.resolve('component-lib/asset.css')
// file:///app/node_modules/component-lib/asset.css
import.meta.resolve('./dep.js')
// file:///app/dep.js

Toutes les fonctionnalités de la résolution de module Node.js sont prises en charge. Les résolutions de dépendances sont soumises aux résolutions d'exportations autorisées dans le package.

Avertissements :

  • Cela peut entraîner des opérations synchrones sur le système de fichiers, ce qui peut avoir un impact sur les performances de manière similaire à require.resolve.
  • Cette fonctionnalité n'est pas disponible dans les chargeurs personnalisés (cela créerait une interblocage).

API non standard :

Lorsque vous utilisez l'indicateur --experimental-import-meta-resolve, cette fonction accepte un deuxième argument :

  • parent <chaîne de caractères> | <URL> Une URL de module parent absolue facultative à partir de laquelle résoudre. Valeur par défaut : import.meta.url

Interopérabilité avec CommonJS

Instructions import

Une instruction import peut référencer un module ES ou un module CommonJS. Les instructions import ne sont autorisées que dans les modules ES, mais les expressions import() dynamiques sont prises en charge dans CommonJS pour le chargement des modules ES.

Lors de l'importation de modules CommonJS, l'objet module.exports est fourni comme export par défaut. Des exportations nommées peuvent être disponibles, fournies par analyse statique pour une meilleure compatibilité avec l'écosystème.

require

Le module CommonJS require ne prend actuellement en charge que le chargement synchrone des modules ES (c'est-à-dire les modules ES qui n'utilisent pas await au niveau supérieur).

Voir Chargement des modules ECMAScript à l'aide de require() pour plus de détails.

Espaces de noms CommonJS

[Historique]

VersionModifications
v23.0.0Ajout du marqueur d'exportation 'module.exports' aux espaces de noms CJS.
v14.13.0Ajouté dans : v14.13.0

Les modules CommonJS consistent en un objet module.exports qui peut être de n'importe quel type.

Pour prendre en charge cela, lors de l'importation de CommonJS à partir d'un module ECMAScript, un wrapper d'espace de noms pour le module CommonJS est construit, qui fournit toujours une clé d'exportation default pointant vers la valeur module.exports de CommonJS.

De plus, une analyse statique heuristique est effectuée sur le texte source du module CommonJS pour obtenir une liste statique des exportations afin de fournir les valeurs sur module.exports dans l'espace de noms. Ceci est nécessaire car ces espaces de noms doivent être construits avant l'évaluation du module CJS.

Ces objets d'espace de noms CommonJS fournissent également l'exportation default comme exportation nommée 'module.exports', afin d'indiquer sans ambiguïté que leur représentation dans CommonJS utilise cette valeur, et non la valeur de l'espace de noms. Cela reflète la sémantique de la gestion du nom d'exportation 'module.exports' dans la prise en charge de l'interopérabilité require(esm).

Lors de l'importation d'un module CommonJS, il peut être importé de manière fiable à l'aide de l'importation par défaut du module ES ou de sa syntaxe sucrée correspondante :

js
import { default as cjs } from 'cjs'
// Identique à ce qui précède
import cjsSugar from 'cjs'

console.log(cjs)
console.log(cjs === cjsSugar)
// Affiche :
//   <module.exports>
//   true

Cet objet exotique d'espace de noms de module peut être directement observé en utilisant import * as m from 'cjs' ou une importation dynamique :

js
import * as m from 'cjs'
console.log(m)
console.log(m === (await import('cjs')))
// Affiche :
//   [Module] { default: <module.exports>, 'module.exports': <module.exports> }
//   true

Pour une meilleure compatibilité avec l'utilisation existante dans l'écosystème JS, Node.js tente en outre de déterminer les exportations nommées CommonJS de chaque module CommonJS importé pour les fournir comme exportations de module ES séparées à l'aide d'un processus d'analyse statique.

Par exemple, considérons un module CommonJS écrit :

js
// cjs.cjs
exports.name = 'exported'

Le module précédent prend en charge les importations nommées dans les modules ES :

js
import { name } from './cjs.cjs'
console.log(name)
// Affiche : 'exported'

import cjs from './cjs.cjs'
console.log(cjs)
// Affiche : { name: 'exported' }

import * as m from './cjs.cjs'
console.log(m)
// Affiche :
//   [Module] {
//     default: { name: 'exported' },
//     'module.exports': { name: 'exported' },
//     name: 'exported'
//   }

Comme on peut le voir dans le dernier exemple de l'objet exotique de l'espace de noms du module étant enregistré, l'exportation name est copiée à partir de l'objet module.exports et définie directement sur l'espace de noms du module ES lorsque le module est importé.

Les mises à jour de liaison active ou les nouvelles exportations ajoutées à module.exports ne sont pas détectées pour ces exportations nommées.

La détection des exportations nommées est basée sur des modèles de syntaxe courants, mais ne détecte pas toujours correctement les exportations nommées. Dans ces cas, l'utilisation du formulaire d'importation par défaut décrit ci-dessus peut être une meilleure option.

La détection des exportations nommées couvre de nombreux modèles d'exportation courants, les modèles de réexportation et les sorties des outils de build et des transpileurs. Voir cjs-module-lexer pour la sémantique exacte implémentée.

Différences entre les modules ES et CommonJS

Pas de require, exports, ou module.exports

Dans la plupart des cas, l'instruction import des modules ES peut être utilisée pour charger des modules CommonJS.

Si nécessaire, une fonction require peut être construite au sein d'un module ES en utilisant module.createRequire().

Pas de __filename ou __dirname

Ces variables CommonJS ne sont pas disponibles dans les modules ES.

Les cas d'utilisation de __filename et __dirname peuvent être reproduits via import.meta.filename et import.meta.dirname.

Pas de chargement d'extensions

Les extensions ne sont pas actuellement prises en charge avec les importations de modules ES.

Elles peuvent être chargées à la place avec module.createRequire() ou process.dlopen.

Pas de require.resolve

La résolution relative peut être gérée via new URL('./local', import.meta.url).

Pour un remplacement complet de require.resolve, il existe l'API import.meta.resolve.

Alternativement, module.createRequire() peut être utilisé.

Pas de NODE_PATH

NODE_PATH ne fait pas partie de la résolution des spécificateurs import. Veuillez utiliser des liens symboliques si ce comportement est souhaité.

Pas de require.extensions

require.extensions n'est pas utilisé par import. Des hooks de personnalisation de modules peuvent fournir un remplacement.

Pas de require.cache

require.cache n'est pas utilisé par import car le chargeur de modules ES possède son propre cache séparé.

Modules JSON

[Historique]

VersionModifications
v23.1.0Les modules JSON ne sont plus expérimentaux.

[Stable : 2 - Stable]

Stable : 2 Stabilité : 2 - Stable

Les fichiers JSON peuvent être référencés par import :

js
import packageConfig from './package.json' with { type: 'json' };

La syntaxe with { type: 'json' } est obligatoire ; voir Attributs d'importation.

Le JSON importé n'expose qu'une exportation default. Il n'y a pas de support pour les exportations nommées. Une entrée de cache est créée dans le cache CommonJS pour éviter les doublons. Le même objet est renvoyé dans CommonJS si le module JSON a déjà été importé depuis le même chemin.

Modules Wasm

[Stable : 1 - Expérimental]

Stable : 1 Stabilité : 1 - Expérimental

L'importation de modules WebAssembly est prise en charge avec l'indicateur --experimental-wasm-modules, permettant l'importation de fichiers .wasm comme des modules normaux tout en prenant en charge leurs importations de modules.

Cette intégration est conforme à la proposition d'intégration des modules ES pour WebAssembly.

Par exemple, un fichier index.mjs contenant :

js
import * as M from './module.wasm'
console.log(M)

exécuté sous :

bash
node --experimental-wasm-modules index.mjs

fournirait l'interface d'exportation pour l'instanciation de module.wasm.

await de niveau supérieur

Ajouté dans : v14.8.0

Le mot clé await peut être utilisé dans le corps de niveau supérieur d'un module ECMAScript.

En supposant un fichier a.mjs avec

js
export const five = await Promise.resolve(5)

Et un fichier b.mjs avec

js
import { five } from './a.mjs'

console.log(five) // Affiche `5`
bash
node b.mjs # fonctionne

Si une expression await de niveau supérieur ne se résout jamais, le processus node se terminera avec un code de statut 13 code de statut.

js
import { spawn } from 'node:child_process'
import { execPath } from 'node:process'

spawn(execPath, [
  '--input-type=module',
  '--eval',
  // Promise sans résolution :
  'await new Promise(() => {})',
]).once('exit', code => {
  console.log(code) // Affiche `13`
})

Chargeurs

L'ancienne documentation des chargeurs se trouve maintenant à Modules : Hooks de personnalisation.

Algorithme de résolution et de chargement

Fonctionnalités

Le solveur par défaut possède les propriétés suivantes :

  • Résolution basée sur FileURL comme utilisée par les modules ES
  • Résolution d'URL relatives et absolues
  • Pas d'extensions par défaut
  • Pas de principaux dossiers
  • Recherche de résolution de package de spécificateur nu via node_modules
  • Ne échoue pas sur les extensions ou protocoles inconnus
  • Peut éventuellement fournir un indice du format à la phase de chargement

Le chargeur par défaut possède les propriétés suivantes :

  • Prise en charge du chargement de modules intégrés via les URL node:
  • Prise en charge du chargement de modules « intégrés » via les URL data:
  • Prise en charge du chargement de modules file:
  • Échoue sur tout autre protocole URL
  • Échoue sur les extensions inconnues pour le chargement file: (ne prend en charge que .cjs, .js et .mjs)

Algorithme de résolution

L'algorithme de chargement d'un spécificateur de module ES est donné par la méthode ESM_RESOLVE ci-dessous. Il renvoie l'URL résolue pour un spécificateur de module relatif à un parentURL.

L'algorithme de résolution détermine l'URL complète résolue pour le chargement d'un module, ainsi que son format de module suggéré. L'algorithme de résolution ne détermine pas si le protocole de l'URL résolue peut être chargé, ni si les extensions de fichier sont autorisées ; ces validations sont appliquées par Node.js pendant la phase de chargement (par exemple, s'il a été demandé de charger une URL ayant un protocole autre que file:, data: ou node:).

L'algorithme tente également de déterminer le format du fichier en fonction de son extension (voir l'algorithme ESM_FILE_FORMAT ci-dessous). S'il ne reconnaît pas l'extension de fichier (par exemple, si ce n'est pas .mjs, .cjs ou .json), un format undefined est renvoyé, ce qui provoquera une erreur pendant la phase de chargement.

L'algorithme permettant de déterminer le format de module d'une URL résolue est fourni par ESM_FILE_FORMAT, qui renvoie le format de module unique pour chaque fichier. Le format "module" est renvoyé pour un module ECMAScript, tandis que le format "commonjs" est utilisé pour indiquer le chargement via le chargeur CommonJS hérité. Des formats supplémentaires tels que "addon" peuvent être ajoutés lors de futures mises à jour.

Dans les algorithmes suivants, toutes les erreurs de sous-routine sont propagées en tant qu'erreurs de ces routines de niveau supérieur, sauf indication contraire.

*defaultConditions* est le tableau de noms d'environnements conditionnels, ["node", "import"].

Le résolveur peut lever les erreurs suivantes :

  • Spécificateur de module invalide : le spécificateur de module est une URL, un nom de package ou un spécificateur de sous-chemin de package invalide.
  • Configuration de package invalide : la configuration package.json est invalide ou contient une configuration invalide.
  • Cible de package invalide : les exportations ou importations de package définissent un module cible pour le package qui est un type ou une cible de chaîne invalide.
  • Chemin de package non exporté : les exportations de package ne définissent pas ou n'autorisent pas un sous-chemin cible dans le package pour le module donné.
  • Importation de package non définie : les importations de package ne définissent pas le spécificateur.
  • Module introuvable : le package ou le module demandé n'existe pas.
  • Importation de répertoire non prise en charge : le chemin résolu correspond à un répertoire, qui n'est pas une cible prise en charge pour les importations de module.

Spécification de l'algorithme de résolution

ESM_RESOLVE(specifier, parentURL)

PACKAGE_RESOLVE(packageSpecifier, parentURL)

PACKAGE_SELF_RESOLVE(packageName, packageSubpath, parentURL)

PACKAGE_EXPORTS_RESOLVE(packageURL, subpath, exports, conditions)

PACKAGE_IMPORTS_RESOLVE(specifier, parentURL, conditions)

PACKAGE_IMPORTS_EXPORTS_RESOLVE(matchKey, matchObj, packageURL, isImports, conditions)

PATTERN_KEY_COMPARE(keyA, keyB)

PACKAGE_TARGET_RESOLVE(packageURL, target, patternMatch, isImports, conditions)

ESM_FILE_FORMAT(url)

LOOKUP_PACKAGE_SCOPE(url)

READ_PACKAGE_JSON(packageURL)

DETECT_MODULE_SYNTAX(source)

Personnalisation de l'algorithme de résolution des spécificateurs ESM

Les hooks de personnalisation des modules fournissent un mécanisme pour personnaliser l'algorithme de résolution des spécificateurs ESM. Un exemple qui fournit une résolution de style CommonJS pour les spécificateurs ESM est commonjs-extension-resolution-loader.