IlmHamroh
JavaScript Full-stack/16-qism. Frontend asboblari: npm, bundlerlar, config19/48-dars18 daqiqa
Mundarija (30)

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: brauzerda require is not defined, CommonJS'dan kelgan default ning 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 module xatolarining sababini topasiz.
  • CommonJS paketdan default import 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:

text
 8991 web-vitals.iife.js
 9180 web-vitals.umd.cjs
 8967 web-vitals.js

Hajmlari 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:

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.

bash
npx rollup src/narx.js --format es --file dist/narx.es.js

Buyruq --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

js
// 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

js
'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

js
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):

js
(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 VAT global o'zgaruvchiga aylanmadi, BahorNarx esa 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):

html
<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):

text
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:

  1. exports is not defined — "exports aniqlanmagan". Brauzerda exports, module, require umuman yo'q: ular Node'ning CommonJS "o'rami" beradigan o'zgaruvchilar (CommonJS va ESM darsidagi "har fayl — funksiya ichida").
  2. Cannot use import statement outside a module — "import'ni moduldan tashqarida ishlatib bo'lmaydi". Oddiy <script> — modul emas. Tuzatish — type="module".
  3. 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:

js
const { formatPrice } = require("./dist/narx.cjs.js");
console.log(formatPrice(35000));
text
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:

text
SyntaxError: Cannot use import statement outside a module

Bu 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"] --> C

Kengaytma (.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 va exports is not defined oldi. 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):

json
{
  "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. Buyruq npm view web-vitals exports esa kalitlarni alifbo bo'yicha tartiblab ko'rsatadi (default require dan oldin chiqadi) — haqiqiy tartibni package.json ning 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:

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:

js
import formatCheck from "eski-chek";

console.log(typeof formatCheck);
console.log(formatCheck([{ name: "Osh", price: 35000 }]));

Node 24 da:

text
object
TypeError: formatCheck is not a function

formatCheck — 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

js
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'da Object.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:

json
{
  "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:

js
// eski-kutubxona.cjs — bahor-xato ni require qiladi
const { OrderError } = require("bahor-xato");
exports.failOrder = () => {
  throw new OrderError("Osh tugadi");
};
js
// 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);
}
text
Osh tugadi
false

Xato 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"| A

6.2 Ikki yechim

1. ESM "eshik", kod bitta. index.mjs faqat CommonJS faylni qayta eksport qiladi:

js
// 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:

json
{
  "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)?

  1. module.exports = { VAT }; —
  2. export { VAT, formatPrice }; —
  3. var Bahor = (function () { … })(); —
  4. typeof define === "function" && define.amd bor —
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:

  1. Har fayl hajmini wc -c dist/* bilan o'lchang.
  2. node -e "console.log(require('./dist/narx.cjs.js').formatPrice(5000))" nima chiqaradi? Nega?
  3. Shu buyruq dist/narx.es.js bilan ishlaydimi? Nega?

Yordam: node -e — kodni fayl yaratmasdan bajaradi va u CommonJS sifatida ishlaydi.

Yechim
bash
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, function ham bor; IIFE ichida ham exports.x = bor. Avval eng o'ziga xos belgini qidiring.
  • Minifikatsiya qilingan ESM'da export qator boshida emas: …;export{a as b}. Regex'da (^|[;}]) va m bayrog'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
js
// 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:

bash
node format.mjs dist/*.js
text
cjs   dist/narx.cjs.js
esm   dist/narx.es.js
iife  dist/narx.iife.js
umd   dist/narx.umd.js

web-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", exports bilan. 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, default qavati, instanceof ning false bo'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 defined qachon 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 .js formatini "type" dan, .mjs/.cjs dan biladi; kengaytma ustun.
  • CommonJS'dagi exports.default Node'da (va "type": "module" li bundlerda) bir qavat ichkarida qoladi — m.default ?? m.
  • Dual package hazard — paketning ikki nusxasi: instanceof va 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
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Modul formatlari: IIFE, UMD, CommonJS va ESM — tooling nuqtai nazaridan — IlmHamroh