Skip to content

Moduli: Moduli ECMAScript

[Cronologia]

VersioneModifiche
v23.1.0Gli attributi di importazione non sono più sperimentali.
v22.0.0Rimosso il supporto per le asserzioni di importazione.
v21.0.0, v20.10.0, v18.20.0Aggiunto il supporto sperimentale per gli attributi di importazione.
v20.0.0, v18.19.0Gli hook di personalizzazione del modulo vengono eseguiti al di fuori del thread principale.
v18.6.0, v16.17.0Aggiunto il supporto per l'incatenamento degli hook di personalizzazione del modulo.
v17.1.0, v16.14.0Aggiunto il supporto sperimentale per le asserzioni di importazione.
v17.0.0, v16.12.0Consolidati gli hook di personalizzazione, rimossi gli hook getFormat, getSource, transformSource e getGlobalPreloadCode, aggiunti gli hook load e globalPreload, consentito di restituire format dagli hook resolve o load.
v14.8.0Rimosso il flag per Top-Level Await.
v15.3.0, v14.17.0, v12.22.0Stabilizzata l'implementazione dei moduli.
v14.13.0, v12.20.0Supporto per il rilevamento delle esportazioni denominate CommonJS.
v14.0.0, v13.14.0, v12.20.0Rimossa l'avvertenza sui moduli sperimentali.
v13.2.0, v12.17.0Il caricamento dei moduli ECMAScript non richiede più un flag da riga di comando.
v12.0.0Aggiunto il supporto per i moduli ES utilizzando l'estensione file .js tramite il campo "type" di package.json.
v8.5.0Aggiunto in: v8.5.0

[Stabile: 2 - Stabile]

Stabile: 2 Stabilità: 2 - Stabile

Introduzione

I moduli ECMAScript sono il formato standard ufficiale per impacchettare codice JavaScript per il riutilizzo. I moduli sono definiti utilizzando una varietà di istruzioni import e export.

L'esempio seguente di un modulo ES esporta una funzione:

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

export { addTwo }

L'esempio seguente di un modulo ES importa la funzione da addTwo.mjs:

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

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

Node.js supporta pienamente i moduli ECMAScript così come sono attualmente specificati e fornisce interoperabilità tra loro e il suo formato di modulo originale, CommonJS.

Abilitazione

Node.js ha due sistemi di moduli: moduli CommonJS e moduli ECMAScript.

Gli autori possono indicare a Node.js di interpretare JavaScript come un modulo ES tramite l'estensione del file .mjs, il campo package.json "type" con il valore "module" o il flag --input-type con il valore "module". Questi sono indicatori espliciti che il codice è destinato a essere eseguito come un modulo ES.

Inversamente, gli autori possono indicare esplicitamente a Node.js di interpretare JavaScript come CommonJS tramite l'estensione del file .cjs, il campo package.json "type" con il valore "commonjs" o il flag --input-type con il valore "commonjs".

Quando il codice manca di indicatori espliciti per entrambi i sistemi di moduli, Node.js ispezionerà il codice sorgente di un modulo per cercare la sintassi del modulo ES. Se viene trovata tale sintassi, Node.js eseguirà il codice come modulo ES; altrimenti, eseguirà il modulo come CommonJS. Vedere Determinazione del sistema di moduli per maggiori dettagli.

Pacchetti

Questa sezione è stata spostata a Moduli: Pacchetti.

Specificatori import

Terminologia

Lo specificatore di un'istruzione import è la stringa dopo la parola chiave from, ad es. 'node:path' in import { sep } from 'node:path'. Gli specificatori sono anche utilizzati nelle istruzioni export from e come argomento di un'espressione import().

Esistono tre tipi di specificatori:

  • Specificatori relativi come './startup.js' o '../config.mjs'. Si riferiscono a un percorso relativo alla posizione del file importatore. L'estensione del file è sempre necessaria per questi.
  • Specificatori nudi come 'some-package' o 'some-package/shuffle'. Possono fare riferimento al punto di ingresso principale di un pacchetto tramite il nome del pacchetto o a un modulo di funzionalità specifico all'interno di un pacchetto preceduto dal nome del pacchetto come da rispettivi esempi. Includere l'estensione del file è necessario solo per i pacchetti senza un campo "exports".
  • Specificatori assoluti come 'file:///opt/nodejs/config.js'. Si riferiscono direttamente ed esplicitamente a un percorso completo.

Le risoluzioni degli specificatori nudi sono gestite dall'algoritmo di risoluzione e caricamento dei moduli di Node.js. Tutte le altre risoluzioni degli specificatori vengono sempre risolte solo con la semantica standard di risoluzione URL relativa.

Come in CommonJS, è possibile accedere ai file dei moduli all'interno dei pacchetti aggiungendo un percorso al nome del pacchetto a meno che il package.json del pacchetto non contenga un campo "exports", nel qual caso è possibile accedere ai file all'interno dei pacchetti solo tramite i percorsi definiti in "exports".

Per i dettagli su queste regole di risoluzione dei pacchetti che si applicano agli specificatori nudi nella risoluzione dei moduli di Node.js, consultare la documentazione dei pacchetti.

Estensioni file obbligatorie

Un'estensione file deve essere fornita quando si usa la parola chiave import per risolvere identificatori relativi o assoluti. Anche gli indici di directory (ad es. './startup/index.js') devono essere specificati per intero.

Questo comportamento corrisponde a come import si comporta negli ambienti browser, assumendo un server configurato in modo tipico.

URL

I moduli ES vengono risolti e memorizzati nella cache come URL. Ciò significa che i caratteri speciali devono essere codificati in percentuale, come # con %23 e ? con %3F.

Sono supportati gli schemi URL file:, node: e data:. Un identificatore come 'https://example.com/app.js' non è supportato nativamente in Node.js a meno che non si utilizzi un caricatore HTTPS personalizzato.

URL file:

I moduli vengono caricati più volte se l'identificatore import utilizzato per risolverli ha una query o un frammento diversi.

js
import './foo.mjs?query=1' // carica ./foo.mjs con query di "?query=1"
import './foo.mjs?query=2' // carica ./foo.mjs con query di "?query=2"

La radice del volume può essere referenziata tramite /, // o file:///. Date le differenze tra URL e risoluzione del percorso (come i dettagli sulla codifica in percentuale), si consiglia di utilizzare url.pathToFileURL quando si importa un percorso.

Importazioni data:

Aggiunto in: v12.10.0

Gli data: URL sono supportati per l'importazione con i seguenti tipi MIME:

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

Gli data: URL risolvono solo gli identificatori semplici per i moduli incorporati e gli identificatori assoluti. La risoluzione degli identificatori relativi non funziona perché data: non è uno schema speciale. Ad esempio, il tentativo di caricare ./foo da data:text/javascript,import "./foo"; non riesce a risolvere perché non esiste un concetto di risoluzione relativa per gli data: URL.

node: import

[Storia]

VersioneModifiche
v16.0.0, v14.18.0Aggiunto il supporto per l'importazione node: a require(...).
v14.13.1, v12.20.0Aggiunto in: v14.13.1, v12.20.0

Gli URL node: sono supportati come mezzo alternativo per caricare moduli integrati di Node.js. Questo schema URL consente di fare riferimento ai moduli integrati tramite stringhe URL assolute valide.

js
import fs from 'node:fs/promises'

Attributi di importazione

[Storia]

VersioneModifiche
v21.0.0, v20.10.0, v18.20.0Passaggio dalle asserzioni di importazione agli attributi di importazione.
v17.1.0, v16.14.0Aggiunto in: v17.1.0, v16.14.0

[Stabile: 2 - Stabile]

Stabile: 2 Stabilità: 2 - Stabile

Gli attributi di importazione sono una sintassi inline per le istruzioni di importazione dei moduli per trasmettere maggiori informazioni insieme allo specificatore del modulo.

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

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

Node.js supporta solo l'attributo type, per il quale supporta i seguenti valori:

Attributo typeNecessario per
'json'Moduli JSON

L'attributo type: 'json' è obbligatorio quando si importano moduli JSON.

Moduli integrati

I moduli integrati forniscono esportazioni con nome della loro API pubblica. Viene fornita anche un'esportazione predefinita che è il valore delle esportazioni CommonJS. L'esportazione predefinita può essere utilizzata, tra l'altro, per modificare le esportazioni con nome. Le esportazioni con nome dei moduli integrati vengono aggiornate solo chiamando 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

Espressioni import()

L'espressione dinamica import() è supportata sia nei moduli CommonJS che nei moduli ES. Nei moduli CommonJS può essere utilizzata per caricare i moduli ES.

import.meta

La meta proprietà import.meta è un Oggetto che contiene le seguenti proprietà. È supportata solo nei moduli ES.

import.meta.dirname

Aggiunto in: v21.2.0, v20.11.0

[Stabile: 1 - Sperimentale]

Stabile: 1 Stabilità: 1.2 - Release candidate

import.meta.filename

Aggiunto in: v21.2.0, v20.11.0

[Stabile: 1 - Sperimentale]

Stabile: 1 Stabilità: 1.2 - Release candidate

import.meta.url

Questo è definito esattamente come nei browser che forniscono l'URL del file del modulo corrente.

Ciò abilita schemi utili come il caricamento di file relativi:

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

import.meta.resolve(specifier)

[Cronologia]

VersioneModifiche
v20.6.0, v18.19.0Non più dietro il flag CLI --experimental-import-meta-resolve, tranne per il parametro parentURL non standard.
v20.6.0, v18.19.0Questa API non genera più un'eccezione quando punta a URL file: che non corrispondono a un file esistente sul FS locale.
v20.0.0, v18.19.0Questa API ora restituisce una stringa in modo sincrono anziché una Promise.
v16.2.0, v14.18.0Aggiunto il supporto per l'oggetto WHATWG URL al parametro parentURL.
v13.9.0, v12.16.2Aggiunto in: v13.9.0, v12.16.2

[Stabile: 1 - Sperimentale]

Stabile: 1 Stabilità: 1.2 - Release candidate

  • specifier <stringa> Lo specificatore del modulo da risolvere rispetto al modulo corrente.
  • Restituisce: <stringa> La stringa URL assoluta a cui lo specificatore verrebbe risolto.

import.meta.resolve è una funzione di risoluzione relativa al modulo con ambito per ciascun modulo, che restituisce la stringa 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

Sono supportate tutte le funzionalità della risoluzione dei moduli di Node.js. Le risoluzioni delle dipendenze sono soggette alle risoluzioni delle esportazioni consentite all'interno del pacchetto.

Avvertenze:

  • Ciò può comportare operazioni sincrone sul file system, che possono influire sulle prestazioni in modo simile a require.resolve.
  • Questa funzionalità non è disponibile all'interno dei loader personalizzati (creerebbe un deadlock).

API non standard:

Quando si utilizza il flag --experimental-import-meta-resolve, tale funzione accetta un secondo argomento:

  • parent <stringa> | <URL> Un URL di modulo padre assoluto facoltativo da cui risolvere. Predefinito: import.meta.url

Interoperabilità con CommonJS

Dichiarazioni import

Una dichiarazione import può fare riferimento a un modulo ES o a un modulo CommonJS. Le dichiarazioni import sono consentite solo nei moduli ES, ma le espressioni dinamiche import() sono supportate in CommonJS per caricare moduli ES.

Quando si importano moduli CommonJS, l'oggetto module.exports viene fornito come esportazione predefinita. Le esportazioni con nome potrebbero essere disponibili, fornite dall'analisi statica come una comodità per una migliore compatibilità con l'ecosistema.

require

Il modulo CommonJS require attualmente supporta solo il caricamento sincrono di moduli ES (ovvero, moduli ES che non utilizzano await di livello superiore).

Vedere Caricamento dei moduli ECMAScript utilizzando require() per i dettagli.

Spazi dei nomi CommonJS

[Cronologia]

VersioneModifiche
v23.0.0Aggiunto marcatore di esportazione 'module.exports' agli spazi dei nomi CJS.
v14.13.0Aggiunto in: v14.13.0

I moduli CommonJS sono costituiti da un oggetto module.exports che può essere di qualsiasi tipo.

Per supportare questo, quando si importa CommonJS da un modulo ECMAScript, viene costruito un wrapper dello spazio dei nomi per il modulo CommonJS, che fornisce sempre una chiave di esportazione default che punta al valore module.exports di CommonJS.

Inoltre, viene eseguita un'analisi statica euristica sul testo sorgente del modulo CommonJS per ottenere un elenco statico di esportazioni con il miglior sforzo da fornire nello spazio dei nomi dai valori in module.exports. Ciò è necessario poiché questi spazi dei nomi devono essere costruiti prima della valutazione del modulo CJS.

Questi oggetti dello spazio dei nomi CommonJS forniscono anche l'esportazione default come esportazione con nome 'module.exports', al fine di indicare inequivocabilmente che la loro rappresentazione in CommonJS utilizza questo valore e non il valore dello spazio dei nomi. Questo rispecchia la semantica della gestione del nome di esportazione 'module.exports' nel supporto interop require(esm).

Quando si importa un modulo CommonJS, può essere importato in modo affidabile utilizzando l'importazione predefinita del modulo ES o la sua sintassi sugar corrispondente:

js
import { default as cjs } from 'cjs'
// Identico a quanto sopra
import cjsSugar from 'cjs'

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

Questo oggetto esotico dello spazio dei nomi del modulo può essere osservato direttamente quando si utilizza import * as m from 'cjs' o un'importazione dinamica:

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

Per una migliore compatibilità con l'uso esistente nell'ecosistema JS, Node.js inoltre tenta di determinare le esportazioni con nome CommonJS di ogni modulo CommonJS importato per fornirle come esportazioni di moduli ES separati utilizzando un processo di analisi statica.

Ad esempio, considera un modulo CommonJS scritto:

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

Il modulo precedente supporta le importazioni con nome nei moduli ES:

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

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

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

Come si può vedere dall'ultimo esempio dell'oggetto esotico dello spazio dei nomi del modulo che viene registrato, l'esportazione name viene copiata dall'oggetto module.exports e impostata direttamente nello spazio dei nomi del modulo ES quando il modulo viene importato.

Gli aggiornamenti live binding o le nuove esportazioni aggiunte a module.exports non vengono rilevati per queste esportazioni con nome.

Il rilevamento delle esportazioni con nome si basa su modelli di sintassi comuni ma non sempre rileva correttamente le esportazioni con nome. In questi casi, l'utilizzo del modulo di importazione predefinito descritto sopra può essere un'opzione migliore.

Il rilevamento delle esportazioni con nome copre molti schemi di esportazione comuni, schemi di riesportazione e output di strumenti di compilazione e transpiler. Vedere cjs-module-lexer per la semantica esatta implementata.

Differenze tra moduli ES e CommonJS

Nessun require, exports o module.exports

Nella maggior parte dei casi, l'import del modulo ES può essere utilizzato per caricare i moduli CommonJS.

Se necessario, una funzione require può essere creata all'interno di un modulo ES utilizzando module.createRequire().

Nessun __filename o __dirname

Queste variabili CommonJS non sono disponibili nei moduli ES.

I casi d'uso di __filename e __dirname possono essere replicati tramite import.meta.filename e import.meta.dirname.

Nessun caricamento di Addon

Gli Addon non sono attualmente supportati con gli import dei moduli ES.

Possono invece essere caricati con module.createRequire() o process.dlopen.

Nessun require.resolve

La risoluzione relativa può essere gestita tramite new URL('./local', import.meta.url).

Per una sostituzione completa di require.resolve, esiste l'API import.meta.resolve.

In alternativa, è possibile utilizzare module.createRequire().

Nessun NODE_PATH

NODE_PATH non fa parte della risoluzione degli identificatori import. Si prega di utilizzare i symlink se si desidera questo comportamento.

Nessun require.extensions

require.extensions non viene utilizzato da import. Gli hook di personalizzazione del modulo possono fornire una sostituzione.

Nessun require.cache

require.cache non viene utilizzato da import poiché il caricatore di moduli ES ha la sua cache separata.

Moduli JSON

[Cronologia]

VersioneModifiche
v23.1.0I moduli JSON non sono più sperimentali.

[Stabile: 2 - Stabile]

Stabile: 2 Stabilità: 2 - Stabile

I file JSON possono essere referenziati da import:

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

La sintassi with { type: 'json' } è obbligatoria; vedi Attributi di importazione.

Il JSON importato espone solo un'esportazione default. Non c'è supporto per le esportazioni denominate. Viene creata una voce della cache nella cache CommonJS per evitare duplicazioni. Lo stesso oggetto viene restituito in CommonJS se il modulo JSON è già stato importato dallo stesso percorso.

Moduli Wasm

[Stabile: 1 - Sperimentale]

Stabile: 1 Stabilità: 1 - Sperimentale

L'importazione di moduli WebAssembly è supportata con il flag --experimental-wasm-modules, consentendo l'importazione di qualsiasi file .wasm come moduli normali, supportando anche le loro importazioni di moduli.

Questa integrazione è in linea con la Proposta di integrazione dei moduli ES per WebAssembly.

Ad esempio, un index.mjs contenente:

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

eseguito sotto:

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

fornirebbe l'interfaccia di esportazione per l'istanza di module.wasm.

await di primo livello

Aggiunto in: v14.8.0

La parola chiave await può essere utilizzata nel corpo di primo livello di un modulo ECMAScript.

Supponendo un a.mjs con

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

E un b.mjs con

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

console.log(five) // Registra `5`
bash
node b.mjs # funziona

Se un'espressione await di primo livello non si risolve mai, il processo node si chiuderà con un codice di stato 13.

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

spawn(execPath, [
  '--input-type=module',
  '--eval',
  // Promessa che non si risolve mai:
  'await new Promise(() => {})',
]).once('exit', code => {
  console.log(code) // Registra `13`
})

Caricatori

La precedente documentazione dei Caricatori è ora disponibile in Moduli: Hook di personalizzazione.

Algoritmo di risoluzione e caricamento

Funzionalità

Il resolver predefinito ha le seguenti proprietà:

  • Risoluzione basata su FileURL come utilizzata dai moduli ES
  • Risoluzione di URL relativi e assoluti
  • Nessuna estensione predefinita
  • Nessun main di cartelle
  • Ricerca di risoluzione di pacchetti specificatori bare tramite node_modules
  • Non fallisce su estensioni o protocolli sconosciuti
  • Può opzionalmente fornire un suggerimento del formato alla fase di caricamento

Il caricatore predefinito ha le seguenti proprietà

  • Supporto per il caricamento di moduli integrati tramite URL node:
  • Supporto per il caricamento di moduli "inline" tramite URL data:
  • Supporto per il caricamento di moduli file:
  • Fallisce su qualsiasi altro protocollo URL
  • Fallisce su estensioni sconosciute per il caricamento file: (supporta solo .cjs, .js e .mjs)

Algoritmo di risoluzione

L'algoritmo per caricare uno specificatore di modulo ES viene fornito tramite il metodo ESM_RESOLVE di seguito. Restituisce l'URL risolto per uno specificatore di modulo relativo a un parentURL.

L'algoritmo di risoluzione determina l'URL completo risolto per il caricamento di un modulo, insieme al suo formato di modulo suggerito. L'algoritmo di risoluzione non determina se il protocollo URL risolto può essere caricato o se le estensioni di file sono consentite, ma queste convalide vengono applicate da Node.js durante la fase di caricamento (ad esempio, se è stato richiesto di caricare un URL con un protocollo che non è file:, data: o node:).

L'algoritmo cerca anche di determinare il formato del file in base all'estensione (vedere l'algoritmo ESM_FILE_FORMAT di seguito). Se non riconosce l'estensione del file (ad esempio, se non è .mjs, .cjs o .json), viene restituito un formato undefined, che genererà un'eccezione durante la fase di caricamento.

L'algoritmo per determinare il formato del modulo di un URL risolto è fornito da ESM_FILE_FORMAT, che restituisce il formato di modulo univoco per qualsiasi file. Il formato "module" viene restituito per un modulo ECMAScript, mentre il formato "commonjs" viene utilizzato per indicare il caricamento tramite il loader CommonJS legacy. Formati aggiuntivi come "addon" possono essere estesi in futuri aggiornamenti.

Nei seguenti algoritmi, tutti gli errori delle subroutine vengono propagati come errori di queste routine di livello superiore, salvo diversamente specificato.

defaultConditions è l'array di nomi di ambiente condizionali, ["node", "import"].

Il resolver può generare i seguenti errori:

  • Specificatore di modulo non valido: Lo specificatore di modulo è un URL, un nome di pacchetto o uno specificatore di sottopath di pacchetto non validi.
  • Configurazione pacchetto non valida: La configurazione di package.json non è valida o contiene una configurazione non valida.
  • Destinazione pacchetto non valida: Le esportazioni o le importazioni del pacchetto definiscono un modulo di destinazione per il pacchetto che è un tipo o una stringa di destinazione non validi.
  • Percorso pacchetto non esportato: Le esportazioni del pacchetto non definiscono o non consentono un sottopath di destinazione nel pacchetto per il modulo specificato.
  • Importazione pacchetto non definita: Le importazioni del pacchetto non definiscono lo specificatore.
  • Modulo non trovato: Il pacchetto o il modulo richiesto non esiste.
  • Importazione di directory non supportata: Il percorso risolto corrisponde a una directory, che non è una destinazione supportata per le importazioni di moduli.

Specifiche dell'Algoritmo di Risoluzione

ESM_RESOLVE(specificatore, URLGenitore)

PACKAGE_RESOLVE(specificatorePacchetto, URLGenitore)

PACKAGE_SELF_RESOLVE(nomePacchetto, sottopercorsoPacchetto, URLGenitore)

PACKAGE_EXPORTS_RESOLVE(URLPacchetto, sottopercorso, esportazioni, condizioni)

PACKAGE_IMPORTS_RESOLVE(specificatore, URLGenitore, condizioni)

PACKAGE_IMPORTS_EXPORTS_RESOLVE(chiaveCorrispondenza, oggettoCorrispondenza, URLPacchetto, èImportazioni, condizioni)

PATTERN_KEY_COMPARE(chiaveA, chiaveB)

PACKAGE_TARGET_RESOLVE(URLPacchetto, target, corrispondenzaPattern, èImportazioni, condizioni)

ESM_FILE_FORMAT(url)

LOOKUP_PACKAGE_SCOPE(url)

READ_PACKAGE_JSON(URLPacchetto)

DETECT_MODULE_SYNTAX(source)

Personalizzazione dell'algoritmo di risoluzione degli specificatori ESM

Hook di personalizzazione del modulo forniscono un meccanismo per personalizzare l'algoritmo di risoluzione degli specificatori ESM. Un esempio che fornisce la risoluzione in stile CommonJS per gli specificatori ESM è commonjs-extension-resolution-loader.