Code Splitting
Code splitting strategiyasi: dynamic import() orqali bundle'ni chunk'larga bo'lish, route-based splitting (React.lazy/Suspense), bundler'ning split-point va shared-vendor optimallashtirishi, va bu strategiyaning Tree Shaking'dan farqi.
76-dars
Code Splitting
Tree shaking va minifikatsiyadan keyin ham, katta zamonaviy dastur (React/Vue kabi framework + barcha sahifalar + barcha kutubxonalar) bitta bundle.js faylga yig'ilsa, bu fayl osongina 1-2 MB yoki undan katta bo'lib qolishi mumkin.
Muammo shunda: foydalanuvchi saytga kirganda, hatto u faqat bosh sahifani ko'rmoqchi bo'lsa ham, brauzer butun 2 MB'ni yuklab olishi, parse qilishi va bajarishi kerak bo'ladi — shu jumladan /admin, /settings, /checkout kabi sahifalar uchun kerak bo'lgan kod ham, garchi foydalanuvchi ularga hech qachon kirmasligi mumkin.
Code splitting — bitta katta bundle'ni kichikroq bo'laklarga (chunk) bo'lib, ularni faqat kerak bo'lganda yuklash strategiyasi.
1. Qanday ishlaydi — asosiy mexanizm: Dynamic Import
Bu yerda ESM'ning statik importidan farqli, dinamik import() funksiyasi ishlatiladi (bu — ESM ichidagi yagona dinamik mexanizm):
// Statik import — bundle qurilishida DARHOL bitta chunk'ga qo'shiladi
import { heavyChart } from './chart.js';
// Dinamik import — ALOHIDA fayl (chunk) sifatida ajratiladi,
// va faqat chaqirilganda tarmoqdan yuklab olinadi
button.addEventListener('click', async () => {
const { heavyChart } = await import('./chart.js');
heavyChart();
});
import('./chart.js') — bu oddiy funksiya chaqiruvi, Promise qaytaradi. Bundler (webpack/Vite) buni ko'rganda: "Aha, bu yerda dinamik import bor — demak, chart.js va uning barcha bog'liqliklarini alohida faylga (masalan, chunk-3f2a1.js) chiqarib qo'yaman, va asosiy bundle'ga faqat uni so'rov yuborish kodini qoldiraman."
2. Natijada nima hosil bo'ladi — fayl darajasida
Build'dan keyin siz papkada shunga o'xshash fayllarni ko'rasiz:
dist/
main.js ← asosiy kod (kichik, tez yuklanadi)
vendor.js ← React/Vue kabi katta kutubxonalar (alohida keshlanadi)
chunk-a1b2.js ← faqat /admin sahifasi uchun kod
chunk-c3d4.js ← faqat chart komponenti uchun kod
Brauzer boshida faqat main.jsni yuklaydi. Foydalanuvchi /adminga o'tganda yoki chart ko'rsatiladigan tugmani bosganda, brauzer yangi <script> tegini dinamik ravishda DOM'ga qo'shadi (bu ishni bundler'ning runtime kodi avtomatik bajaradi) va tegishli chunk'ni tarmoqdan yuklab oladi.
3. Route-based splitting — eng ko'p ishlatiladigan amaliyot
React'da odatda sahifalar (route) bo'yicha bo'linadi:
import { lazy, Suspense } from 'react';
const AdminPage = lazy(() => import('./AdminPage.jsx'));
const SettingsPage = lazy(() => import('./SettingsPage.jsx'));
function App() {
return (
<Suspense fallback={<div>Yuklanmoqda...</div>}>
<Routes>
<Route path="/admin" element={<AdminPage />} />
<Route path="/settings" element={<SettingsPage />} />
</Routes>
</Suspense>
);
}
React.lazy() — ichida import() chaqiruvi bo'lgan komponentni "kechiktirilgan" qilib beradi. Suspense — bu komponent hali yuklanayotgan paytda (tarmoq so'rovi tugamaguncha) nima ko'rsatishni belgilaydi (fallback).
Bu — oldingi bosqichda o'tgan Lazy loading g'oyasining komponent/route darajasidagi ko'rinishi (o'sha safar rasm/elementlar uchun Intersection Observer orqali edi, bu yerda esa butun JS moduli uchun).
4. Bundler ichida qanday algoritm ishlaydi (Webpack misolida)
- Grafni qurish — bundler avval statik va dinamik importlarning barchasini o'qib, module graph'ni tuzadi (tree shaking'dagi bilan bir xil bosqich).
- "Split point"larni aniqlash — har bir
import()chaqiruvi — bu grafda "bo'linish nuqtasi". Bundler shu nuqtadan boshlab kerak bo'ladigan barcha modullarni alohida chunk'ka ajratadi. - Umumiy bog'liqliklarni optimallashtirish (SplitChunksPlugin) — agar ikkita turli chunk bir xil kutubxonani (masalan, ikkalasi ham lodash ishlatsa) import qilsa, bundler buni aqlli tarzda aniqlab, alohida umumiy chunk'ka chiqaradi — aks holda lodash ikki marta (ikkala chunk'da) takrorlanib, umumiy hajm ortib ketardi.
Agar chunk-A va chunk-B ikkalasi ham lodash ishlatsa:
❌ Yomon: chunk-A (lodash + A kodi), chunk-B (lodash + B kodi) — lodash 2x
✅ Yaxshi: chunk-A (faqat A), chunk-B (faqat B), shared-vendor (lodash, bitta marta)
5. Brauzer/V8 darajasida nima sodir bo'ladi
Bu qism sof build-time strategiya bo'lsa-da, uning ishlashi to'g'ridan-to'g'ri brauzerning tarmoq va parsing xatti-harakatiga bog'liq:
- Dinamik
import('./chart.js')chaqirilganda, bundler runtime kodi (masalan, Webpack'ning__webpack_require__.e()) yangi<script>elementini yaratib, unidocument.headga qo'shadi. - Brauzer bu faylni alohida HTTP so'rov orqali yuklaydi (agar u allaqachon keshda bo'lmasa).
- Fayl yuklangach, V8 uni parse qiladi va bajaradi — bu yerda V8 lazy parsing deb ataladigan optimallashtirishni qo'llaydi: katta fayl kelganda, V8 darhol ichki funksiyalarning to'liq tanasini parse qilmaydi, faqat ularning "shakli" (nomi, parametrlari)ni saqlab, haqiqiy chaqirilganda to'liq parse qiladi. Bu — Code splitting bilan bevosita bog'liq bo'lmasa-da, kichikroq chunk kelganda umumiy parse+compile vaqti kamayishiga qo'shimcha yordam beradi.
- Promise resolve bo'lgach (
await import(...)), modul obyekti qaytariladi va sizning kodingiz davom etadi.
Nega bu Tree shaking'dan farq qiladi (chalkashtirmaslik uchun)
| Tree Shaking | Code Splitting | |
|---|---|---|
| Nima qiladi | Ishlatilmagan kodni butunlay o'chiradi | Ishlatiladigan kodni guruhlarga bo'ladi, hammasi saqlanadi |
| Maqsad | Umumiy hajmni kamaytirish | Boshlang'ich yuklash vaqtini kamaytirish (kerak bo'lmagan qismni keyinga qoldirish) |
| Natija | Kod umuman yo'q bo'ladi | Kod bor, lekin boshqa faylda, kerak bo'lganda yuklanadi |
Ikkalasi ham birga ishlatiladi va bir-birini to'ldiradi — avval tree shaking ortiqcha narsani o'chiradi, keyin qolgan kerakli kod code splitting orqali oqilona bo'laklarga bo'linadi.