Mundarija (30)
- Bu darsda
- 1. Nega bu kerak?
- 2. Node paketni qanday topadi
- 2.1 Umumiy yo'l
- 2.2 Mashq paketi
- 3. main: eski yo'l va uning muammolari
- 3.1 Faqat main
- 3.2 Ichki fayllar ochiq
- 3.3 module maydoni
- 4. exports: paketning eshiklari
- 4.1 Shartli eksport
- 4.2 Yopiq devor
- 4.3 Naqsh: *
- 4.4 Shartlar tartibi
- 5. Haqiqiy paket: web-vitals
- 6. types: TypeScript uchun eshik
- 7. imports: paket ichidagi # taxallus
- 8. Qolgan maydonlar: files, bin, sideEffects
- 8.1 files: arxivga nima tushadi
- 8.2 bin: terminal buyrug'i
- 8.3 sideEffects: tree shaking uchun va'da
- 8.4 engines va packageManager
- 9. Ko'p uchraydigan xatolar
- 10. Mashqlar
- 1-mashq (oson): web-vitals eshiklari
- 2-mashq (o'rta): Narxlarni ochiq qiling
- 3-mashq (qiyin): O'z resolver'ingiz
- 11. Real ishda
- Xulosa
- Manbalar
package.json kirish nuqtalari: main, module, exports, imports va types
Qisqacha:
import "paket"yozganingizda qaysi fayl ochilishini paketningpackage.jsoni belgilaydi. Eski usul —main(va bundler'lar uchunmodule), zamonaviy usul —exports. Unda har kirish yo'li va shart (import,require,types) uchun alohida fayl yoziladi. Ro'yxatda yo'q fayllar tashqaridan yopiq (ERR_PACKAGE_PATH_NOT_EXPORTED).importspaket ichidagi#taxalluslarni,files— nashrga tushadigan fayllarni,bin— terminal buyrug'ini belgilaydi.
Bu darsda
- Node paketni qanday topishini:
exports→ shartlar → fayl, yo'q bo'lsamain. exportsdagiimport,require,types,defaultshartlari va ularning tartibi.- Kichik yo'llar (subpath) va
ERR_PACKAGE_PATH_NOT_EXPORTEDxatosi. imports(#narxlar),files,bin,sideEffectsvamodulemaydonlari.web-vitalsning haqiqiyexportsini o'qish.
Oldin bilishingiz kerak: package.json II: bog'liqlik turlari, CommonJS va ESM bilan o'zaro ishlash, Declaration fayllari (.d.ts).
1. Nega bu kerak?
O'tgan darsda vazifalar ga npm run check qo'shdik. Endi Sardor boshqa vazifa oldi: Jasur aka «Bahor» narxlarini bir nechta loyihada ishlatmoqchi — sayt, Telegram bot, kassa dasturi. "Narxlarni bitta paketga yig', hamma loyiha o'shandan olsin."
Sardor bahor-narx paketini yozdi va birinchi foydalanuvchisi — ESM loyihadagi kassa — darhol xato oldi. Keyin kimdir paketning ichki fayliga to'g'ridan-to'g'ri ulanib oldi, Sardor esa o'sha faylni o'zgartirdi va begona loyiha sinib qoldi. Ikkala muammoning yechimi bitta maydonda — exports.
Siz kutubxona yozmasangiz ham, bu dars kerak. Har import … from "vite" yoki "web-vitals" ortida aynan shu qoidalar ishlaydi. ERR_PACKAGE_PATH_NOT_EXPORTED yoki TypeScript'ning TS7016 xatosini ko'rganingizda, sababini shu yerdan qidirasiz.
Maslahat: Chiqishlar 2026-10-10 da Windows 11, Node 24.21.0, npm 11.19.0 va TypeScript 7.0.2 bilan olingan. Yo'l boshi
…bilan qisqartirilgan.
2. Node paketni qanday topadi
2.1 Umumiy yo'l
import { priceOf } from "bahor-narx" — bu bare specifier ("yalang'och nom"): ./ yoki / bilan boshlanmaydi. Node uni shunday qidiradi:
flowchart TD
A["import 'bahor-narx'"] --> B["node_modules/bahor-narx<br/>package.json"]
B --> C{"exports bormi?"}
C -- "ha" --> D["yo'l va shart bo'yicha<br/>fayl tanlanadi"]
C -- "yo'q" --> E{"main bormi?"}
E -- "ha" --> F["main fayli"]
E -- "yo'q" --> G["index.js"]
D --> H["ro'yxatda yo'q:<br/>ERR_PACKAGE_PATH_NOT_EXPORTED"]Muhim qoida: exports bor bo'lsa, Node main ga umuman qaramaydi. main faqat exports ni bilmaydigan eski vositalar uchun qoldiriladi. node_modules qayerdan qidirilishi — keyingi darslarning biri, node_modules ichida.
2.2 Mashq paketi
kurs/mashqlar/16/07-kirish/ da ikki papka: bahor-narx/ (paket) va kassa/ (uni ishlatadigan loyiha). Paketda build yo'q — fayllar qo'lda yozilgan:
| Fayl | Nima |
|---|---|
dist/index.js |
ESM kirish: priceOf, format = "esm" |
dist/index.cjs |
CommonJS kirish: o'sha funksiya, format: "cjs" |
dist/narxlar.js |
ichki ma'lumot — narxlar obyekti |
dist/format.js |
som(28000) → "28000 so'm" |
| Fayl | Nima |
|---|---|
dist/cli.js |
terminal buyrug'i |
types/index.d.ts |
TypeScript turlari |
format qiymati qaysi fayl ochilganini ko'rsatadi. CommonJS fayli:
// index.cjs — CommonJS kirish nuqtasi (require uchun)
const prices = { osh: 35000, "lag'mon": 28000, manti: 30000 };
function priceOf(name) {
return prices[name] ?? null;
}
module.exports = { priceOf, format: "cjs" };Kassa paketni papkadan o'rnatadi:
npm i ../bahor-narx
added 1 package, and audited 3 packages in 461ms
found 0 vulnerabilitiespackage.json ga "bahor-narx": "file:../bahor-narx" yozildi. file: — "registrdan emas, diskdagi papkadan". npm node_modules/bahor-narx ni papkaga havola (symlink) qilib qo'yadi: paketni o'zgartirsangiz, kassa darhol yangisini ko'radi. Tajriba uchun qulay.
3. main: eski yo'l va uning muammolari
3.1 Faqat main
Paketning birinchi package.json i:
{
"name": "bahor-narx",
"version": "1.0.0",
"type": "module",
"main": "./dist/index.cjs"
}CommonJS loyihadan (eski.cjs):
// eski.cjs — CommonJS loyihadan foydalanish
const { priceOf, format } = require("bahor-narx");
console.log("manti:", priceOf("manti"), "| format:", format);node eski.cjsmanti: 30000 | format: cjsIshladi. Endi ESM kassadan (kassa.js):
// kassa.js — bahor-narx paketidan foydalanadi
import { priceOf, format } from "bahor-narx";
console.log("osh:", priceOf("osh"), "| format:", format);node kassa.jsfile:///…/kurs/mashqlar/16/07-kirish/kassa/kassa.js:2
import { priceOf, format } from "bahor-narx";
^^^^^^
SyntaxError: Named export 'format' not found. The requested module 'bahor-narx' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:
import pkg from 'bahor-narx';
const { priceOf, format } = pkg;(at … qatorlari olib tashlandi.) Tarjima: "format nomli eksport topilmadi. bahor-narx — CommonJS modul, u module.exports ning hamma qismini nomli eksport sifatida bermasligi mumkin". Node CommonJS faylni ishga tushirmasdan, matnini ko'zdan kechirib nomlarni taxmin qiladi. priceOf — qisqa yozuv, uni topdi. format: "cjs" — qiymati satr, uni taxmin qila olmadi. CommonJS va ESM darsidagi chegaralardan biri.
Bitta main ikki dunyoga ham xizmat qila olmaydi. ESM fayl bersak, CommonJS'dagi eski Node'lar sinadi; CommonJS bersak — yuqoridagi xato.
3.2 Ichki fayllar ochiq
main faqat "asosiy fayl qaysi" deydi, qolganini yopmaydi. Kassada:
// chuqur.js — paketning ichki fayliga to'g'ridan-to'g'ri kirish
import { prices } from "bahor-narx/dist/narxlar.js";
console.log(prices);node chuqur.js{ osh: 35000, "lag'mon": 28000, manti: 30000 }Ishladi — va aynan shu xavfli. Sardor ertaga narxlar.js ni menyu.js deb o'zgartirsa, bu loyiha sinadi. Muallif uchun har fayl "ommaviy API" bo'lib qoladi: hech narsani ko'chirib bo'lmaydi.
3.3 module maydoni
Eski paketlarda main yonida yana bir maydon uchraydi:
npm view web-vitals@6.2.3 main modulemain = 'dist/web-vitals.umd.cjs'
module = 'dist/web-vitals.js'module — rasmiy Node maydoni emas. Uni bundler'lar (webpack, Rollup, Vite) o'ylab topgan: "ESM versiya shu yerda". Node unga qaramaydi. Bugun uning o'rnini exports dagi import sharti egalladi, lekin eski paketlar va bundler sozlamalarida (resolve.mainFields) hali ko'rasiz.
Tekshirib ko'ring: Faqat
mainbor paketdaimport pkg from "bahor-narx"(default import) ishlaydimi?pkg.formatnima bo'ladi?
Javob
Ishlaydi. Xabarning o'zi shuni taklif qilgan edi: CommonJS modul ESM'dan doim default import bilan ochiladi va pkg — module.exports obyektining o'zi. pkg.format — "cjs".
4. exports: paketning eshiklari
4.1 Shartli eksport
exports — paketning "eshiklar ro'yxati". Ro'yxatdagi eshikdan kiriladi, qolgan devorlar yopiq. Yangi package.json dan:
{
"exports": {
".": {
"types": "./types/index.d.ts",
"import": "./dist/index.js",
"require": "./dist/index.cjs"
},
"./format": "./dist/format.js",
"./package.json": "./package.json"
}
}Kalitlarni o'qiymiz:
| Kalit | Ma'nosi |
|---|---|
"." |
asosiy eshik: import "bahor-narx" |
"./format" |
kichik yo'l: import "bahor-narx/format" |
"./package.json" |
package.json ni o'qishga ruxsat |
"." ichidagi kalitlar — shartlar (conditions). Node ularni yuqoridan pastga o'qiydi va birinchi mosini oladi:
| Shart | Kim ishlatadi |
|---|---|
types |
TypeScript (Node e'tiborsiz qoldiradi) |
import |
import va import() |
require |
require() |
default |
hammasi — oxirgi zaxira |
| Shart | Kim ishlatadi |
|---|---|
node |
faqat Node |
browser |
bundler brauzer uchun yig'ganda |
development, production |
Vite kabi bundler'lar rejimga qarab |
Endi kassaning uchala fayli:
node kassa.jsosh: 35000 | format: esmnode eski.cjsmanti: 30000 | format: cjsBir paket, ikki dunyo: import ESM faylni, require CommonJS faylni oldi. Bunday paket dual package ("ikki formatli") deyiladi.
Diqqat: Ikki format — ikki nusxa kod. Bitta loyihada bir qism
import, boshqa qismrequireqilsa, modul ikki marta yuklanadi va ichki holat (masalan, kesh) ikkiga bo'linadi. Node hujjati buni "dual package hazard" deb ataydi. Node 24 darequire()ESM faylni ham yuklay oladi (pasport darsidagichalkmisoli), shuning uchun yangi paketlar tobora faqat ESM chiqmoqda.
4.2 Yopiq devor
chuqur.js endi:
node chuqur.jsnode:internal/modules/esm/resolve:315
return new ERR_PACKAGE_PATH_NOT_EXPORTED(
^
Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath './dist/narxlar.js' is not defined by "exports" in …\kassa\node_modules\bahor-narx\package.json imported from …\kassa\chuqur.js
code: 'ERR_PACKAGE_PATH_NOT_EXPORTED'
}
Node.js v24.21.0Tarjima: "./dist/narxlar.js kichik yo'li exports da belgilanmagan". Paket muallifi endi ichki fayllarni bemalol ko'chira oladi. Foydalanuvchi uchun qoida: bu xato — "muallif bu faylni ochmagan". Paket hujjatidan ochiq yo'lni qidiring, package.json ni qo'lda tahrirlamang.
Kichik yo'l esa ishlaydi. format.js:
// format.js — kichik yo'l (subpath) orqali import
import { som } from "bahor-narx/format";
import pkg from "bahor-narx/package.json" with { type: "json" };
console.log(som(28000), "| versiya:", pkg.version);node format.js28000 so'm | versiya: 1.0.0with { type: "json" } — JSON faylni ESM'da import qilish yozuvi (Dinamik import darsidagi import atributlari). "./package.json" eshigi bo'lmasa, bu qator ham ERR_PACKAGE_PATH_NOT_EXPORTED berardi — ba'zi vositalar paket versiyasini shunday o'qiydi, shuning uchun uni ochiq qoldirish odat.
4.3 Naqsh: *
Ko'p kichik yo'l bo'lsa, ularni bittalab yozish shart emas:
{
"exports": {
"./taomlar/*": "./dist/taomlar/*.js"
}
}import "bahor-narx/taomlar/osh" → ./dist/taomlar/osh.js. * o'rniga kelgan qism o'ng tomondagi * ga qo'yiladi.
4.4 Shartlar tartibi
Node birinchi mos shartni oladi. Shuning uchun default doim oxirida bo'lishi kerak. Ataylab xato tartib bilan sinadik — { "default": "./a.js", "require": "./b.cjs" } va require("tartib"):
a.js (default)require sharti hech qachon ishlamaydi — default uni oldinroq "yutib" yubordi. Xato yo'q, ogohlantirish yo'q, faqat noto'g'ri fayl.
types esa birinchi yoziladi — TypeScript hujjatining tavsiyasi. TypeScript ham shartlarni tartib bilan o'qiydi. Bizning sinovda tsc 7.0.2 types ni oxirida ham topdi, lekin boshqa vositalar va eski TypeScript'lar birinchi mos shartda to'xtaydi.
Tekshirib ko'ring: Paketda
"exports": "./dist/index.js"(bitta qator).import "paket/dist/index.js"ishlaydimi?
Javob
Yo'q. Bitta qator — { ".": "./dist/index.js" } ning qisqa yozuvi: faqat asosiy eshik ochiq. paket/dist/index.js — kichik yo'l, u ro'yxatda yo'q, natija ERR_PACKAGE_PATH_NOT_EXPORTED. Fayl bir xil bo'lsa ham, Node faqat ochiq eshiklarni tan oladi.
5. Haqiqiy paket: web-vitals
vazifalar dagi web-vitals 6.2.3 ning exports ini o'qiymiz. npm view web-vitals@6.2.3 exports 13 ta kalit chiqaradi, boshi:
{
'.': {
types: './dist/modules/index.d.ts',
default: './dist/web-vitals.js',
require: './dist/web-vitals.umd.cjs'
},
'./onCLS.js': {
types: './dist/modules/onCLS.d.ts',
default: './dist/modules/onCLS.js'
},
…Bir zum — default require dan oldin? Unda require hech qachon ishlamasligi kerak edi. node_modules dagi haqiqiy faylga qaraymiz:
cd node_modules/web-vitals
node -p "require('./package.json').exports['.']"{
types: './dist/modules/index.d.ts',
require: './dist/web-vitals.umd.cjs',
default: './dist/web-vitals.js'
}Faylda tartib to'g'ri. Kalitlarni registr javobi o'zgartirgan ekan. Saboq: exports tartibini tekshirishda npm view ga emas, node_modules dagi package.json ga ishoning.
Ildizga qaytib (cd ../..), Node'ning o'zidan so'raymiz — har ikki yo'l qaysi faylga olib boradi:
node -p "require.resolve('web-vitals')"…\kurs\vazifalar\node_modules\web-vitals\dist\web-vitals.umd.cjsnode --input-type=module \
-e "console.log(import.meta.resolve('web-vitals'))"file:///…/kurs/vazifalar/node_modules/web-vitals/dist/web-vitals.jsrequire.resolve va import.meta.resolve — faylni ochmasdan "qaysi fayl?" savoliga javob beradi. Paket g'alati ishlasa, birinchi tekshiruv shu.
web-vitals ichki faylni yopgan. import("web-vitals/dist/web-vitals.js") ni sinadik (xato kodi va xabari):
ERR_PACKAGE_PATH_NOT_EXPORTED Package subpath './dist/web-vitals.js' is not defined by "exports" in …\kurs\vazifalar\node_modules\web-vitals\package.jsonLekin har o'lchovni alohida ochgan: import { onCLS } from "web-vitals/onCLS.js" — faqat bitta funksiya kerak bo'lsa. vazifalar hozircha vendor/ nusxasini ishlatadi (bog'liqlik turlari). Vite kelganda import … from "web-vitals" yoziladi va Vite "." eshigidan default shartini oladi.
6. types: TypeScript uchun eshik
kassa da narx.ts va tsconfig.json ("module": "nodenext", strict):
// narx.ts — paket turlari bilan
import { priceOf } from "bahor-narx";
const price: number = priceOf("osh");
console.log(price);Avval "types" shartini olib tashlab sinadik. .d.ts fayl types/ papkasida, .js esa dist/ da — TypeScript uni o'zi topa olmaydi:
npx -p typescript@7.0.2 tscnarx.ts(2,25): error TS7016: Could not find a declaration file for module 'bahor-narx'. '…/kurs/mashqlar/16/07-kirish/bahor-narx/dist/index.js' implicitly has an 'any' type.
Try `npm i --save-dev @types/bahor-narx` if it exists or add a new declaration (.d.ts) file containing `declare module 'bahor-narx';`Tarjima: "bahor-narx uchun e'lon fayli topilmadi, dist/index.js yashirincha any turini oldi". Declaration fayllari darsidan tanish xato. TypeScript avval .js ning yonidan (dist/index.d.ts) qidiradi. U yerda yo'q va types sharti ham yo'q.
"types": "./types/index.d.ts" ni qaytardik:
npx -p typescript@7.0.2 tscnarx.ts(4,7): error TS2322: Type 'number | null' is not assignable to type 'number'.
Type 'null' is not assignable to type 'number'.Endi turlar ishlayapti — va ular haqiqiy xatoni topdi: priceOf menyuda yo'q taom uchun null qaytaradi. Kassa buni hisobga olishi kerak.
Eski usul — ildizdagi "types" maydoni ("types": "./types/index.d.ts"). U main ga o'xshaydi: faqat asosiy eshik uchun ishlaydi va kichik yo'llarni bilmaydi. Paketda ham turlar bo'lmasa — @types/paket (15-qism).
7. imports: paket ichidagi # taxallus
dist/index.js narxlarni shunday oladi:
// index.js — ESM kirish nuqtasi
import { prices } from "#narxlar";
export function priceOf(name) {
return prices[name] ?? null;
}
export const format = "esm";#narxlar — package.json dagi imports maydonidan:
{
"imports": {
"#narxlar": "./dist/narxlar.js"
}
}imports — exports ning ichki egizagi. exports tashqariga "nimani beraman" deydi, imports esa paketning o'zi uchun qisqa nomlar beradi. # bilan boshlanishi majburiy. Bu taxallus faqat shu paket ichida ishlaydi. Kassada import … from "#narxlar" yozsak:
TypeError [ERR_PACKAGE_IMPORT_NOT_DEFINED]: Package import specifier "#narxlar" is not defined in package …\kassa\package.json imported from …\kassa\ichki.js"#narxlar taxallusi kassaning package.json ida belgilanmagan". Node # ni har doim eng yaqin package.json dan qidiradi.
imports ilovada ham foydali: ../../../utils/format.js o'rniga #utils/format.js. Uni Node ham, TypeScript ham, Vite ham tushunadi. Path alias darsida uni @/ taxallusi bilan solishtiramiz.
8. Qolgan maydonlar: files, bin, sideEffects
8.1 files: arxivga nima tushadi
Paketda sinov/ papkasi bor (testlar). files siz npm pack --dry-run uni ham arxivga soldi (sinov/narx.test.js, jami 9 fayl). files — "faqat shularni sol" ro'yxati:
npm pkg set "files[]=dist" "files[]=types"
npm pack --dry-runnpm notice
npm notice package: bahor-narx@1.0.0
npm notice Tarball Contents
npm notice 42B README.md
npm notice 269B dist/cli.js
npm notice 114B dist/format.js
npm notice 224B dist/index.cjs
npm notice 165B dist/index.js
npm notice 127B dist/narxlar.js
npm notice 492B package.json
npm notice 148B types/index.d.ts
…
npm notice total files: 8sinov/ tushmadi. package.json va README.md esa files da bo'lmasa ham doim qo'shiladi. Oq ro'yxat (files) qora ro'yxatdan (.npmignore) xavfsizroq: yangi maxfiy fayl tasodifan nashrga tushmaydi.
8.2 bin: terminal buyrug'i
{
"bin": {
"bahor-narx": "./dist/cli.js"
}
}cli.js ning birinchi qatori — #!/usr/bin/env node ("bu faylni Node bilan ishga tushir"). Paket o'rnatilganda npm node_modules/.bin/ ga bahor-narx, bahor-narx.cmd va bahor-narx.ps1 ni yaratadi — har shell uchun bittadan. Kassada:
npx bahor-narx manti30000 so'mvite, tsc, eslint buyruqlari ham aynan shu yo'l bilan paydo bo'ladi — scripts darsidagi .bin papkasi.
8.3 sideEffects: tree shaking uchun va'da
"sideEffects": false — "mening fayllarim import qilinganda o'z-o'zidan hech narsa qilmaydi (global o'zgaruvchi, CSS, console.log)". Bundler bu va'daga ishonib, ishlatilmagan fayllarni tashlab yuboradi — bu tree shaking (ishlatilmagan kodni "silkitib tushirish") ning bir qismi. Va'da yolg'on bo'lsa, kerakli kod ham yo'qoladi. Chuqur — Tree shaking darsida.
8.4 engines va packageManager
engines ni Node versiya menejerlari darsida o'rgangansiz. packageManager ("pnpm@12.10.1") — loyiha qaysi paket menejeri bilan ishlashini aytadi, uni Corepack o'qiydi (Yarn va Bun darsida).
Barcha maydonlar bir sxemada:
| Maydon | Kim o'qiydi | Nima uchun |
|---|---|---|
exports |
Node, bundler, TS | eshiklar va shartlar |
main / module |
eski vositalar / bundler | eski kirish nuqtasi |
types |
TypeScript | eski turlar yo'li |
imports |
Node, bundler, TS | ichki # taxalluslar |
| Maydon | Kim o'qiydi | Nima uchun |
|---|---|---|
files |
npm (pack, publish) |
arxiv tarkibi |
bin |
npm (o'rnatishda) | terminal buyruqlari |
sideEffects |
bundler | tree shaking |
engines, packageManager |
npm, Corepack | muhit talabi |
Tekshirib ko'ring: Sardor
bahor-narxgadist/menyu.jsqo'shdi, lekinexportsga yozmadi.npm pack --dry-runda u bo'ladimi? Kassa uni import qila oladimi?
Javob
Arxivda bo'ladi — files da dist papkasi butunligicha. Import qilib bo'lmaydi — exports da yo'q (ERR_PACKAGE_PATH_NOT_EXPORTED). files "nima yetkaziladi", exports "nimaga kirish mumkin" degan savolga javob beradi. Paketning o'zi esa menyu.js ni nisbiy yo'l bilan yoki # taxallusi orqali bemalol ishlata oladi.
9. Ko'p uchraydigan xatolar
| Xabar | Sabab | Davosi |
|---|---|---|
ERR_PACKAGE_PATH_NOT_EXPORTED |
yo'l exports da yo'q |
hujjatdagi ochiq yo'l |
Named export '…' not found … CommonJS module |
ESM'dan CJS paket | default import yoki import sharti |
ERR_PACKAGE_IMPORT_NOT_DEFINED |
# taxallus bu package.json da yo'q |
imports ga qo'shing |
TS7016: Could not find a declaration file |
turlar topilmadi | types sharti yoki @types/… |
| Belgi | Sabab | Davosi |
|---|---|---|
require boshqa fayl oldi |
default require dan oldin |
default — oxirida |
| arxivda testlar, maxfiy fayllar | files yo'q |
files oq ro'yxati |
| buyruq topilmadi | bin yo'q yoki shebang yo'q |
bin + #!/usr/bin/env node |
npm view da tartib boshqacha |
registr javobi | node_modules/…/package.json |
10. Mashqlar
Mashqlar kurs/mashqlar/16/07-kirish/ da: bahor-narx/ va kassa/ — darsdagidek.
1-mashq (oson): web-vitals eshiklari
«Haqiqiy paket» bo'limidagi exports (fayldagi tartib bilan) bo'yicha javob bering:
import { onLCP } from "web-vitals"ochadigan fayl:require("web-vitals")ochadigan fayl:import "web-vitals/onCLS.js":import "web-vitals/dist/modules/onCLS.js"— xato kodi:
Yechim
import sharti yo'q — default oladi. require — o'z sharti bor, u default dan oldin. ./onCLS.js — ochiq kichik yo'l. Oxirgisi fayl sifatida mavjud, lekin exports da yo'q. Tekshirish uchun import.meta.resolve("web-vitals/onCLS.js") yoki require.resolve dan foydalaning.
2-mashq (o'rta): Narxlarni ochiq qiling
Telegram bot narxlar ro'yxatini butunligicha olmoqchi: import { prices } from "bahor-narx/narxlar". Hozir ERR_PACKAGE_PATH_NOT_EXPORTED. bahor-narx ga bitta qator qo'shib, kassada narxlar.js ni ishlating. Ichki fayl nomi (dist/narxlar.js) foydalanuvchiga ko'rinmasin.
Yechim
exports ga:
{
"exports": {
"./format": "./dist/format.js",
"./narxlar": "./dist/narxlar.js"
}
}(Qolgan kalitlar o'zgarmaydi.) Kassadagi narxlar.js:
// narxlar.js — 2-mashq yechimi: ochiq kichik yo'l orqali
import { prices } from "bahor-narx/narxlar";
console.log(prices);node narxlar.js{ osh: 35000, "lag'mon": 28000, manti: 30000 }Foydalanuvchi bahor-narx/narxlar ni biladi, dist/ ni emas. Ertaga fayl dist/data/narxlar.js ga ko'chsa, faqat exports dagi o'ng tomon o'zgaradi — bot sinmaydi.
3-mashq (qiyin): O'z resolver'ingiz
resolver/exports.mjs da resolveExport(exportsField, subpath, conditions) yozing — Node algoritmining soddalashtirilgan nusxasi:
exportsField— qator yoki obyekt. Hamma kalitlari.bilan boshlansa — bu yo'llar xaritasi, aks holda —"."ning qiymati.- Qiymat qator bo'lsa — javob shu. Obyekt bo'lsa — kalitlarni tartib bilan ko'rib,
defaultyokiconditionsdagi birinchi mosini oling (ichma-ich obyekt ham bo'lishi mumkin). "./taomlar/*"kabi naqshlar:*o'rniga kelgan qism o'ng tomondagi*ga qo'yiladi.- Topilmasa —
null.
exports.test.mjs da web-vitals ning haqiqiy exports parchasi bilan kamida 4 test yozing, jumladan "tartib muhim" testi.
Ishoralar: Object.entries kalitlarni yozilish tartibida beradi. Object.hasOwn(map, key) — kalit bormi. replaceAll — matnni o'zgartirish.
Yechim
exports.mjs:
// exports.mjs — package.json "exports" ni o'qiydigan resolver
// (Node algoritmining soddalashtirilgan nusxasi: massiv va null yo'q)
// Shartlar obyekti yoki qator → fayl yo'li (yoki null)
function pickTarget(target, conditions) {
if (typeof target === "string") return target;
for (const [key, value] of Object.entries(target)) {
if (key === "default" || conditions.includes(key)) {
const found = pickTarget(value, conditions);
if (found !== null) return found;
}
}
return null;
}
// exportsField — package.json dagi "exports"; subpath — "." yoki
// "./format"; conditions — masalan ["import", "node"]
export function resolveExport(exportsField, subpath, conditions) {
const isMap =
typeof exportsField === "object" &&
Object.keys(exportsField).every((key) => key.startsWith("."));
const map = isMap ? exportsField : { ".": exportsField };
if (Object.hasOwn(map, subpath)) {
return pickTarget(map[subpath], conditions);
}
// "./modules/*": "./dist/*.js" kabi naqshlar
for (const [key, value] of Object.entries(map)) {
const star = key.indexOf("*");
if (star === -1) continue;
const before = key.slice(0, star);
const after = key.slice(star + 1);
if (subpath.startsWith(before) && subpath.endsWith(after)) {
const end = subpath.length - after.length;
const middle = subpath.slice(before.length, end);
const target = pickTarget(value, conditions);
return target === null ? null : target.replaceAll("*", middle);
}
}
return null;
}
const demo = { ".": { require: "./a.cjs", default: "./a.js" } };
console.log(resolveExport(demo, ".", ["import"])); // ./a.js
console.log(resolveExport(demo, ".", ["require"])); // ./a.cjs
console.log(resolveExport(demo, "./ichki", ["import"])); // nullOxirgi to'rt qator — sinash uchun. pickTarget o'zini o'zi chaqiradi (rekursiya): { "node": { "import": "…" } } kabi ichma-ich shartlar uchun.
exports.test.mjs:
// exports.test.mjs — node --test exports.test.mjs
import { test } from "node:test";
import assert from "node:assert/strict";
import { resolveExport } from "./exports.mjs";
// web-vitals 6.2.3 ning haqiqiy "exports" idan parcha
const webVitals = {
".": {
types: "./dist/modules/index.d.ts",
require: "./dist/web-vitals.umd.cjs",
default: "./dist/web-vitals.js",
},
"./onCLS.js": {
types: "./dist/modules/onCLS.d.ts",
default: "./dist/modules/onCLS.js",
},
};
test("shartlar: import, require, types", () => {
const imp = ["import", "node"];
const req = ["require", "node"];
assert.equal(
resolveExport(webVitals, ".", imp),
"./dist/web-vitals.js",
);
assert.equal(
resolveExport(webVitals, ".", req),
"./dist/web-vitals.umd.cjs",
);
assert.equal(
resolveExport(webVitals, ".", ["types", "import"]),
"./dist/modules/index.d.ts",
);
});
test("kichik yo'llar va ochilmagan fayl", () => {
const imp = ["import"];
assert.equal(
resolveExport(webVitals, "./onCLS.js", imp),
"./dist/modules/onCLS.js",
);
const hidden = "./dist/web-vitals.js";
assert.equal(resolveExport(webVitals, hidden, imp), null);
});
test("qator va naqsh (*)", () => {
const only = resolveExport("./index.js", ".", ["import"]);
assert.equal(only, "./index.js");
const map = { "./taomlar/*": "./dist/taomlar/*.js" };
assert.equal(
resolveExport(map, "./taomlar/osh", ["import"]),
"./dist/taomlar/osh.js",
);
const tea = resolveExport(map, "./ichimlik/choy", ["import"]);
assert.equal(tea, null);
});
test("tartib muhim: birinchi mos shart yutadi", () => {
const wrong = { default: "./a.js", require: "./b.cjs" };
assert.equal(resolveExport(wrong, ".", ["require"]), "./a.js");
});ℹ tests 4
ℹ pass 4
ℹ fail 0Oxirgi test — «Shartlar tartibi» bo'limidagi haqiqiy Node xulqi (a.js (default)) bilan bir xil. Haqiqiy Node algoritmi yana massivlar, null qiymatlar va bir nechta * qoidalarini biladi — u Node hujjatida "Resolution algorithm" bo'limida to'liq yozilgan.
11. Real ishda
ERR_PACKAGE_PATH_NOT_EXPORTEDpaket yangilangandan keyin ko'p chiqadi: yangi versiyaexportsqo'shib, eski ichki yo'llarni yopgan. Yechim — changelog'dan yangi yo'lni topish, eski versiyada qolish emas.- Kutubxona chiqarganda
exports+types+files— minimal to'plam.npm pack --dry-runni har nashrdan oldin ko'ring. "Are The Types Wrong?" (arethetypeswrong.github.io) kabi vositalar paketingizning eshiklarini avtomatik tekshiradi. - Monorepolarda
importsvaexportsichki paketlar orasidagi chegarani belgilaydi. - Intervyu: "
mainvaexportsfarqi?", "dual package nima va uning xavfi?", "sideEffects: falsenima beradi?".
Xulosa
exportsbor bo'lsa, Nodemainga qaramaydi; ro'yxatda yo'q yo'l —ERR_PACKAGE_PATH_NOT_EXPORTED.- Shartlar tartib bilan o'qiladi:
typesbirinchi,defaultoxirida;import/require— ikki formatli paket. main— eski yagona kirish,module— bundler'larning eski maydoni, ildizdagitypes— eski turlar yo'li.imports— paket ichidagi#taxalluslar; Node uni eng yaqinpackage.jsondan oladi.files— arxiv oq ro'yxati,bin—node_modules/.bindagi buyruq,sideEffects— tree shaking va'dasi.- "Qaysi fayl ochildi?" —
require.resolvevaimport.meta.resolve.
Keyingi dars: Semver va versiya diapazonlari — ^, ~, >=, || va 0.x tuzog'i: package.json dagi versiya yozuvi qaysi yangilanishni o'tkazadi.
Manbalar
- Node.js Docs (v24): Modules: Packages — exports, imports, conditional exports, dual package hazard
- npm Docs (v11): package.json — main, files, bin, exports
- TypeScript Handbook: Modules Reference — package.json "exports"
- webpack Docs: Tree Shaking — sideEffects
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!