Seriya: JavaScript Basics Dars 95

Frontend Architecture

Frontend arxitekturasi nima, Layer-based va Feature-based tuzilma farqi, unidirectional data flow, komponent chegaralari (coupling/cohesion), rendering strategiyasini tanlash (CSR/SSR/SSG/ISR), code splitting arxitekturasi, micro-frontends, va arxitektura qarorlarining V8/brauzer darajasida bundle parse/compile va main thread'ga ta'siri.

95-dars

Frontend Architecture

Kichik loyihada arxitektura haqida o'ylash shart emas — 5 ta komponent, 2 ta sahifa, hamma narsa ko'z oldingizda. Lekin loyiha o'sib, 50, keyin 500 komponentga yetganda, savol o'zgaradi: "qanday yozaman" emas, balki "bu yangi kod qayerga tushishi kerak, va u qolgan hamma narsaga qanday ta'sir qiladi".

Frontend arxitekturasi — bu kodni "ishlaydigan" holatdan "o'zgartirish oson" holatga o'tkazadigan qarorlar to'plami: fayllar qayerda yotadi, data qaysi yo'nalishda oqadi, komponentlar bir-biriga qanday bog'langan. Bu — texnologiya emas, balki chegaralar chizish intizomi.


1. Nega tuzilma o'zi muhim — "spagetti" muammosi

Arxitekturasiz loyihada odatiy holat:

// UserProfile.jsx — hammasi bitta joyda
function UserProfile() {
  const [user, setUser] = useState(null);

  useEffect(() => {
    fetch('/api/user').then(r => r.json()).then(setUser);
  }, []);

  const formatDate = (d) => new Date(d).toLocaleDateString('uz-UZ');
  const validateEmail = (e) => /\S+@\S+\.\S+/.test(e);

  // ... 300 qator JSX, validatsiya, fetch, formatlash — hammasi aralash
}

Muammo hajmda emas — muammo shundaki, bu komponentni sinash, qayta ishlatish yoki tushunish qiyin, chunki u bir vaqtning o'zida to'rtta ishni qiladi: data olish, validatsiya, formatlash, render qilish. Har birini o'zgartirsangiz, boshqasini buzib qo'yish xavfi bor.

Arxitektura — bu ayni shu vazifalarni ataylab ajratish:

UserProfile/
  index.jsx          ← faqat render
  useUser.js          ← faqat data olish (custom hook)
  formatDate.js        ← faqat formatlash (sof funksiya)
  validateEmail.js     ← faqat validatsiya (sof funksiya)

Endi har bir fayl — bitta sabab bilan o'zgaradi (Single Responsibility). formatDateni test qilish uchun React'ni ishga tushirish shart emas.


2. Layer-based vs Feature-based tuzilma

Loyiha papkalarini tashkil qilishning ikki asosiy yo'li bor:

Layer-based (texnik qatlam bo'yicha):     Feature-based (biznes funksiya bo'yicha):
src/                                       src/
  components/                                features/
    UserCard.jsx                               user-profile/
    ProductCard.jsx                              UserCard.jsx
  hooks/                                          useUser.js
    useUser.js                                   product-list/
    useProducts.js                                ProductCard.jsx
  utils/                                          useProducts.js
    formatDate.js                                formatPrice.js
    formatPrice.js
Layer-based Feature-based
Yangi funksiya qo'shish 4-5 ta papkaga bir nechta fayl qo'shiladi Bitta yangi papka, hammasi bir joyda
Funksiyani o'chirish Fayllarni har joydan qidirib topish kerak Bitta papkani o'chirish yetarli
Kichik loyiha uchun Qulay — kam fayl, tez topiladi Ortiqcha struktura
Katta loyiha (50+ komponent) uchun "Qayerda nima bor" qidirish qiyinlashadi Yaxshi masshtablanadi — jamoalar mustaqil ishlaydi

Amalda: kichik loyihalar layer-based bilan boshlaydi, o'sgach feature-based (yoki Feature-Sliced Design kabi rasmiy metodologiya) tomon siljiydi — chunki bitta funksiya ustida ishlayotganda, unga tegishli hamma narsa bir joyda bo'lishi kognitiv yukni kamaytiradi.


3. Data oqimi — nega yo'nalish muhim

Katta ilovalarda eng ko'p uchraydigan xato — ikki tomonlama, tartibsiz data bog'lanishi:

// XATARLI: ComponentA state'ni o'zgartiradi, ComponentB ham xuddi shu state'ga
// to'g'ridan-to'g'ri tegadi — kim, qachon o'zgartirganini kuzatib bo'lmaydi

Zamonaviy arxitektura unidirectional data flow (bir yo'nalishli data oqimi) printsipiga tayanadi:

State (bitta manba)
     │
     ▼
UI (state asosida render qilinadi)
     │
     ▼
Event (foydalanuvchi harakati — click, input)
     │
     ▼
Action / State yangilanishi
     │
     └──────► (yana State'ga qaytadi, doira yopiladi)

Bu — Redux, Zustand, hatto oddiy useState + props pattern'ning barchasida bir xil g'oya: data faqat bitta yo'nalishda oqadi, shuning uchun har qanday o'zgarish qayerdan kelganini aniq kuzatish mumkin. Bu — DOM va Virtual DOM darsida ko'rgan "eski vs yangi" solishtirish g'oyasining architectural darajadagi davomi: agar state qayerdan o'zgarganini bilmasangiz, nimani solishtirish kerakligini ham bilmaysiz.

State qayerda yashashi kerak — "state joylashuvi" qoidasi

State turi Qayerda saqlanadi Misol
Faqat bitta komponentga tegishli Local state (useState) Modal ochiq/yopiqligi
Bir nechta "qarindosh" komponentga kerak Lifted state (ota komponentda) Forma qiymati va uning preview'i
Butun ilovaga kerak Global state (Context, Redux, Zustand) Login qilgan foydalanuvchi, til
Server'dan kelgan, keshlanadigan Server state (React Query, SWR) API'dan olingan mahsulotlar ro'yxati

Eng ko'p uchraydigan arxitektura xatosi — hamma narsani global state'ga tiqish. Bu — har bir kichik o'zgarishda butun ilovani qayta render qilishga (yoki keraksiz murakkablikka) olib keladi. Qoida: state'ni iloji boricha pastda, kerak bo'lganda yuqoriga ko'taring ("lift state up" faqat zarurat tug'ilganda).


4. Komponent chegaralari — Coupling va Cohesion

Ikkita asosiy tushuncha arxitektura sifatini o'lchaydi:

  • Cohesion (bog'liqlik ichkarida) — bitta modul ichidagi narsalar qanchalik mantiqan birga turadi. Yuqori cohesion — yaxshi (useUser.js faqat user bilan ishlaydi).
  • Coupling (bog'liqlik tashqarida) — modullar bir-biriga qanchalik qattiq bog'langan. Past coupling — yaxshi (bitta modulni o'zgartirish boshqasini buzmasligi kerak).
// YUQORI COUPLING — yomon: ProductList to'g'ridan-to'g'ri Cart ichki tuzilmasini biladi
function ProductList({ cart }) {
  return <button onClick={() => cart.items.push(product)}>Qo'shish</button>;
}

// PAST COUPLING — yaxshi: ProductList faqat "nima kerakligini" e'lon qiladi,
// QANDAY bajarilishini bilmaydi
function ProductList({ onAddToCart }) {
  return <button onClick={() => onAddToCart(product)}>Qo'shish</button>;
}

Bu — Web Components darsida ko'rgan CustomEvent + composed: true g'oyasi bilan bir xil printsip: komponent o'z ichki holatini tashqariga oshkor qilmasdan, faqat "signal chiqaradi", tashqarisi qanday reaksiya berishni o'zi hal qiladi.


5. Rendering strategiyasini tanlash — arxitektura qarori

SSR vs CSR va Hydration darslarida ko'rgan tushunchalar — bu shunchaki texnik detal emas, balki arxitekturaning eng boshida qabul qilinadigan qaror, chunki uni loyihaning yarmisida o'zgartirish qimmatga tushadi:

Strategiya Qachon tanlanadi
CSR (Client-Side Rendering) Admin panel, dashboard — SEO kerak emas, tez ichki navigatsiya muhim
SSR (Server-Side Rendering) Blog, marketing sayt — SEO va tezkor birinchi ko'rinish muhim
SSG (Static Site Generation) Kontent kam o'zgaradigan sahifalar (dokumentatsiya, landing) — build vaqtida tayyorlanadi, server yuki yo'q
ISR (Incremental Static Regeneration) SSG + vaqti-vaqti bilan yangilanish kerak bo'lgan sahifalar (masalan, mahsulot narxi)

Bu qaror — sahifa darajasida ham qabul qilinishi mumkin (Next.js kabi framework'larda har bir route o'zining strategiyasini tanlashi mumkin): masalan, /blog/* — SSG, /dashboard/* — CSR, / — SSR. Bu — hybrid arxitektura, va aynan shu moslashuvchanlik zamonaviy meta-framework'larning asosiy qadriyati.


6. Code Splitting arxitekturasi — bundle chegaralari

Performance Budget darsida ko'rganimizdek, JS — eng "og'ir" resurs turi. Arxitektura darajasida bu shuni anglatadi: qaysi kod qachon yuklanishi kerakligini oldindan rejalashtirish:

// Route-based splitting — har bir sahifa alohida bundle
const Dashboard = lazy(() => import('./pages/Dashboard'));
const Settings = lazy(() => import('./pages/Settings'));

// Component-based splitting — kam ishlatiladigan, og'ir komponent uchun
const VideoEditor = lazy(() => import('./features/VideoEditor'));

Yaxshi arxitektura — foydalanuvchi hech qachon ishlatmasligi mumkin bo'lgan kodni (masalan, admin-only modal, murakkab chart kutubxonasi) boshlang'ich bundle'ga qo'shmaydi. Bu qaror papka tuzilmasi bilan chambarchas bog'liq: feature-based struktura, har bir features/* papkasini alohida chunk qilib bo'lish tabiiy ravishda osonlashtiradi.


7. Micro-frontends — jamoalar ko'payganda

Bitta katta ilova ustida 5-10 ta jamoa mustaqil ishlaganda, bitta umumiy kodbaza (monolith frontend) "hamma hammaga to'sqinlik qiladi" muammosiga olib keladi: bitta jamoaning deploy'i boshqasining ishini kutishi kerak bo'ladi.

Micro-frontend arxitekturasi — ilovani mustaqil deploy qilinadigan qismlarga bo'ladi, har biri o'z jamoasi, hatto o'z framework'i (React, Vue) bilan ishlashi mumkin:

shell-app (asosiy konteyner)
  ├── checkout-app     (Jamoa A, alohida deploy)
  ├── product-catalog  (Jamoa B, alohida deploy)
  └── user-profile     (Jamoa C, alohida deploy)

Bu yerda Shadow DOM darsida ko'rgan izolyatsiya g'oyasi amaliy ahamiyat kasb etadi: agar har bir micro-frontend o'z CSS/JS'ini olib kelsa, ular bir-birining stillariga "aralashib ketmasligi" uchun aynan Shadow DOM kabi native izolyatsiya vositalari ishlatiladi (yoki Module Federation kabi build-time yechimlar).

Muhim: micro-frontends — bu "har doim yaxshi" yechim emas, balki muammoga javob: agar sizda bitta kichik jamoa bo'lsa, bu ortiqcha murakkablik qo'shadi. Bu faqat tashkiliy shkala (ko'p mustaqil jamoa) muammosini yechadi, texnik muammoni emas.


8. Xavfsizlik va performance — arxitekturaga singib ketgan qarorlar

XSS darsida ko'rganimizdek, innerHTML yoki dangerouslySetInnerHTML — bu bitta joyda xato qilinadigan narsa emas, balki arxitektura darajasida oldini olinadigan narsa: agar loyihada "foydalanuvchi kiritgan HTML ko'rsatiladigan barcha joylar — faqat bitta <SafeHtml> komponenti orqali o'tadi" degan qoida bo'lsa, DOMPurify'ni har safar qo'lda chaqirish unutilmaydi, chunki tekshirish bitta markazlashgan joyda.

Xuddi shunday, Performance Budget — bu CI'da tekshiriladigan raqam bo'lishidan oldin, arxitektura qarori: yangi kutubxona qo'shishdan oldin "bu bizning bundle budget'imizga sig'adimi" degan savolni loyihalash bosqichida berish, keyin CI'da ushlab qolishdan ancha arzon.


9. V8 va brauzer darajasida — arxitektura qarorlari qanday moddiylashadi

Bu yerda muhim tushuncha bor: arxitektura o'zi V8'da "ishlamaydi" — u shunchaki kod tuzilishi. Lekin har bir arxitektura qarori, oxir-oqibat, V8 va brauzerning aniq, o'lchanadigan xarajatlariga aylanadi:

Feature-based struktura + Code splitting
    ↓ natijada
Kichikroq boshlang'ich bundle
    ↓ natijada
V8 kamroq baytni Parse + Compile qiladi (Ignition bosqichi qisqaradi)
    ↓ natijada
Main Thread tezroq bo'shaydi
    ↓ natijada
LCP / INP yaxshilanadi (foydalanuvchi HIS QILADIGAN natija)

Va aksincha: yomon arxitektura (hamma narsa bitta katta bundle'da, hamma narsa global state'da, har bir o'zgarish butun daraxtni qayta render qiladi) — bu to'g'ridan-to'g'ri ko'proq createElement/appendChild chaqiruvi, ko'proq reflow, ko'proq Long Task degani (Performance Budget darsida ko'rilgan 50ms chegara).

Ya'ni frontend arxitekturasi — bu shu kursda o'rgangan barcha past darajadagi mexanizmlarni (V8 Parse/Compile, DOM reflow/repaint, Event Loop, Virtual DOM diffing) loyihaning butun umri davomida boshqarib turish uchun ustiga qo'yiladigan inson qatlami.


10. Amaliy checklist — yangi loyiha boshlaganda so'raladigan savollar

  1. Tuzilma: Layer-based yetarlimi, yoki feature-based kerakmi (jamoa hajmi, loyiha o'sish tezligiga qarab)?
  2. State: Qaysi state global, qaysi lokal bo'lishi kerak — hammasini bitta joyga tiqmaslik.
  3. Rendering: Har bir sahifa uchun CSR/SSR/SSG/ISR'dan qaysi biri mos — SEO va tezlik talablariga qarab.
  4. Bundle chegaralari: Qaysi kod "darhol kerak", qaysi kod lazy() orqali kechiktirilishi mumkin.
  5. Xavfsizlik: Foydalanuvchi data'si ko'rsatiladigan joylar markazlashganmi, yoki har joyda alohida-alohida yozilganmi?
  6. Masshtablash: Agar jamoa 3 martaga ko'paysa, joriy tuzilma baribir ishlay oladimi, yoki micro-frontend kerak bo'ladimi?

Arxitektura — bir marta qabul qilinadigan qaror emas, balki loyiha o'sgani sayin qayta ko'rib chiqiladigan, doimiy jarayon.