exports non è il campo main
Il 31 ottobre 2026 la documentazione Node.js v26.13.0 fa prevalere exports su main quando il pacchetto si importa per nome. Senza la riga, require di un subpath lancia ERR_PACKAGE_PATH_NOT_EXPORTED. Non ho lanciato node.
In questa guida (5)
Il 31 ottobre 2026 "exports" non è "main". Se il primo c’è, la documentazione di Node lo fa prevalere quando il pacchetto si importa per nome. Ho letto la pagina Packages della documentazione Node.js v26.13.0. Non ho lanciato node.
In breve: "main", aggiunto in v0.4.0, è il punto di ingresso nel lookup da node_modules. "exports", da v12.7.0, è l’alternativa che può definire sottopercorsi e condizioni, e incapsula i moduli non esportati. Non è npm ci: lì si parla di un comando e di un lockfile. Qui si parla del campo che dice da quale file parte il pacchetto. Il cluster è Prodotto.
Il campo che cede
La sezione Node.js package.json field definitions, sulla stessa pagina, definisce "main" come una stringa. Il valore è un percorso. Definisce il punto di ingresso di un pacchetto importato per nome, con un lookup in node_modules. Definisce anche lo script usato quando la directory del pacchetto è caricata con require(). L’esempio della pagina è require('./path/to/directory'), che risolve ./path/to/directory/index.js.
La frase che separa i due campi: se "exports" esiste, ha la precedenza su "main" quando si importa il pacchetto per nome. La storia in cima alla pagina data l’introduzione di "exports" a v12.7.0, «as a more powerful alternative to the classic "main" field».
Il campo che incapsula
"exports" è un oggetto, una stringa o un array di stringhe. Permette di definire i punti di ingresso quando il pacchetto è importato per nome, da node_modules o con un autoriferimento al proprio nome. È supportato in Node.js 12+ come alternativa a "main", e può definire subpath export e conditional export, incapsulando i moduli interni non esportati. I conditional export, scrive la pagina, servono anche a punti di ingresso diversi per ambiente, compreso require oppure import.
Tutti i percorsi in "exports" devono essere URL di file relativi che iniziano con ./. Per un pacchetto nuovo la guida raccomanda di usare "exports". Quando il campo è definito, tutti i sottopercorsi del pacchetto sono incapsulati e non sono più disponibili a chi importa.
Per chi usa una versione vecchia di Node o uno strumento di build che non legge "exports", la pagina mostra i due campi insieme, puntati allo stesso modulo:
{
"main": "./index.js",
"exports": "./index.js"
}Aggiunge che tutte le versioni di Node attualmente supportate, e gli strumenti di build moderni, supportano "exports". Il "main" accanto non sostituisce il primo: è la riga di compatibilità.
Il subpath che lancia
L’esempio è netto. Con "exports": "./index.js", require('pkg/subpath.js') lancia ERR_PACKAGE_PATH_NOT_EXPORTED. Non è un incapsulamento forte: un require diretto di un percorso assoluto, come require('/path/to/node_modules/pkg/subpath.js'), carica comunque il file.
I sottopercorsi si dichiarano trattando il punto di ingresso principale come il subpath ".":
{
"exports": {
".": "./index.js",
"./submodule.js": "./src/submodule.js"
}
}import submodule from 'es-module-package/submodule.js' carica ./node_modules/es-module-package/src/submodule.js. import submodule from 'es-module-package/private-module.js' lancia ERR_PACKAGE_PATH_NOT_EXPORTED. I pattern dentro "exports" arrivano, nella storia della pagina, con v14.13.0 e v12.20.0. Non ho provato un import.
| Documentazione Node.js v26.13.0, letta il 31 ottobre 2026 | "main" | "exports" |
|---|---|---|
| Aggiunto in | v0.4.0 | v12.7.0 |
| Tipo, sulla pagina | stringa, un percorso | oggetto, stringa o array di stringhe |
| Import per nome | Punto di ingresso, se exports non c’è | Se c’è, ha la precedenza |
| Sottopercorsi | La sezione non gliene assegna | Solo quelli dichiarati. Gli altri lanciano |
| Percorsi | Un path | URL di file relativi che iniziano con ./ |
| Require assoluto del file | Non è il caso discusso | La pagina dice che carica ancora il file |
Errori da evitare
Tenere
"main"e credere che vinca anche se"exports"c’è. La pagina dice il contrario, sull’import per nome.Importare
pkg/qualunque-file.jssolo perché il file è nella cartella. Senza una riga in"exports", l’errore nominato èERR_PACKAGE_PATH_NOT_EXPORTED.Scrivere in
"exports"un percorso che non inizia con./. La pagina chiede URL di file relativi.Chiamarlo incapsulamento forte. Il
requiredel percorso assoluto, scrive la pagina, passa lo stesso.Cancellare
"main"in un progetto che deve ancora parlare con un Node vecchio. La pagina lo lascia, puntato allo stesso modulo.Confondere il campo con
npm ci. Un lockfile non è un punto di ingresso.
In sintesi
Il 31 ottobre 2026 la documentazione Node.js v26.13.0 tiene "main" come campo classico e "exports" come alternativa, in precedenza sull’import per nome. Il secondo incapsula i sottopercorsi e, se manca la riga, lancia ERR_PACKAGE_PATH_NOT_EXPORTED. Un require assoluto del file non è bloccato da quella frase. Non ho eseguito né l’import né il require.
Foto di copertina: Henry Söderlund, «Cardboard boxes», Wikimedia Commons, CC BY 2.0. La descrizione del file è una pila di cartone. Non è un package.json e non è un punto di ingresso.


