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.
Ushbu bo‘lim mundarijasi
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:
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:
import salomla, { PI, qosh, kopaytir } from "./hisob.mjs";
console.log(salomla("Malika"));
console.log(qosh(2, 3), kopaytir(4, 5));
console.log(PI);
Salom, Malika!
5 20
3.14159
Ikki xil eksport bor:
| Turi | Eksport | Import |
|---|---|---|
| Nomlangan | export const PI | import { PI } from ... |
| Odatiy | export default ... | import istalganNom from ... |
Odatiy eksport faylda bittagina bo'ladi va uni import qilganda istalgan nom berish mumkin.
Brauzerda va Node da import "./hisob" ishlamaydi:
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 #
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(", "));
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.
const PI = 3.14159;
function qosh(a, b) {
return a + b;
}
module.exports = { PI, qosh };
module.exports.kopaytir = (a, b) => a * b;
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(", "));
5
3.14159
function
PI, kopaytir, qosh
CommonJS da module.exports - oddiy obyekt. Unga istalgan narsani
qo'yish mumkin.
Ikkisining farqi #
| CommonJS | ESM | |
|---|---|---|
| Eksport | module.exports | export |
| Import | require() | import |
| Qachon yuklanadi | Ishlash paytida | Oldindan tahlil qilinadi |
| Kengaytma | Ixtiyoriy | Majburiy |
Yuqori darajada await | Yo'q | Bor |
| Fayl kengaytmasi | .cjs | .mjs |
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:
| Fayl | Qanday o'qiladi |
|---|---|
.mjs | Har doim ESM |
.cjs | Har doim CommonJS |
.js + "type": "module" | ESM |
.js + type yo'q | CommonJS |
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:
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);
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 #
import { join } from "node:path";
import { readFile } from "node:fs/promises";
console.log(join("hujjatlar", "hisobot.txt"));
console.log(typeof readFile);
hujjatlar/hisobot.txt
function
node: - bu ichki modul degan aniq belgi.
import { join } from "path" ham ishlaydi, lekin node:path yozish
afzalroq:
- Aniqlik. O'quvchi bu ichki modul ekanini darhol ko'radi.
- Xavfsizlik. Kimdir npm ga
pathnomli paket joylasa va u tasodifan o'rnatilsa, prefikssiz import o'sha paketni olib qo'yishi mumkin.node:pathesa doim ichki modulni oladi. - Tezlik. Node qidirishga vaqt sarflamaydi.
Yangi kodda doim node: yozing.
Yuqori darajada await #
const boshlanish = "ESM da await";
const natija = await Promise.resolve("darhol ishlaydi");
console.log(boshlanish);
console.log(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 #
let soni = 0;
export function oshir() {
soni += 1;
return soni;
}
import { oshir } from "./hisoblagich.mjs";
import { oshir as yana } from "./hisoblagich.mjs";
console.log(oshir(), oshir());
console.log(yana());
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.
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 #
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
requireqilish 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 #
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);
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.
- Ikki funksiyani eksport qiladigan modul yozing.
- Uni nomlangan import bilan chaqiring.
export defaultqo'shib, uni istalgan nom bilan import qiling.- Kengaytmani tushirib qoldirib, xatoni ko'ring.
import * asbilan butun modulni oling.- Xuddi shuni
requirevamodule.exportsbilan yozing. .cjsva.mjskengaytmalarini sinang.await import()ni shart ichida ishlating.node:prefiksi bilan ichki modulni chaqiring.- Modul bir marta yuklanishini hisoblagich bilan isbotlang.
Xulosa #
- Har bir fayl - alohida modul; tashqariga faqat eksport qilingani chiqadi.
- ESM:
exportvaimport; CommonJS:module.exportsvarequire. - ESM da fayl kengaytmasi majburiy.
import- e'lon, oldindan tahlil qilinadi; shu sababdantree shakingmumkin.- Kengaytma (
.mjs/.cjs)package.jsondagitypedan kuchliroq. - Shart ichida yuklash kerak bo'lsa -
await import(). - Ichki modullarni doim
node:prefiksi bilan chaqiring. - ESM da yuqori darajada
awaitishlaydi. - 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.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
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.