Mundarija (30)
- Bu darsda
- 1. Nega bu kerak?
- 2. Bitta kod — to'rt qadoq
- 2.1 Manba
- 2.2 ESM
- 2.3 CommonJS
- 2.4 IIFE
- 2.5 UMD
- 3. Har format qayerda yiqiladi
- 3.1 Brauzerda
- 3.2 Node'da
- 4. Kutubxona formatlarni qanday e'lon qiladi
- 4.1 exports shartlari
- 4.2 Bundler formatni qanday "ko'radi"
- 5. Default export tuzog'i
- 5.1 Muammo
- 5.2 Bundlerlarda — ikki xil natija
- 5.3 Xavfsiz yozuv
- 6. Dual package hazard
- 6.1 Ikki nusxa
- 6.2 Ikki yechim
- 7. Import maps — bundlersiz yo'l
- 8. Ko'p uchraydigan xatolar
- 9. Mashqlar
- 1-mashq (oson): Formatni ayting
- 2-mashq (o'rta): To'rt formatni yig'ing
- 3-mashq (qiyin): Format aniqlovchi
- 10. Real ishda
- Xulosa
- Manbalar
Modul formatlari: IIFE, UMD, CommonJS va ESM — tooling nuqtai nazaridan
Qisqacha: Bitta JavaScript kodini to'rt xil "qadoq"da yetkazish mumkin. IIFE —
<script>bilan ulanadigan, bitta global o'zgaruvchi yaratadigan fayl. CommonJS (require,module.exports) — Node'ning eski formati. UMD — ikkalasida ham ishlaydigan "universal" o'ram. ESM (import/export) — zamonaviy standart. Bundler bir formatdan boshqasiga o'gira oladi, lekin aralashganda tuzoqlar bor: brauzerdarequire is not defined, CommonJS'dan kelgandefaultning noto'g'ri bo'lishi va paketning ikki nusxasi (dual package hazard).
Bu darsda
- Bitta manba koddan rollup bilan to'rt formatni yig'ib, farqini o'qiysiz.
- Har format qayerda (brauzer
<script>,type="module", Node) ishlashini va qayerda yiqilishini bilasiz. require is not defined,exports is not defined,Cannot use import statement outside a modulexatolarining sababini topasiz.- CommonJS paketdan
defaultimport qilish tuzog'ini tushunasiz va xavfsiz yozasiz. - Dual package hazard nima ekanini ko'rasiz va undan qochishni bilasiz.
Oldin bilishingiz kerak: CommonJS va ESM bilan o'zaro ishlash, Brauzerda ESM va import maps, IIFE, package.json IV: kirish nuqtalari.
1. Nega bu kerak?
CommonJS va ESM darsida ikki modul tizimini Node'da o'rgandik: require va import, "type": "module", .cjs va .mjs. U dars — til haqida edi. Bu dars — asboblar haqida: kutubxona qanday "qadoqlanadi" va bundler uni qanday o'qiydi.
Sardor node_modules/web-vitals/dist/ papkasini ochdi. vazifalar ishlatadigan bu kichik kutubxonada bitta kod uchun uch xil fayl turibdi:
8991 web-vitals.iife.js
9180 web-vitals.umd.cjs
8967 web-vitals.jsHajmlari deyarli bir xil (baytlarda, wc -c bilan o'lchandi). Ichida bir xil funksiyalar. Nega uchta? Chunki kutubxona muallifi bilmaydi: siz uni <script> bilan ulaysizmi, eski Node loyihasida require qilasizmi yoki Vite bilan import qilasizmi. U har holat uchun alohida qadoq tayyorlagan.
Hayotiy o'xshatish: «Bahor» oshi bitta. Lekin uni zalda likopchada, olib ketish uchun konteynerda, to'yga esa katta qozonda berishadi. Osh o'sha — idish iste'molchiga qarab.
2. Bitta kod — to'rt qadoq
2.1 Manba
Kichik kutubxona — narx.js:
// narx.js — «Bahor» narx kutubxonasi
export const VAT = 0.12;
export function formatPrice(sum) {
return `${sum} so'm`;
}
console.log(formatPrice(35000)); // 35000 so'm(Oxirgi qator faqat tekshirish uchun — yig'ishda biz uni olib tashladik.) Endi uni rollup 4.64.1 bilan to'rt formatga yig'amiz. Rollup — kutubxonalarni yig'ish uchun keng ishlatiladigan bundler, Vite'ning oldingi versiyalari ham build uchun uni ishlatgan. Bundler nima ekanini keyingi darsda to'liq ochamiz; bugun uning bitta qobiliyati kerak: formatni almashtirish.
npx rollup src/narx.js --format es --file dist/narx.es.jsBuyruq --format qiymatini almashtirib (iife, cjs, umd, es) to'rt marta bajarildi. IIFE va UMD uchun --name BahorNarx ham berildi — global o'zgaruvchi nomi.
2.2 ESM
// narx.js — «Bahor» narx kutubxonasi
const VAT = 0.12;
function formatPrice(sum) {
return `${sum} so'm`;
}
export { VAT, formatPrice };Deyarli manbaning o'zi: eksportlar oxirida bitta ro'yxatga yig'ilgan. 145 bayt. ESM (ECMAScript Modules) — tilning o'z standarti: brauzer ham, Node ham uni tushunadi, va bundler uni eng yaxshi tahlil qiladi.
2.3 CommonJS
'use strict';
// narx.js — «Bahor» narx kutubxonasi
const VAT = 0.12;
function formatPrice(sum) {
return `${sum} so'm`;
}
exports.VAT = VAT;
exports.formatPrice = formatPrice;export o'rniga exports.X = X. 'use strict' qo'shildi: ESM har doim qat'iy rejimda (Strict mode), CommonJS esa yo'q — rollup xulq o'zgarmasin deb uni yoqdi. 185 bayt.
2.4 IIFE
var BahorNarx = (function (exports) {
'use strict';
// narx.js — «Bahor» narx kutubxonasi
const VAT = 0.12;
function formatPrice(sum) {
return `${sum} so'm`;
}
exports.VAT = VAT;
exports.formatPrice = formatPrice;
return exports;
})({});IIFE darsidagi "darhol chaqiriladigan funksiya": ichki o'zgaruvchilar (VAT) global'ga chiqmaydi, tashqariga faqat bitta nom — BahorNarx chiqadi. 267 bayt. Bu format modullar paydo bo'lishidan oldin, <script> teglari zamonasida yaratilgan. Bugun ham CDN orqali ulanadigan fayllarda (<script src="…/web-vitals.iife.js">) uchraydi.
2.5 UMD
UMD (Universal Module Definition) — "universal" o'ram: atrofni tekshiradi va mos usulda eksport qiladi. Rollup chiqishi (telefonga sig'ishi uchun Prettier bilan 60 belgiga formatladik):
(function (global, factory) {
typeof exports === "object" &&
typeof module !== "undefined"
? factory(exports)
: typeof define === "function" && define.amd
? define(["exports"], factory)
: ((global =
typeof globalThis !== "undefined"
? globalThis
: global || self),
factory((global.BahorNarx = {})));
})(this, function (exports) {
"use strict";
// narx.js — «Bahor» narx kutubxonasi
const VAT = 0.12;
function formatPrice(sum) {
return `${sum} so'm`;
}
exports.VAT = VAT;
exports.formatPrice = formatPrice;
});Boshidagi uch qavatli ? : ichida uch shox bor. Birinchisi: module bor bo'lsa — CommonJS. Ikkinchisi: define.amd bor bo'lsa — AMD (2010-yillardagi RequireJS formati, bugun deyarli uchramaydi). Uchinchisi — global o'zgaruvchi. 538 bayt — eng kattasi. web-vitals.umd.cjs ham shu formatda, faqat minifikatsiya qilingan.
| Format | Eksport | Kim o'qiydi | Bugun |
|---|---|---|---|
| ESM | export |
brauzer (type="module"), Node, bundler |
asosiy |
| CommonJS | exports.x =, module.exports |
Node, bundler | eski Node kodi |
| IIFE | global o'zgaruvchi | brauzer (<script>) |
CDN fayllari |
| UMD | uchala usul | Node, <script>, AMD |
eski kutubxonalar |
Tekshirib ko'ring: Nega IIFE'da
VATglobal o'zgaruvchiga aylanmadi,BahorNarxesa aylandi?
Javob
VAT funksiya ichida const bilan e'lon qilingan — uning ko'rinish doirasi shu funksiya (scope). Funksiya tugagach, unga faqat qaytarilgan exports obyekti orqali yetish mumkin. BahorNarx esa eng tashqi qatorda var bilan e'lon qilingan — oddiy skriptda bu global o'zgaruvchi. IIFE butun g'oyasi shu: ichkarida xohlagancha nom, tashqarida — bittasi.
3. Har format qayerda yiqiladi
3.1 Brauzerda
To'rt faylni bitta sahifada sinadik (Chrome 154, lokal server, puppeteer orqali):
<script src="dist/narx.iife.js"></script>
<script>console.log("IIFE:", BahorNarx.formatPrice(35000));</script>
<script src="dist/narx.cjs.js"></script>
<script>import { VAT } from "./dist/narx.es.js";</script>
<script type="module">
import { formatPrice } from "./dist/narx.es.js";
console.log("ESM:", formatPrice(28000));
</script>
<script type="module">
const { VAT } = require("./dist/narx.cjs.js");
</script>Konsolda (tartib bilan):
IIFE: 35000 so'm
Uncaught ReferenceError: exports is not defined
Uncaught SyntaxError: Cannot use import statement outside a module
ESM: 28000 so'm
Uncaught ReferenceError: require is not defined| Teg | Fayl | Natija |
|---|---|---|
<script> |
IIFE | |
<script> |
CommonJS | exports is not defined |
<script> |
import qatori |
Cannot use import statement outside a module |
<script type="module"> |
ESM | |
<script type="module"> |
require(…) |
require is not defined |
Uch xato — uch saboq:
exports is not defined— "exports aniqlanmagan". Brauzerdaexports,module,requireumuman yo'q: ular Node'ning CommonJS "o'rami" beradigan o'zgaruvchilar (CommonJS va ESM darsidagi "har fayl — funksiya ichida").Cannot use import statement outside a module— "import'ni moduldan tashqarida ishlatib bo'lmaydi". Oddiy<script>— modul emas. Tuzatish —type="module".require is not defined— eng ko'p uchraydigan xato. Odatda bundler'siz CommonJS paketni brauzerga berganda yoki bundler config'ida bu paket "tashqi" deb qoldirilganda chiqadi.
3.2 Node'da
Node'da ham ikki teskari xato bor. "type": "module" li loyihada require:
const { formatPrice } = require("./dist/narx.cjs.js");
console.log(formatPrice(35000));ReferenceError: require is not defined in ES module scope, you can use import instead"ES modul doirasida require aniqlanmagan, o'rniga import ishlatishingiz mumkin". Teskarisi — "type": "commonjs" li papkada import:
SyntaxError: Cannot use import statement outside a moduleBu holatda Node bundan oldin bitta ogohlantirish ham beradi: Warning: Failed to load the ES module: …\app.js. Make sure to set "type": "module" in the nearest package.json file or use the .mjs extension. — "eng yaqin package.json ga "type": "module" qo'ying yoki .mjs kengaytmasini ishlating". Qoida package.json I darsidan: Node .js faylning formatini eng yaqin package.json dagi "type" ga qarab hal qiladi.
flowchart TB
F["fayl.js"] --> Q{"eng yaqin package.json:<br/>type?"}
Q -->|module| E["ESM: import ✅<br/>require ❌"]
Q -->|commonjs| C["CJS: require ✅<br/>import ❌"]
M["fayl.mjs"] --> E
J["fayl.cjs"] --> CKengaytma (.mjs, .cjs) "type" dan ustun turadi — shuning uchun kutubxonalar web-vitals.umd.cjs kabi nom ishlatadi: web-vitals ning package.json ida "type": "module", lekin .cjs fayl baribir CommonJS bo'lib o'qiladi.
Tekshirib ko'ring: Sardor kutubxonaning README'sidagi
<script src="https://cdn…/narx.cjs.js">ni sahifaga qo'ydi vaexports is not definedoldi. Qaysi faylni ulashi kerak edi va qayerdan biladi?
Javob
IIFE yoki UMD faylni — ular brauzerdagi oddiy <script> uchun. Kutubxonaning package.json idagi unpkg yoki jsdelivr maydoni CDN uchun qaysi faylni berish kerakligini ko'rsatadi: masalan, web-vitals da "unpkg": "dist/web-vitals.iife.js". Yoki — <script type="module"> va ESM fayl.
4. Kutubxona formatlarni qanday e'lon qiladi
4.1 exports shartlari
web-vitals 6.2.3 ning package.json idan (biz node_modules dan o'qidik):
{
"type": "module",
"main": "dist/web-vitals.umd.cjs",
"module": "dist/web-vitals.js",
"unpkg": "dist/web-vitals.iife.js",
"exports": {
".": {
"types": "./dist/modules/index.d.ts",
"require": "./dist/web-vitals.umd.cjs",
"default": "./dist/web-vitals.js"
}
}
}Kirish nuqtalari darsidan bu maydonlarni bilasiz. Formatlar nuqtai nazaridan:
| Kim so'raydi | Nima oladi |
|---|---|
Node: require("web-vitals") |
require sharti → UMD |
Node yoki bundler: import |
default → ESM |
| CDN (unpkg.com) | unpkg → IIFE |
| juda eski bundler | main yoki module |
Node 24 da tekshirdik: require.resolve("web-vitals") → …\dist\web-vitals.umd.cjs.
Diqqat: Shartlar yozilish tartibida tekshiriladi va birinchi mos kelgani olinadi. Shart
"default"hamma narsaga mos keladi, shuning uchun u doim oxirida. Buyruqnpm view web-vitals exportsesa kalitlarni alifbo bo'yicha tartiblab ko'rsatadi (defaultrequiredan oldin chiqadi) — haqiqiy tartibnipackage.jsonning o'zidan o'qing.
4.2 Bundler formatni qanday "ko'radi"
Vite kabi bundler ikki savol beradi: "qaysi faylni olay?" (exports, browser, module shartlari) va "bu fayl qaysi formatda?". ESM'ni u to'g'ridan-to'g'ri tahlil qiladi: import va export statik — fayl bajarilmasdan oldin ko'rinadi. CommonJS'ni esa ESM'ga o'giradi: module.exports — oddiy obyekt, unga qachon nima yozilishini faqat bajarib bilish mumkin. Shuning uchun bundler ESM paketdan ishlatilmagan funksiyalarni bemalol tashlay oladi, CommonJS'dan — deyarli yo'q (Modul semantikasi darsidagi tree shaking; chuqur — Tree shaking darsida).
5. Default export tuzog'i
5.1 Muammo
Eski kutubxonalarning ko'pi TypeScript'da yozilib, CommonJS'ga o'girilgan. export default formatCheck TypeScript (yoki Babel) chiqishida shunday ko'rinadi — eski-chek paketining index.js:
"use strict";
// TypeScript'dan CommonJS'ga o'girilgan kod shunday ko'rinadi
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = formatCheck;
function formatCheck(items) {
return items.map((i) => `${i.name}: ${i.price}`).join("\n");
}__esModule: true — "bu fayl aslida ESM edi" degan belgi. exports.default — o'sha export default. Endi ESM loyihada ("type": "module") uni ishlatamiz:
import formatCheck from "eski-chek";
console.log(typeof formatCheck);
console.log(formatCheck([{ name: "Osh", price: 35000 }]));Node 24 da:
object
TypeError: formatCheck is not a functionformatCheck — funksiya emas, obyekt. Sabab: Node CommonJS paketdan import x from qilinganda x ga butun module.exports ni beradi va __esModule belgisiga qaramaydi. module.exports esa — { default: formatCheck }. Funksiya bir qavat ichkarida.
5.2 Bundlerlarda — ikki xil natija
Eng chalkash qismi: bir xil kodni bundler ba'zan "to'g'ri" yig'adi. Biz esbuild 0.28.2 va Rolldown 1.2.12 (Vite 8 ichidagi bundler) bilan sinadik:
| Import qiluvchi fayl | esbuild | Rolldown |
|---|---|---|
"type": "module" li papkada |
object — xato |
object — xato |
"type" siz papkada |
function — ishlaydi |
function — ishlaydi |
Ikkala bundler ham Node qoidasini takrorlaydi: import qiluvchi fayl Node ma'nosida ESM bo'lsa ("type": "module", .mjs), __esModule e'tiborga olinmaydi. Aks holda — Babel davridagi "eski" kelishuv ishlaydi va default — funksiya. Ya'ni bitta qator "type": "module" qo'shilishi ishlab turgan kodni buzishi mumkin.
5.3 Xavfsiz yozuv
import checkModule from "eski-chek";
// Node: modul obyekti ({ default: fn }); ba'zi bundlerlar: fn
const formatCheck = checkModule.default ?? checkModule;
console.log(formatCheck([{ name: "Osh", price: 35000 }]));Uch holatda ham (Node, esbuild type bilan va type siz) natija bir xil: Osh: 35000. ?? — ?? operatori: chap tomon undefined bo'lsa, o'ng tomonni oladi. Bu "ko'prik" faqat eski CommonJS paketlar uchun kerak. Yaxshiroq yechim — kutubxonaning ESM versiyasini topish (yangi MAJOR yoki boshqa paket).
Tekshirib ko'ring:
import * as m from "eski-chek"qilsak, Node'daObject.keys(m)nima beradi? Taxmin qiling, keyin pastdan tekshiring.
Javob
Biz Node 24 da tekshirdik: [ '__esModule', 'default', 'module.exports' ]. Node CommonJS faylni tahlil qilib, topgan nomlarni (__esModule) alohida eksport qiladi, default ga butun module.exports ni qo'yadi va yana 'module.exports' nomli eksport qo'shadi. Ya'ni funksiyaga yo'l — m.default.default. Bunday qavatlar — CommonJS va ESM aralashganining belgisi.
6. Dual package hazard
6.1 Ikki nusxa
Dual package — ham ESM, ham CommonJS versiyasi bor paket (exports da import va require shartlari). Bu qulay, lekin bir xavf yashiradi. Sinov: bahor-xato paketi ikki faylda bir xil klassni beradi:
{
"name": "bahor-xato",
"version": "1.0.0",
"exports": {
"import": "./index.mjs",
"require": "./index.cjs"
}
}index.mjs da export class OrderError extends Error {}, index.cjs da xuddi shu klass module.exports bilan. Loyiha paketni import qiladi, loyihadagi eski CommonJS kutubxona esa require:
// eski-kutubxona.cjs — bahor-xato ni require qiladi
const { OrderError } = require("bahor-xato");
exports.failOrder = () => {
throw new OrderError("Osh tugadi");
};// app.js — ESM loyiha
import { OrderError } from "bahor-xato";
import { failOrder } from "./eski-kutubxona.cjs";
try {
failOrder();
} catch (error) {
console.log(error.message);
console.log(error instanceof OrderError);
}Osh tugadi
falseXato OrderError dan yaratilgan — lekin instanceof false! Chunki bu boshqa OrderError: biri index.mjs dan, biri index.cjs dan. Node ikkalasini ham yukladi, ular ikki alohida klass. Bu — dual package hazard ("ikki formatli paket xavfi"). Klass bilan instanceof, ichki holat (hisoblagich, kesh, sozlamalar) — hammasi ikkiga bo'linadi.
flowchart LR
A["app.js<br/>import"] --> E["index.mjs<br/>OrderError #1"]
L["eski-kutubxona.cjs<br/>require"] --> C["index.cjs<br/>OrderError #2"]
L -->|"throw new #2"| A
A -.->|"instanceof #1 → false"| A6.2 Ikki yechim
1. ESM "eshik", kod bitta. index.mjs faqat CommonJS faylni qayta eksport qiladi:
// ESM "eshik" — klassning o'zi bitta, CommonJS faylda
export { OrderError } from "./index.cjs";Natija: Osh tugadi, true. Klass bitta — ikki yo'l unga olib boradi.
2. Faqat ESM. Node 24 da require() ESM faylni ham yuklay oladi (CommonJS va ESM darsidagi require(esm)). Demak, ikkinchi nusxa kerak emas:
{
"name": "bahor-xato",
"version": "2.0.0",
"type": "module",
"exports": "./index.js"
}Natija yana true. 2026-yilda ko'p kutubxona shu yo'lga o'tmoqda: oldingi darsda ko'rgan nanoid 4.0 dan beri faqat ESM. Node'ning qo'llab-quvvatlanadigan hamma versiyalarida (20.19+, 22.12+, 24) require(esm) ishlaydi.
Tekshirib ko'ring: Dual package hazard nega aynan klass va holat bilan muammo, oddiy funksiya bilan esa deyarli sezilmaydi?
Javob
Funksiya natijasi faqat argumentga bog'liq bo'lsa, uning ikki nusxasi bir xil ishlaydi — farqi bilinmaydi. Klass esa "o'ziga xos" obyekt: instanceof aynan o'sha nusxani solishtiradi. Holat ham: biri hisoblagichni oshirsa, ikkinchisi bilmaydi. Shuning uchun xavf "jim": xato chiqmaydi, faqat mantiq noto'g'ri ishlaydi.
7. Import maps — bundlersiz yo'l
Brauzerda ESM va import maps darsida ko'rdik: <script type="importmap"> brauzerga import "web-vitals" dagi yalang nomni manzilga bog'lashni o'rgatadi. Bu bundlersiz ham ESM paketlarni ishlatish imkonini beradi — lekin faqat ESM paketlarni. CommonJS yoki UMD paketni import map orqali import qilib bo'lmaydi: brauzer module.exports ni tushunmaydi. Formatlar haqidagi bilim shu yerda ham kerak: exports dagi default yoki module faylini ko'rsatish kerak, main dagi .cjs ni emas.
8. Ko'p uchraydigan xatolar
| Xabar | Qayerda | Sabab va davosi |
|---|---|---|
require is not defined |
brauzer | CommonJS kod bundler'siz → bundler yoki ESM versiya |
require is not defined in ES module scope |
Node | "type": "module" → import yoki .cjs |
Cannot use import statement outside a module |
brauzer / Node | type="module" yoki "type": "module" / .mjs |
exports is not defined |
brauzer | CommonJS fayl <script> da → IIFE/UMD yoki ESM |
x is not a function (default import) |
Node, bundler | CommonJS exports.default → m.default ?? m |
Yana bir maslahat: xato paket ichida chiqsa, node_modules/<paket>/package.json ni oching va type, main, exports ni o'qing. Muammoning yarmi shu uch maydonda.
9. Mashqlar
Mashqlar kurs/mashqlar/16/19-modul-formatlari/ da.
1-mashq (oson): Formatni ayting
Har parcha qaysi formatda (ESM, CommonJS, IIFE, UMD)?
module.exports = { VAT };—export { VAT, formatPrice };—var Bahor = (function () { … })();—typeof define === "function" && define.amdbor —
Yechim
1 — CommonJS (module.exports). 2 — ESM (export). 3 — IIFE: global var va darhol chaqiriladigan funksiya. 4 — UMD: AMD'ni tekshirish faqat UMD o'ramida bo'ladi. UMD ichida exports ham, funksiya ham bor — shuning uchun avval aynan define.amd ni qidiring.
2-mashq (o'rta): To'rt formatni yig'ing
kurs/mashqlar/16/19-modul-formatlari/ da npm init -y, npm pkg set type=module, npm i -D -E rollup@4.64.1. Darsdagi src/narx.js ni yozing (oxirgi console.log siz) va to'rt formatni yig'ing. So'ng:
- Har fayl hajmini
wc -c dist/*bilan o'lchang. node -e "console.log(require('./dist/narx.cjs.js').formatPrice(5000))"nima chiqaradi? Nega?- Shu buyruq
dist/narx.es.jsbilan ishlaydimi? Nega?
Yordam: node -e — kodni fayl yaratmasdan bajaradi va u CommonJS sifatida ishlaydi.
Yechim
for f in iife cjs umd es; do
npx rollup src/narx.js --format $f --name BahorNarx \
--file dist/narx.$f.js
done
wc -c dist/*Hajmlar: es — 145, cjs — 185, iife — 267, umd — 538 bayt.
2-savol — tuzoq. Loyihada "type": "module", demak dist/narx.cjs.js ham ESM sifatida o'qiladi. Natija: TypeError: require(...).formatPrice is not a function. require bo'sh modul obyektini qaytardi ([Module: null prototype] { }): ESM faylda exports.VAT = … eksport hisoblanmaydi. Faylni import qilsangiz, asl sabab ko'rinadi: ReferenceError: exports is not defined in ES module scope. Tuzatish — CommonJS faylni .cjs kengaytmasi bilan yig'ish (--file dist/narx.cjs), chunki kengaytma "type" dan ustun.
3-savol: dist/narx.es.js bilan 5000 so'm chiqadi. Node 24 da require() ESM faylni ham yuklaydi (require(esm)). Node 20.19 dan eski versiyalarda bu ERR_REQUIRE_ESM xatosini berardi.
3-mashq (qiyin): Format aniqlovchi
format.mjs yozing: detectFormat(code) faylning matniga qarab "esm", "cjs", "iife", "umd" yoki "noma'lum" qaytarsin. Buyruq qatoridan bir nechta fayl nomi olib, har biri uchun formatni chiqarsin. 2-mashqdagi to'rt fayl va node_modules/web-vitals/dist/ dagi uchta fayl bilan sinang.
Ishoralar:
- Tekshirish tartibi muhim: UMD ichida
exports.x =ham,functionham bor; IIFE ichida hamexports.x =bor. Avval eng o'ziga xos belgini qidiring. - Minifikatsiya qilingan ESM'da
exportqator boshida emas:…;export{a as b}. Regex'da(^|[;}])vambayrog'i (RegExp bayroqlari). \b— so'z chegarasi:export\b"exports" ni ushlamaydi.- Bu — taxmin (heuristika), haqiqiy tahlil emas. Haqiqiysi AST bilan qilinadi — Transpilyatsiya darsida.
Yechim
// format.mjs — fayl qaysi modul formatida (naqsh bo'yicha taxmin)
export function detectFormat(code) {
// UMD ichida "exports" ham, "function" ham bor — birinchi
if (/define\.amd/.test(code)) return "umd";
// import/export — qator boshida yoki ";" va "}" dan keyin
if (/(^|[;}])\s*(import|export)\b\s*[\w{*"]/m.test(code)) {
return "esm";
}
// IIFE ichida exports.x = bo'lishi mumkin — CJS'dan oldin
if (/^\s*(var \w+\s*=\s*)?[!(]?\(?\s*function/.test(code)) {
return "iife";
}
if (/\b(module\.exports|exports\.\w+)\s*=/.test(code)) return "cjs";
return "noma'lum";
}
if (import.meta.main) {
const { readFileSync } = await import("node:fs");
for (const file of process.argv.slice(2)) {
const format = detectFormat(readFileSync(file, "utf8"));
console.log(`${format.padEnd(5)} ${file}`);
}
}Test (format.test.mjs) to'rt formatni va console.log(1); → "noma'lum" ni tekshiradi: ℹ tests 1, ℹ pass 1, ℹ fail 0. Natija:
node format.mjs dist/*.jscjs dist/narx.cjs.js
esm dist/narx.es.js
iife dist/narx.iife.js
umd dist/narx.umd.jsweb-vitals fayllari: iife web-vitals.iife.js, umd web-vitals.umd.cjs, esm web-vitals.js. Birinchi urinishda ikki xatoga duch keldik (va siz ham kelishingiz mumkin): export ning \b siz versiyasi rollup'ning CommonJS faylidagi exports.VAT ni "esm" dedi; IIFE tekshiruvi CJS'dan keyin bo'lganda IIFE fayl "cjs" bo'lib qoldi. Ikkalasi ham "tartib va chegara" xatosi.
10. Real ishda
- Kutubxona yozsangiz, 2026-yildagi tavsiya: faqat ESM,
"type": "module",exportsbilan. CDN uchun kerak bo'lsa — qo'shimcha IIFE. Kurs oxirida o'z paketingizni shunday chiqarasiz. - Ilova yozsangiz, formatlarni bundler hal qiladi. Siz faqat xatoni tanishingiz kerak:
require is not defined,defaultqavati,instanceofningfalsebo'lishi. - Eski loyihalarda (webpack 4, Jest, Node 16 davri) CommonJS ko'p. webpack konseptlari darsida bunday loyihani o'qiymiz.
- Intervyu savollari: "CommonJS va ESM farqi?", "UMD nima uchun kerak edi?", "Dual package hazard nima?", "
require is not definedqachon chiqadi?".
Xulosa
- Bitta kod — to'rt qadoq: ESM (
export), CommonJS (exports), IIFE (bitta global), UMD (uchalasini tekshiradigan o'ram). - Brauzer:
<script>— IIFE/UMD,type="module"— ESM; CommonJS bundler'siz ishlamaydi (require/exports is not defined). - Node
.jsformatini"type"dan,.mjs/.cjsdan biladi; kengaytma ustun. - CommonJS'dagi
exports.defaultNode'da (va"type": "module"li bundlerda) bir qavat ichkarida qoladi —m.default ?? m. - Dual package hazard — paketning ikki nusxasi:
instanceofva holat buziladi; yechim — bitta kod (ESM eshik) yoki faqat ESM (require(esm)).
Keyingi dars: Bundler nima: bog'liqlik grafi, chunk va asset — vazifalar ga vite build keladi: entry'dan boshlab import grafi qanday quriladi, 24 modul qanday 4 ta faylga aylanadi va dist/ dagi har fayl qayerdan keladi.
Manbalar
- Node.js Docs: "Modules: Packages" (
type,exports, conditional exports, dual package hazard) — nodejs.org/api/packages.html - Node.js Docs: "Modules: ECMAScript modules → Interoperability with CommonJS" — nodejs.org/api/esm.html
- Rollup: "Configuration Options → output.format" — rollupjs.org
- esbuild: "Content Types → Default interop" — esbuild.github.io
- Rolldown: "In-depth → Non-ESM" (CommonJS interop) — rolldown.rs
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!