3-bo‘lim

Modullar - ESM va CommonJS

import va export, require va module.exports, .mjs va .cjs kengaytmalari, node: prefiksi, dinamik import va ikki tizimning farqi.

🕑 14 daqiqa o‘qish 📄 954 so‘z 👁 0 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. ESM - zamonaviy usul
  2. Nomni o'zgartirish va hammasini olish
  3. CommonJS - eski usul
  4. Ikkisining farqi
  5. Kengaytmalar va type
  6. Dinamik import
  7. node: prefiksi
  8. Yuqori darajada await
  9. Modul bir marta yuklanadi
  10. Ikki tizimni aralashtirish
  11. import.meta
  12. Xulosa

Node da har bir fayl - alohida modul. Undagi o'zgaruvchilar tashqariga chiqmaydi, toki siz ularni ochiq eksport qilmaguningizcha.

Node da ikki modul tizimi bor va ikkalasini ham bilish kerak.

ESM - zamonaviy usul #

Avval eksport qiladigan fayl yozamiz:

JavaScript
export const PI = 3.14159;

export function qosh(a, b) {
    return a + b;
}

export function kopaytir(a, b) {
    return a * b;
}

export default function salomla(ism) {
    return `Salom, ${ism}!`;
}

Endi uni ishlatamiz:

JavaScript
import salomla, { PI, qosh, kopaytir } from "./hisob.mjs";

console.log(salomla("Malika"));
console.log(qosh(2, 3), kopaytir(4, 5));
console.log(PI);
Natija
Salom, Malika!
5 20
3.14159

Ikki xil eksport bor:

TuriEksportImport
Nomlanganexport const PIimport { PI } from ...
Odatiyexport default ...import istalganNom from ...

Odatiy eksport faylda bittagina bo'ladi va uni import qilganda istalgan nom berish mumkin.

ESM da fayl kengaytmasi majburiy

Brauzerda va Node da import "./hisob" ishlamaydi:

Natija
Error: Cannot find module '.../hisob'

Kengaytmani to'liq yozish kerak: "./hisob.mjs" yoki "./hisob.js".

Bu require dan farq qiladi - u kengaytmani o'zi topib olardi. ESM ni ataylab qat'iy qilishgan: shunda qidirish tezroq va natija oldindan ma'lum bo'ladi.

Nomni o'zgartirish va hammasini olish #

JavaScript
import { qosh as yigindi, PI } from "./hisob.mjs";
import * as hisob from "./hisob.mjs";

console.log(yigindi(10, 20));
console.log(hisob.kopaytir(3, 3));
console.log(typeof hisob.default);
console.log(Object.keys(hisob).sort().join(", "));
Natija
30
9
function
PI, default, kopaytir, qosh

as bilan nomni almashtirish mumkin - to'qnashuvlarda foydali.

* as nom esa butun modulni bitta obyekt sifatida beradi.

E'tibor bering: Object.keys natijasi saralangan, chunki modul kalitlari tartibi kafolatlanmaydi.

CommonJS - eski usul #

Node dastlab faqat shu tizimni bilardi va u hali ham juda keng tarqalgan.

JavaScript
const PI = 3.14159;

function qosh(a, b) {
    return a + b;
}

module.exports = { PI, qosh };
module.exports.kopaytir = (a, b) => a * b;
JavaScript
const { PI, qosh } = require("./eski.cjs");
const hammasi = require("./eski.cjs");

console.log(qosh(2, 3));
console.log(PI);
console.log(typeof hammasi.kopaytir);
console.log(Object.keys(hammasi).sort().join(", "));
Natija
5
3.14159
function
PI, kopaytir, qosh

CommonJS da module.exports - oddiy obyekt. Unga istalgan narsani qo'yish mumkin.

Ikkisining farqi #

CommonJSESM
Eksportmodule.exportsexport
Importrequire()import
Qachon yuklanadiIshlash paytidaOldindan tahlil qilinadi
KengaytmaIxtiyoriyMajburiy
Yuqori darajada awaitYo'qBor
Fayl kengaytmasi.cjs.mjs
Nega ESM oldindan tahlil qilinadi

require() - oddiy funksiya. U kod ishlayotganda chaqiriladi, shuning uchun uni if ichiga qo'yish mumkin.

import esa buyruq emas, e'lon. Node fayl ishga tushishidan oldin hamma import larni o'qib chiqadi va bog'liqliklar xaritasini tuzadi.

Bu sekinroq tuyuladi, lekin katta foyda beradi: vositalar qaysi kod ishlatilmayotganini oldindan ko'ra oladi va uni yig'ilmadan tashlab ketadi. Bu tree shaking deb ataladi va front-end da fayl hajmini sezilarli kamaytiradi.

Shu sababdan import ni if ichiga yozib bo'lmaydi - u doim faylning eng yuqorisida bo'lishi kerak.

Kengaytmalar va type #

Qaysi tizim ishlashini ikki narsa hal qiladi:

FaylQanday o'qiladi
.mjsHar doim ESM
.cjsHar doim CommonJS
.js + "type": "module"ESM
.js + type yo'qCommonJS

Kengaytma har doim kuchliroq: package.json da "type": "module" bo'lsa ham, .cjs fayli CommonJS bo'lib qolaveradi.

Dinamik import #

import ni shart ichiga yozib bo'lmaydi, lekin funksiya shakli bor:

JavaScript
const kerakmi = true;

if (kerakmi) {
    const hisob = await import("./hisob.mjs");
    console.log(hisob.qosh(7, 8));
}

const nom = "./hisob.mjs";
const { PI } = await import(nom);
console.log(PI);
Natija
15
3.14159

import() - vada (Promise) qaytaradigan funksiya. U:

  • shart ichida ishlaydi;
  • modul nomini o'zgaruvchidan oladi;
  • katta modulni faqat kerak bo'lganda yuklashga imkon beradi.

node: prefiksi #

JavaScript
import { join } from "node:path";
import { readFile } from "node:fs/promises";

console.log(join("hujjatlar", "hisobot.txt"));
console.log(typeof readFile);
Natija
hujjatlar/hisobot.txt
function

node: - bu ichki modul degan aniq belgi.

node: prefiksini har doim yozing

import { join } from "path" ham ishlaydi, lekin node:path yozish afzalroq:

  1. Aniqlik. O'quvchi bu ichki modul ekanini darhol ko'radi.
  2. Xavfsizlik. Kimdir npm ga path nomli paket joylasa va u tasodifan o'rnatilsa, prefikssiz import o'sha paketni olib qo'yishi mumkin. node:path esa doim ichki modulni oladi.
  3. Tezlik. Node qidirishga vaqt sarflamaydi.

Yangi kodda doim node: yozing.

Yuqori darajada await #

JavaScript
const boshlanish = "ESM da await";

const natija = await Promise.resolve("darhol ishlaydi");

console.log(boshlanish);
console.log(natija);
Natija
ESM da await
darhol ishlaydi

ESM da await ni funksiyadan tashqarida, faylning eng yuqorisida ishlatish mumkin.

CommonJS da bu mumkin emas - u yerda async funksiya o'rab yozish kerak bo'ladi.

Modul bir marta yuklanadi #

JavaScript
let soni = 0;

export function oshir() {
    soni += 1;
    return soni;
}
JavaScript
import { oshir } from "./hisoblagich.mjs";
import { oshir as yana } from "./hisoblagich.mjs";

console.log(oshir(), oshir());
console.log(yana());
Natija
1 2
3

Ikki marta import qilindi, lekin hisoblagich umumiy bo'lib qoldi.

Node har bir modulni bir marta yuklaydi va natijani keshda saqlaydi. Keyingi importlar o'sha nusxani oladi.

Modul holati - yashirin global holat

Yuqoridagi xatti-harakat foydali bo'lishi mumkin: masalan, ma'lumotlar bazasiga ulanishni bir marta ochib, hamma joyda ishlatish.

Lekin u tuzoq ham: modul ichidagi let - aslida global o'zgaruvchi. Uni bir joyda o'zgartirsangiz, butun dastur bo'ylab o'zgaradi.

Testlarda bu ayniqsa bezovta qiladi: bir test modul holatini o'zgartirsa, keyingi test boshqa natija olishi mumkin.

Qoida: modul darajasida o'zgaruvchan holat saqlashdan imkon qadar saqlaning. Uning o'rniga funksiya yoki sinf qaytaring.

Ikki tizimni aralashtirish #

CommonJS dan ESM ni require qilib bo'lmaydi

Yo'nalishlar teng emas:

  • ESM dan CommonJS ni import qilish mumkin: import eski from "./eski.cjs" - u odatiy eksport bo'lib keladi.
  • CommonJS dan ESM ni require qilish uzoq vaqt umuman mumkin emas edi. Yangi Node versiyalarida cheklangan holda ishlaydi, lekin unga tayanmagan ma'qul.

Amaliy maslahat: yangi loyihada faqat ESM ishlating va package.json ga darhol "type": "module" qo'shing.

CommonJS ni esa eski kodni o'qish uchun biling - internetdagi misollarning ko'pchiligi hali ham require bilan yozilgan.

import.meta #

JavaScript
console.log(typeof import.meta.url);
console.log(import.meta.url.startsWith("file:"));
console.log(import.meta.url.endsWith(".mjs"));
console.log(typeof import.meta.dirname);
Natija
string
true
true
string

CommonJS da __dirname va __filename o'zgaruvchilari bor edi. ESM da ular yo'q, o'rniga import.meta keladi.

import.meta.dirname va import.meta.filename - Node 20.11 dan qo'shilgan qulay shakllar.

Amaliy topshiriq
  1. Ikki funksiyani eksport qiladigan modul yozing.
  2. Uni nomlangan import bilan chaqiring.
  3. export default qo'shib, uni istalgan nom bilan import qiling.
  4. Kengaytmani tushirib qoldirib, xatoni ko'ring.
  5. import * as bilan butun modulni oling.
  6. Xuddi shuni require va module.exports bilan yozing.
  7. .cjs va .mjs kengaytmalarini sinang.
  8. await import() ni shart ichida ishlating.
  9. node: prefiksi bilan ichki modulni chaqiring.
  10. Modul bir marta yuklanishini hisoblagich bilan isbotlang.

Xulosa #

  • Har bir fayl - alohida modul; tashqariga faqat eksport qilingani chiqadi.
  • ESM: export va import; CommonJS: module.exports va require.
  • ESM da fayl kengaytmasi majburiy.
  • import - e'lon, oldindan tahlil qilinadi; shu sababdan tree shaking mumkin.
  • Kengaytma (.mjs / .cjs) package.json dagi type dan kuchliroq.
  • Shart ichida yuklash kerak bo'lsa - await import().
  • Ichki modullarni doim node: prefiksi bilan chaqiring.
  • ESM da yuqori darajada await ishlaydi.
  • Modul bir marta yuklanadi - modul darajasidagi holat global holatga aylanadi.
  • Yangi loyihada faqat ESM; CommonJS ni eski kodni o'qish uchun biling.

Keyingi bo'limda npm va paketlarni o'rganamiz.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.