Mundarija (28)
- Bu darsda
- 1. Nega bu kerak?
- 2. ESM'dan CommonJS: nomli eksportlar qayerdan keladi
- 2.1 Muammo
- 2.2 Kanon topilmasi va kengaytirilgan tajriba
- 3. CommonJS'dan ESM: require(esm)
- 3.1 Qanday ishlaydi
- 3.2 Faqat default bo'lsa — va "module.exports" eksporti
- 3.3 To'siq: top-level await
- 4. createRequire — ESM ichida require
- 5. Dual package hazard — Node'da o'lchab
- 5.1 Ikki nusxa
- 5.2 require(esm) bilan yechim
- 5.3 Modul yuklash hooklari haqida
- 6. CLI qadami: paket tuzilmasi (holat 12, 2-qism)
- 6.1 Nega index.ts da TLA yo'q — bu darsning markaziy qarori
- 6.2 To'liq package.json (holat 12)
- 6.3 Tekshiruv va o'lchov
- 6.4 Commit
- 7. Ko'p uchraydigan xatolar
- 8. Mashqlar
- 1-mashq (oson): lexer nimani ko'radi?
- 2-mashq (o'rta): require uchun qulay ESM
- 3-mashq (qiyin): TLA'ni kutubxonadan chiqaring
- 4-mashq: CLI qadami — holat 12 ni yakunlang
- 9. Real ishda
- Xulosa
- Manbalar
CJS va ESM birga: require(esm), interop va dual package hazard
Qisqacha: Node 24 da ikki modul tizimi ikki tomonga "gaplasha" oladi. ESM → CJS:
importCommonJS faylni yuklaydi;module.exportsdoimdefaultbo'ladi, nomli eksportlar esa faqat Node ularni statik taniy olsa (exports.x = …,module.exports = { x }) —module.exports = { x: 3 }dagixtanilmadi (o'lchandi). CJS → ESM:require(esm)bayroqsiz ishlaydi (Node 20.19+ / 22.12+) va modul nomlar maydonini qaytaradi — lekin ESM ichida top-levelawaitbo'lsa,ERR_REQUIRE_ASYNC_MODULE. ESM ichidarequirekerak bo'lsa —createRequire(import.meta.url). Paket ikki formatni alohida fayllarda bersa — dual package hazard: bitta klassning ikki nusxasi. Shu darsdavalyutapaket tuzilmasini oladi va CommonJS loyihalar unirequireqila oladi.
Bu darsda
- ESM'dan CommonJS import qilganda qaysi nomli eksportlar ko'rinishini oldindan ayta olasiz.
require(esm)qachon ishlashini va qachonERR_REQUIRE_ASYNC_MODULEberishini bilasiz.createRequirebilan ESM ichidarequire, JSON va CommonJS-faqat paketlarni ishlatasiz.- Dual package hazard'ni Node'da o'lchab ko'rsatasiz va undan qochish yo'llarini tanlaysiz.
valyutani npm paket tuzilmasiga keltirasiz:bin,exports,files,prepack, kutubxona va CLI ajratilgan.
Oldin bilishingiz kerak: ES Modules Node'da, CommonJS ichidan, CommonJS va ESM bilan o'zaro ishlash, Modul formatlari: IIFE, UMD, CJS, ESM.
1. Nega bu kerak?
npm'da millionlab paket bor va ularning katta qismi hali ham CommonJS. Yangilari esa ko'pincha faqat ESM. Sizning loyihangiz qaysi tizimda bo'lmasin, ertami-kechmi ikkinchisidan paket kerak bo'ladi. 2024 yil oxirigacha (Node 22.12 gacha) bu og'riqli edi: CommonJS loyihada ESM paketni require qilsangiz — ERR_REQUIRE_ESM xatosi, yagona yo'l — asinxron import().
CommonJS va ESM bilan o'zaro ishlash darsida asoslarni ko'rdingiz. require(esm) Node 24 da ishlaydi, top-level await esa uni to'xtatadi. Modul formatlari darsida esa bundler nuqtai nazaridan default export tuzog'i va dual package hazard'ni o'rgandingiz. Bu dars — Node ichidagi mexanizm va uni o'z paketingizga qo'llash.
valyuta uchun savol aniq: u ESM paket, ichida top-level await bor (bin.ts). CommonJS'da yozilgan boshqa loyiha require("valyuta") qila oladimi? Kanon buni tekshirdi — javob "ha", lekin faqat bitta to'g'ri qaror tufayli.
O'xshatish: ikki tilli ofis. Bir xodim faqat o'zbekcha, boshqasi faqat ruscha yozadi. Tarjimon (Node interop) ko'p hujjatni o'giradi. Lekin ba'zi hujjatlarda "keyinroq to'ldiriladi" degan bo'sh joy bor (top-level await) — tarjimon ularni kutib o'tira olmaydi va qaytaradi.
Diagrammada ikki yo'nalishni va har birining chegarasini ko'ring — darsning qolgan qismi shu to'rt o'qni ochadi:
flowchart LR
E["ESM fayl"] -->|"import: default = module.exports,<br/>nomlilar — lexer tanisa"| C["CommonJS fayl"]
C -->|"require(esm): nomlar maydoni,<br/>TLA bo'lsa — xato"| E
E -.->|"createRequire"| C
C -.->|"await import()"| E2. ESM'dan CommonJS: nomli eksportlar qayerdan keladi
2.1 Muammo
ESM statik: import { a } from "./x.js" ni bog'lash uchun Node x.js da a borligini bajarishdan oldin bilishi kerak (ES Modules Node'da darsidagi tartib). CommonJS esa dinamik: module.exports faqat fayl bajarilgandan keyin ma'lum. Bu ziddiyatni Node cjs-module-lexer bilan yechadi — CommonJS faylning matnini "tez ko'zdan kechirib", eksport nomlarini taxmin qiladigan kichik tahlilchi.
2.2 Kanon topilmasi va kengaytirilgan tajriba
Kanon tajribasida module.exports = { c: 3 }; module.exports.d = 4; faylini import() qilganda natija:
import(cjs): [Module: null prototype] {
d: 4,
default: { c: 3, d: 4 },
'module.exports': { c: 3, d: 4 }
}d nomli eksport bo'ldi, c — yo'q! Uch xil yozuvni solishtiramiz:
import { writeFileSync } from "node:fs";
writeFileSync("lit.cjs", "module.exports = { c: 3 };");
writeFileSync("short.cjs",
"const c = 3; const d = 4; module.exports = { c, d };");
writeFileSync("dot.cjs", "exports.c = 3; exports.d = 4;");
for (const name of ["lit", "short", "dot"]) {
const mod = await import(`./${name}.cjs`);
console.log(name, Object.keys(mod).join(","));
}Konsolda:
lit default,module.exports
short c,d,default,module.exports
dot c,d,default,module.exports| Yozuv | Lexer taniydimi |
|---|---|
exports.c = 3 / module.exports.c = 3 |
ha |
module.exports = { c, d } (qisqa yozuv) |
ha |
module.exports = { c: 3 } (qiymat — literal) |
yo'q |
Lexer kodni bajarmaydi, faqat naqshlarni qidiradi. Obyekt literalida identifikator (c yoki c: c) bo'lsa — taniydi, qiymat murakkab bo'lsa — to'xtaydi. Natija: import { c } from "./lit.cjs" — xato, import lit from "./lit.cjs"; lit.c — ishlaydi.
Ikkita doimiy qoida:
default— doimmodule.exportsning o'zi. Shuning uchun CommonJS paketdanimport pkg from "pkg"hech qachon yolg'on gapirmaydi.'module.exports'nomli eksport — Node 24 ning yangiligi:defaultbilan bir xil qiymat, lekin "bu CommonJS'ningmodule.exportsi" degan aniq nom bilan.
Maslahat: CommonJS paketdan nomli import xato bersa (
Named export 'c' not found. The requested module './lit.cjs' is a CommonJS module, which may not support all module.exports as named exports.), tuzatish oddiy:import pkg from "pkg"; const { c } = pkg;— xabarning o'zi shuni taklif qiladi (CommonJS va ESM bilan o'zaro ishlash darsidagi xato).
3. CommonJS'dan ESM: require(esm)
3.1 Qanday ishlaydi
Node 22.12 dan (20.19 ga ham qaytarilgan) va Node 24 da bayroqsiz: require("./x.mjs") ESM faylni sinxron yuklaydi va modul nomlar maydonini qaytaradi. Buni tekshirish uchun xususiyat: process.features.require_module. Kanon (Node 24, bayroqsiz):
require(esm): [Module: null prototype] { __esModule: true, a: 1, default: 'sukut' } | __esModule: true
process.features.require_module: true__esModule: true — eski bundlerlar va TypeScript kelishuvi: "bu CommonJS ko'rinishidagi ESM, default ni alohida ko'r". Node uni ESM'da default eksport bo'lsa avtomatik qo'shadi — eski CommonJS kodi require(x).default ni to'g'ri tushunishi uchun.
3.2 Faqat default bo'lsa — va "module.exports" eksporti
Faqat default eksportli ESM'ni require qilsangiz, funksiya emas, obyekt olasiz — funksiya uning default xususiyatida. Bu — Modul formatlari darsidagi "default export tuzog'i"ning Node'dagi shakli. Node 24 da ESM muallifi require natijasini o'zi belgilay oladi: "module.exports" nomi bilan eksport:
import { writeFileSync } from "node:fs";
import { createRequire } from "node:module";
writeFileSync("only.mjs",
'export default function salom() { return "salom"; }');
writeFileSync("me.mjs",
'const api = { v: 1 };\nexport { api as "module.exports" };\n');
const require = createRequire(import.meta.url);
const only = require("./only.mjs");
console.log(typeof only, typeof only.default, only.__esModule);
console.log(require("./me.mjs"));Konsolda:
object function true
{ v: 1 }createRequire haqida — pastda; hozir u shunchaki ESM ichida require beradi. Birinchi qator: require funksiyani emas, obyektni berdi. Ikkinchisi: "module.exports" eksporti bo'lsa, require aynan uni qaytaradi — CommonJS foydalanuvchisi require("pkg")() deb to'g'ridan chaqira oladi.
3.3 To'siq: top-level await
require — sinxron. Top-level await li ESM esa yuklanishi uchun vaqt kutishi kerak. Ikkalasini birlashtirib bo'lmaydi:
const { writeFileSync } = require("node:fs");
writeFileSync("tla.mjs",
"await Promise.resolve();\nexport const b = 2;\n");
try {
require("./tla.mjs");
} catch (e) {
console.log(e.code);
}Konsolda:
ERR_REQUIRE_ASYNC_MODULETo'liq xabar (kanon): require() cannot be used on an ESM graph with top-level await. Use import() instead. To see where the top-level await comes from, use --experimental-print-required-tla. — "top-level await bor ESM grafiga require() ishlatib bo'lmaydi. import() ishlating. Await qayerdan kelayotganini ko'rish uchun — --experimental-print-required-tla bayrog'i". Graf so'ziga e'tibor bering: await require qilingan faylning o'zida bo'lmasa ham, u import qiladigan istalgan modulda bo'lsa — xato.
Tekshirib ko'ring:
index.mjsda TLA yo'q, lekin uconfig.mjsni import qiladi,config.mjsda esaconst sozlama = await readFile(...). CommonJS loyiharequire("./index.mjs")qila oladimi?
Javob
Yo'q — ERR_REQUIRE_ASYNC_MODULE. Tekshiruv butun import grafiga qaraydi. Yechim: config.mjs dagi o'qishni funksiyaga o'rash (export async function sozlamaniOl()), shunda graf sinxron bo'ladi. Yoki CommonJS tarafida await import("./index.mjs").
4. createRequire — ESM ichida require
ESM'da require yo'q (Global obyektlar). Lekin ba'zan kerak: faqat CommonJS'ga mo'ljallangan paket, require.resolve, yoki JSON'ni atributsiz sinxron o'qish. Buning uchun node:module dagi createRequire:
import { createRequire } from "node:module";
import { writeFileSync } from "node:fs";
writeFileSync("sozlama.json", '{ "til": "uz" }');
const require = createRequire(import.meta.url);
console.log(require("./sozlama.json").til);
console.log(require.resolve("node:fs"));
console.log(typeof require.cache);Konsolda:
uz
node:fs
objectcreateRequire(import.meta.url) — "joriy faylga nisbatan ishlaydigan require yasab ber". Nisbiy yo'llar shu faylga nisbatan hisoblanadi, kesh — umumiy require.cache. Yangi kodda kam kerak bo'ladi: JSON uchun import attributes, ESM paketlar uchun import bor. Lekin eski kutubxonalar bilan ishlaganda — eng toza ko'prik.
5. Dual package hazard — Node'da o'lchab
5.1 Ikki nusxa
Modul formatlari darsida bundler misolida ko'rgansiz: paket exports da import uchun bitta fayl, require uchun boshqa fayl bersa, bitta dasturda kutubxonaning ikki nusxasi yuklanishi mumkin. Node'ning o'zida tekshiramiz — blok node_modules da kichik ikki formatli paket yaratadi:
import { writeFileSync, mkdirSync } from "node:fs";
import { createRequire } from "node:module";
const dir = "node_modules/kurs-lib";
mkdirSync(dir, { recursive: true });
writeFileSync(`${dir}/package.json`, JSON.stringify({
name: "kurs-lib",
exports: { import: "./index.mjs", require: "./index.cjs" },
}));
writeFileSync(`${dir}/index.mjs`,
"export class Kurs {}\nexport const counter = { n: 0 };\n");
writeFileSync(`${dir}/index.cjs`,
"class Kurs {}\nmodule.exports = { Kurs, counter: { n: 0 } };\n");
const esm = await import("kurs-lib");
const cjs = createRequire(import.meta.url)("kurs-lib");
esm.counter.n++;
console.log(esm.Kurs === cjs.Kurs);
console.log(new esm.Kurs() instanceof cjs.Kurs);
console.log(esm.counter.n, cjs.counter.n);Konsolda:
false
false
1 0Bitta dasturda kurs-lib ning ikki Kurs klassi va ikki counter i bor. ESM tarafida yaratilgan obyekt CommonJS tarafdagi instanceof dan o'tmaydi, holat esa ikkiga bo'lindi. Real hayotda bu shunday ko'rinadi: kutubxona "agar xato mening ValidationError imda bo'lsa" deb tekshiradi — va tekshiruv sababsiz false beradi.
5.2 require(esm) bilan yechim
Bu xavf aynan "ikki format — ikki fayl" yondashuvidan kelib chiqadi. Node 24 da require(esm) ishlagani uchun eng sodda yechim — faqat ESM nashr qilish: bitta fayl, exports da bitta yo'l. CommonJS foydalanuvchisi require qiladi va o'sha modulni oladi. Shart bitta — ESM grafida top-level await bo'lmasin. Modul formatlari darsidagi ikkinchi yechim aynan shu edi; endi uning Node'dagi asosini — require(esm) va uning chegarasini — bilasiz.
| Yondashuv | Ikki nusxa xavfi | Talab |
|---|---|---|
| ESM + CJS alohida fayllar | bor | hech narsa — eski Node ham |
| ESM "eshik" → CJS kod | yo'q | kod CommonJS'da |
| Faqat ESM | yo'q | Node 20.19+ / 22.12+, TLA yo'q |
5.3 Modul yuklash hooklari haqida
Node'da modul yuklashni o'zgartiradigan hooklar ham bor (masalan, .yaml faylni import qilish yoki testlarda modulni almashtirish). Ikki API bor:
| API | Qanday | Holati (Node hujjati, 2026-10) |
|---|---|---|
module.register() |
asinxron, alohida oqimda | eskirgan (deprecated, DEP0205): Node 24.15 dan hujjatda; Node 26 da ishlatsangiz ogohlantirish chiqadi |
module.registerHooks() |
sinxron, shu oqimda | Node 22.15 / 23.5 dan; "release candidate" — barqarorlikka yaqin |
Node 24.21 da ikkalasi ham ishlaydi. Biz module.register() ni chaqirib ko'rdik — ogohlantirish chiqmadi, chunki 24-versiyada eskirish faqat hujjatda. Node 26 da u hali bor, lekin har chaqiruvda ogohlantirish beradi. Hujjat uni "kelgusi versiyada olib tashlanadi" deydi, aniq versiyani aytmaydi. Xulosa: yangi kod yozsangiz — faqat registerHooks. Bu chuqur mavzu, kundalik ishda test vositalari uni sizning o'rningizga ishlatadi.
6. CLI qadami: paket tuzilmasi (holat 12, 2-qism)
ES Modules Node'da darsida bin.ts, index.ts va self-reference'ni ko'rdingiz. Endi holat 12 ni yakunlaymiz va commit qilamiz.
6.1 Nega index.ts da TLA yo'q — bu darsning markaziy qarori
valyuta ning bin.ts faylida top-level await bor: process.exitCode = await main(…). Agar kutubxona kirishi ham shu fayl bo'lganida, CommonJS loyiha uni require qila olmasdi — ERR_REQUIRE_ASYNC_MODULE. Holat 12 da exports["."] — dist/index.js, u esa faqat kurs.ts va manba.ts ni qayta eksport qiladi. Ularda TLA yo'q. Biz kanon holat 12 da CommonJS fayldan tekshirdik:
// req.cjs — valyuta papkasida (self-reference), build'dan keyin
const v = require("valyuta");
console.log(Object.keys(v).length, typeof v.konvert);
try {
require("./dist/bin.js");
} catch (e) {
console.log(e.code);
}9 function
ERR_REQUIRE_ASYNC_MODULEKutubxona — 9 eksport, CommonJS'dan bemalol. Kirish fayli (bin.js) esa require qilinmaydi — u buyruq sifatida ishga tushiriladi, kutubxona emas. Kanon hisobotida ham xuddi shu xulosa: "kutubxona kirishi index.ts da TLA yo'q, shuning uchun CJS loyihalar ham require("valyuta") qila oladi — tekshirildi: 9 eksport". Bitta paketda — ikki format, ikki nusxa xavfisiz.
6.2 To'liq package.json (holat 12)
{
"name": "valyuta",
"version": "0.2.0",
"description": "O'zbekiston Markaziy banki valyuta kurslari terminalda",
"keywords": ["valyuta", "kurs", "cbu", "cli"],
"license": "MIT",
"type": "module",
"bin": {
"valyuta": "dist/bin.js"
},
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"./package.json": "./package.json"
},
"files": ["dist", "fixtures"],
"engines": {
"node": ">=24"
},
"scripts": {
"start": "node src/bin.ts",
"build": "tsc -p tsconfig.build.json",
"prepack": "npm run build",
"test": "node --test \"test/**/*.test.ts\"",
"tip": "tsc --noEmit",
"lint": "eslint . --max-warnings=0",
"check": "npm run tip && npm run lint && npm test"
},
"devDependencies": {
"@eslint/js": "10.0.1",
"@types/node": "24.19.2",
"eslint": "10.12.0",
"typescript": "6.0.3",
"typescript-eslint": "8.71.2"
}
}(Kanon faylida keywords va files massivlari har elementi alohida qatorda — mazmuni bir xil.) Holat 08 dan farqlar:
| Maydon | Nima | Nega |
|---|---|---|
"private" olib tashlandi |
paket nashr qilinishi mumkin | O'z npm paketingiz |
version 0.2.0, license, keywords |
pasport | npm sahifasi uchun |
bin |
valyuta buyrug'i → dist/bin.js |
o'rnatilganda terminal buyrug'i |
exports |
ochiq yuz — faqat index va package.json |
ichki fayllar yopiq |
files |
paketga faqat dist va fixtures |
test, src, tsconfig kirmaydi |
build, prepack |
pack/publish oldidan avtomatik build | dist doim yangi |
"./package.json": "./package.json" — ba'zi vositalar paketning versiyasini o'qish uchun pkg/package.json ni import qiladi; exports bo'lgani uchun uni alohida ochish kerak.
6.3 Tekshiruv va o'lchov
npm run build && npm run check — kanon natijasi (tekshiruv-12.txt): build 2.1 s, tip 0, lint 0, test 10/10. npm pack --dry-run endi:
Tarball Contents
31B dist/bin.d.ts
333B dist/bin.js
2.8kB dist/cli.js
159B dist/index.d.ts
279B dist/index.js
2.0kB dist/kurs.js
681B dist/manba.js
25.5kB fixtures/kurslar-2026-10-23.json
978B package.json
package size: 10.1 kB
unpacked size: 40.9 kB
total files: 17(Qisqartirilgan: kanon ro'yxatida yana .d.ts va .js.map fayllar — jami 17.) Holat 08 da paketda 9 fayl edi, jumladan testlar va tsconfig.json. Endi files tufayli faqat kerakli narsa: build natijasi, tiplar (.d.ts), source map (.map) va fixture.
Sovuq start (mediana, n=10): dist/bin.js --help — 122 ms, kurs USD — 133 ms. Holat 08 da .ts bilan 127 va 171 ms edi. Farq qayerdan — tiplarni o'chirishmi yoki boshqa sababmi — TypeScript'ni Node'da to'g'ridan darsida toza o'lchanadi.
6.4 Commit
git add .
git commit -m "Paket tuzilmasi: tsc build (dist), bin, exports, files" \n -m "Kutubxona API (index.ts)"Kanon commit xabari bitta qator: Paket tuzilmasi: tsc build (dist), bin, exports, files; kutubxona API (index.ts). U 72 belgidan uzun, shuning uchun sarlavha va tanaga bo'ldik (commit xabarlari).
.gitignore da dist/ bor — build natijasi repoga tushmaydi, u prepack da qayta yasaladi.
7. Ko'p uchraydigan xatolar
| Xato | Sabab | Davosi |
|---|---|---|
SyntaxError: Named export 'c' not found. The requested module './lit.cjs' is a CommonJS module, which may not support all module.exports as named exports. |
lexer nomni tanimadi | import pkg from …; const { c } = pkg; |
ERR_REQUIRE_ASYNC_MODULE |
ESM grafida top-level await |
await import() yoki TLA'ni olib tashlash |
ERR_REQUIRE_ESM |
eski Node (20.19 / 22.12 dan oldin) | Node'ni yangilang yoki import() |
require(esm) funksiya emas, obyekt berdi |
faqat default eksport |
.default yoki "module.exports" eksporti |
instanceof sababsiz false |
dual package hazard | faqat ESM yoki ESM "eshik" |
require is not defined in ES module scope |
ESM'da require |
createRequire(import.meta.url) |
8. Mashqlar
Mashqlar kurs/mashqlar/24/12-interop/ da.
1-mashq (oson): lexer nimani ko'radi?
ESM'dan import * as m from "./x.cjs" qilinadi. Qaysi holatda m.narx nomli eksport sifatida bor (ha/yo'q)?
exports.narx = 35000;—module.exports = { narx: 35000 };—const narx = 35000; module.exports = { narx };—- Har uchala holatda
m.default.narxbormi —
Yechim
- ha —
exports.x =naqshi. - yo'q — obyekt literalida qiymat literal (
35000), lexer to'xtaydi. - ha — qisqa yozuv (
{ narx }) identifikator, lexer taniydi. - ha —
defaultdoimmodule.exportsning o'zi; u kod bajarilgandan keyin to'liq.
2-mashq (o'rta): require uchun qulay ESM
format.mjs faylini (blok ichida) yarating: u sonniYoz(n) funksiyasini (n.toFixed(2)) "module.exports" nomi bilan eksport qilsin, shunda CommonJS kodi require("./format.mjs")(5) deb to'g'ridan chaqira olsin. ESM tarafida esa import { sonniYoz } ham ishlasin. Ikkalasini sinang: natija 5.00 va 7.50.
Yechim
import { writeFileSync } from "node:fs";
import { createRequire } from "node:module";
writeFileSync("format.mjs", `
export function sonniYoz(n) {
return n.toFixed(2);
}
export { sonniYoz as "module.exports" };
`);
const require = createRequire(import.meta.url);
const fromCjs = require("./format.mjs");
const { sonniYoz } = await import("./format.mjs");
console.log(fromCjs(5));
console.log(sonniYoz(7.5));Konsolda:
5.00
7.50Bitta funksiya ikki nom bilan eksport qilindi: oddiy nomli (ESM uchun) va "module.exports" (CommonJS require uchun). require endi nomlar maydonini emas, funksiyaning o'zini qaytaradi — eski CommonJS paketlaridagi module.exports = fn uslubi saqlanib qoladi, kod esa ESM'da.
3-mashq (qiyin): TLA'ni kutubxonadan chiqaring
Blok ichida uch fayl yarating. config.mjs: export const til = await Promise.resolve("uz"); (top-level await). lib.mjs: config.mjs dan til ni import qilib, salom() funksiyasini eksport qiladi. main.cjs: require("./lib.mjs") qiladi. Avval main.cjs ni bola jarayonda ishga tushiring va xato kodini ko'ring. Keyin config.mjs ni TLA'siz qilib qayta yozing (export function tilniOl() { return "uz"; }, lib.mjs ham shunga mos) va yana ishga tushiring.
Yechim
import { writeFileSync } from "node:fs";
import { spawnSync } from "node:child_process";
const run = () => {
const r = spawnSync(process.execPath, ["main.cjs"], {
encoding: "utf8",
});
return (r.stdout + r.stderr).match(/ERR_[A-Z_]+|salom: \w+/)?.[0];
};
writeFileSync("main.cjs",
'const { salom } = require("./lib.mjs");\nconsole.log(salom());\n');
writeFileSync("config.mjs",
'export const til = await Promise.resolve("uz");\n');
writeFileSync("lib.mjs", 'import { til } from "./config.mjs";\n' +
"export const salom = () => `salom: ${til}`;\n");
console.log(run());
writeFileSync("config.mjs",
'export function tilniOl() { return "uz"; }\n');
writeFileSync("lib.mjs", 'import { tilniOl } from "./config.mjs";\n' +
"export const salom = () => `salom: ${tilniOl()}`;\n");
console.log(run());Konsolda:
ERR_REQUIRE_ASYNC_MODULE
salom: uzBirinchi urinishda await lib.mjs da emas, uning bog'liqligida — baribir xato: tekshiruv butun grafga qaraydi. TLA funksiyaga o'ralgach, graf sinxron va require ishladi. valyuta dagi qaror (TLA faqat bin.ts da, kutubxona kirishida emas) aynan shu.
4-mashq: CLI qadami — holat 12 ni yakunlang
package.json ni «To'liq package.json» bo'limidagidek yangilang, tsconfig.build.json qo'shing (ES Modules Node'da darsida ko'rsatilgan). Keyin:
npm run build && npm run check— 10/10.npm pack --dry-run— nechta fayl?test/vatsconfig.jsonbormi?- Loyiha papkasida
req.cjsyarating (yuqoridagi «Negaindex.tsda TLA yo'q» blokidagidek) vanode req.cjs—9 functionvaERR_REQUIRE_ASYNC_MODULEchiqdimi? - Commit:
Paket tuzilmasi: tsc build (dist), bin, exports, files; kutubxona API (index.ts).
Yechim
prepackhozircha ishlamaydi (pack qilinmadi), lekinnpm run builddist/ni yaratadi — 15 fayl (5 modul ×.js,.d.ts,.js.map).- 17 fayl, 10.1 kB:
dist/(15),fixtures/(1),package.json. Test vatsconfigyo'q —filesishladi. - Ha.
req.cjsni commit qilmang — u tajriba fayli (yoki tekshirgach o'chiring). git log --oneline— ikki commit.
9. Real ishda
- ESM-faqat paketlar —
chalk5,execa,nanoidkabi paketlar faqat ESM. Node 20.19+ / 22.12+ dan oldin CommonJS loyihalar ularni faqatimport()bilan yuklay olardi; endirequireham ishlaydi (TLA bo'lmasa). - Kutubxona muallifi qarori — 2026 yilda yangi kutubxonalar odatda faqat ESM chiqaradi va CommonJS foydalanuvchilarni
require(esm)ga qoldiradi. Eski Node'ni qo'llab-quvvatlash kerak bo'lsa —tsupyokitsdownbilan ikki format (va dual hazard'ni hisobga olish). - NestJS va boshqa CommonJS freymvorklar — hali ko'p backend kodi CommonJS'da kompilyatsiya qilinadi. ESM paketni ulashda shu darsdagi qoidalar kerak bo'ladi.
- Intervyu savoli: "
require(esm)qachon ishlamaydi?" — ESM grafida top-levelawaitbo'lsa (ERR_REQUIRE_ASYNC_MODULE) va eski Node versiyalarida.
Xulosa
- ESM → CJS:
default=module.exports; nomli eksportlar — faqat cjs-module-lexer tanigan naqshlar (exports.x,{ x }),{ x: 3 }— yo'q. - CJS → ESM:
require(esm)Node 24 da bayroqsiz; natija — nomlar maydoni (__esModule: true),"module.exports"eksporti uni almashtiradi. - ESM grafida top-level
await—ERR_REQUIRE_ASYNC_MODULE; TLA'ni kirish faylida qoldiring, kutubxonada emas. createRequire(import.meta.url)— ESM ichidarequire.- Ikki formatli paket — ikki nusxa (
instanceof→false, o'lchandi);require(esm)davrida yechim — faqat ESM. valyuta:bin(TLA bilan) vaexports(TLA'sizindex) ajratildi, CommonJS'danrequire— 9 eksport; paket 17 fayl, 10.1 kB.
Keyingi dars: Workspaces va monorepo asoslari — bir repoda bir nechta paket: npm workspaces, workspace:* va kanon tajribasi nega valyuta bitta paket bo'lib qolganini ko'rsatadi.
Manbalar
- Node.js hujjati — Modules: CommonJS — Loading ECMAScript modules using
require(): https://nodejs.org/docs/latest-v24.x/api/modules.html#loading-ecmascript-modules-using-require - Node.js hujjati — ECMAScript modules — Interoperability with CommonJS (cjs-module-lexer,
module.exportseksporti): https://nodejs.org/docs/latest-v24.x/api/esm.html#interoperability-with-commonjs - Node.js hujjati —
module.createRequire,module.register(Stability 0, v24.15.0 dan eskirgan),module.registerHooks(Stability 1.2): https://nodejs.org/docs/latest-v24.x/api/module.html - Node.js hujjati — DEP0205
module.register()(v25.9.0 hujjatda, v26.0.0 runtime ogohlantirish, olib tashlash — "kelgusi versiyada"): https://nodejs.org/api/deprecations.html#dep0205-moduleregister - Node.js hujjati — Packages: dual package hazard: https://nodejs.org/docs/latest-v24.x/api/packages.html#dual-package-hazard
- cjs-module-lexer (qaysi naqshlar taniladi): https://github.com/nodejs/cjs-module-lexer
- Kanon:
valyutaholat 12 (tekshiruv-12.txt),t12-interop.txt(require(esm), TLA, import(cjs)) — Node 24.21.0, Windows 11, 2026-10-23; lexer naqshlari,"module.exports"eksporti, dual hazard,createRequire, CommonJS'danrequire("valyuta")— yozuvchi o'lchovi, xuddi shu mashina.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!