Ce face package.json "exports" și "imports"
Câmpul "exports" spune ce poate importa cineva din pachetul tău. "." este intrarea principală (import "pachet"), iar celelalte chei sunt subcăi (import "pachet/format"). Orice fișier care nu apare în exports este ascuns: încercarea de a-l importa dă ERR_PACKAGE_PATH_NOT_EXPORTED. Când există, exports are prioritate față de main.
Valorile pot fi condiționale: {"import": "./index.mjs", "require": "./index.cjs"} dă alt fișier pentru import și pentru require, iar "default" este varianta de rezervă. Ordinea cheilor contează: prima potrivire câștigă, deci "default" stă ultima.
Câmpul "imports" definește alias-uri private, care încep obligatoriu cu #: import { slug } from "#utile/text" în loc de ../../utile/text.js. Merg doar din interiorul pachetului. Ambele câmpuri acceptă * ca tipar.
Exemple
Exemplul 1: Un pachet local cu exports
Creăm un pachet în node_modules/preturi-ro, cu intrarea principală și subcalea ./format. Fișierul intern.js nu este exportat, deci nu poate fi importat.
import { mkdirSync, writeFileSync } from "node:fs";
const dir = "node_modules/preturi-ro";
mkdirSync(dir, { recursive: true });
writeFileSync(`${dir}/package.json`, JSON.stringify({
name: "preturi-ro",
type: "module",
exports: { ".": "./index.js", "./format": "./format.js" },
}));
writeFileSync(`${dir}/index.js`, "export const tva = 0.21;");
writeFileSync(`${dir}/format.js`, 'export const lei = (s) => s.toFixed(2) + " lei";');
writeFileSync(`${dir}/intern.js`, "export const secret = 42;");
const { tva } = await import("preturi-ro");
const { lei } = await import("preturi-ro/format");
console.log(tva, lei(99.9));
try {
await import("preturi-ro/intern.js");
} catch (eroare) {
console.log(eroare.code);
}
Rezultat
0.21 99.90 lei
ERR_PACKAGE_PATH_NOT_EXPORTED
Exemplul 2: Alias-uri interne cu imports
import { mkdirSync, writeFileSync } from "node:fs";
mkdirSync("app/src/utile", { recursive: true });
writeFileSync("app/package.json", JSON.stringify({
name: "app",
type: "module",
imports: { "#utile/*": "./src/utile/*.js" },
}));
writeFileSync("app/src/utile/text.js",
'export const slug = (s) => s.toLowerCase().normalize("NFD").replace(/[\\u0300-\\u036f]/g, "").replaceAll(" ", "-");');
writeFileSync("app/src/index.js", 'import { slug } from "#utile/text"; console.log(slug("Piața Unirii Iași"));');
await import("./app/src/index.js");
Rezultat
piata-unirii-iasi
Exemplul 3: Exporturi condiționale pentru import și require
{
"name": "preturi-ro",
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.cjs",
"default": "./dist/index.mjs"
},
"./package.json": "./package.json"
}
}
Greșeli frecvente
- Adaugi
exportsîntr-un pachet deja publicat și utilizatorii care importaupachet/lib/ceva.jsprimescERR_PACKAGE_PATH_NOT_EXPORTED. Este o schimbare incompatibilă: publică o versiune majoră nouă sau exportă și acele căi. - Pui
"default"înaintea lui"import": prima condiție potrivită câștigă, deci"import"nu mai este folosit niciodată. - Scrii căile din
exportsfără./în față ("index.js"): Node.js le respinge. Toate țintele încep cu./.
Comenzi înrudite
package.json: Fișierul de configurare al unui proiect Node.js: nume, versiune, tipul modulelor, scripturi, dependențe și versiunea Node cerută.Module ES (import) și CommonJS (require): Cele două sisteme de module din Node.js: import/export (ES) și require/module.exports (CommonJS), și cum le combini.npm publish: Publică un pachet în registrul npm; cu npm pack –dry-run vezi înainte exact ce fișiere pleacă.npm workspaces: Mai multe pachete într-un singur depozit (monorepo), cu un singur node_modules și comenzi rulate în toate deodată.