Minification
Minification jarayoni: Tree Shaking'dan farqi, minifier'ning AST orqali ishlashi (mangling, constant folding, DCE), Gzip/Brotli bilan minification farqi, va V8'ning parse vaqtiga ta'siri haqiqatda qanday ekani.
77-dars
Minification
Minification — kodning bajarilishiga hech qanday ta'sir qilmasdan, uning hajmini kichraytirish jarayoni: keraksiz bo'shliqlar, izohlar, uzun o'zgaruvchi nomlari olib tashlanadi/qisqartiriladi.
// Minifikatsiyadan OLDIN (real loyihada minglab qator)
function calculateTotalPrice(price, taxRate) {
// Soliqni qo'shib umumiy narxni hisoblaymiz
const total = price + (price * taxRate);
return total;
}
// Minifikatsiyadan KEYIN
function calculateTotalPrice(n,t){return n+n*t}
Diqqat qiling: price → n, taxRate → tga aylandi, izoh yo'q qilindi, bo'shliqlar olib tashlandi, hatto oraliq total o'zgaruvchisi ham butunlay yo'qotildi (chunki u faqat bir marta ishlatilib, keyin qaytarilgan — natijani to'g'ridan-to'g'ri hisoblash mumkin).
1. Nega Tree shaking'dan farq qiladi — chalkashtirmaslik uchun
Bu ikkalasi ko'pincha bitta vosita (Terser, esbuild) orqali, bitta build bosqichida ishlaydi, shuning uchun chalkashib ketadi:
| Tree Shaking | Minification | |
|---|---|---|
| Nima qiladi | Ishlatilmagan kodni butunlay o'chiradi | Qolgan (kerakli) kodni qisqartiradi |
| Mantiqiy o'zgarish | Dastur mantig'idan kod yo'qoladi | Dastur mantig'i bir xil qoladi, faqat matn shakli o'zgaradi |
| Misol | unused() funksiyasi butunlay yo'qoladi |
function add(a,b){return a+b} qisqaroq yoziladi |
Ya'ni: avval tree shaking "kerak bo'lmagan butun bloklarni" kesib tashlaydi, keyin minification "qolgan har bir belgini" siqadi.
2. Minifier (masalan, Terser) qanday ishlaydi — bosqichma-bosqich
Bu yerda muhim narsa: minifier kodni matn sifatida regex bilan o'zgartirmaydi (bu juda xavfli bo'lardi — string ichidagi bo'shliqni ham o'chirib qo'yishi mumkin). Buning o'rniga, u to'liq compiler pipeline'dan foydalanadi — xuddi V8'ning o'zi ichida bo'lgani kabi:
1-bosqich: Parsing → AST (Abstract Syntax Tree)
Kod avval tokenlarga (lekser), keyin daraxt tuzilmasiga (parser) aylantiriladi — bu aynan V8'ning Ignition bosqichida qilgan ishiga o'xshash. Masalan:
function add(a, b) { return a + b; }
AST ko'rinishida (soddalashtirilgan):
FunctionDeclaration
name: "add"
params: [Identifier "a", Identifier "b"]
body: ReturnStatement
argument: BinaryExpression "+"
left: Identifier "a"
right: Identifier "b"
2-bosqich: Transformatsiyalar (AST darajasida)
Minifier AST ustida bir qancha xavfsiz o'zgartirishlarni amalga oshiradi:
Nomlarni qisqartirish (mangling) — lokal o'zgaruvchilar va parametrlar a, b, c, ... kabi bir harfli nomlarga almashtiriladi. Bu faqat lokal scope'dagi nomlarga tegishli (closure orqali tashqaridan ko'rinadigan yoki global nomlarga tegilmaydi — aks holda kod buzilib qolardi).
function calculateTotalPrice(price, taxRate) { /* ... */ }
// →
function calculateTotalPrice(n, t) { /* ... */ } // funksiya nomi qoladi (export bo'lishi mumkin), parametrlar qisqaradi
O'lik kodni yo'q qilish (DCE, funksiya ichida) — if (false) {...}, ishlatilmagan lokal o'zgaruvchilar olib tashlanadi (bu — tree shaking'ning modul darajasida emas, funksiya ichidagi kichik versiyasi).
Konstant ifodalarni oldindan hisoblash (constant folding):
const SECONDS_IN_DAY = 60 * 60 * 24;
// →
const SECONDS_IN_DAY = 86400; // build vaqtida hisoblab qo'yiladi
Qisqaroq ekvivalent sintaksisga almashtirish:
if (x === true) { return true; } else { return false; }
// →
return x === true;
3-bosqich: Generatsiya (Codegen)
Optimallashtirilgan AST qaytadan **matn (kod)**ga aylantiriladi — bu safar minimal bo'shliq, qisqa nomlar bilan, yangi qator belgilari ham deyarli olib tashlanadi (; bilan ajratilgan bitta uzun qator).
3. Bu jarayon Tree Shaking bilan qanday birgalikda ishlaydi (real pipeline)
Zamonaviy build jarayonida ketma-ketlik odatda shunday:
1. Bundling — barcha modullar bitta grafga yig'iladi
2. Tree Shaking — ishlatilmagan export/importlar o'chiriladi
3. Minification — qolgan kod qisqartiriladi (nomlar, bo'shliqlar, constant folding)
4. (ixtiyoriy) Compression — Gzip/Brotli orqali tarmoq orqali yuborishda yana siqiladi
Gzip/Brotli bilan farqi — bu muhim, chunki ko'pincha aralashtiriladi: Minification — fayl mazmunini o'zgartiradi (build vaqtida, bir marta), Gzip/Brotli esa transport siqish — server fayl yuborayotganda runtime'da siqadi, brauzer qabul qilib avtomatik ochadi (decompress), fayl diskda/keshda siqilmagan holatda turadi. Ikkalasi birga ishlatilganda eng katta yutuq bo'ladi: minifikatsiya qilingan kod Gzip orqali yana **qo'shimcha 60-70%**gacha kichrayishi mumkin (chunki qisqa, takrorlanuvchi nomlar Gzip'ning algoritmi uchun yanada samarali siqiladi).
4. V8 darajasida — bu Parse/Compile vaqtiga qanday ta'sir qiladi
Bu yerda ikkita alohida ta'sirni ajratish kerak:
- Tarmoq orqali yuklash vaqti — eng katta yutuq shu yerda. Kichikroq fayl = tezroq yuklanadi, ayniqsa sekin tarmoqlarda.
- V8'ning parse vaqti — bu yerda kutilmagan nozik nuqta bor: minifikatsiya V8'ning parse tezligiga sezilarli darajada katta ta'sir qilmaydi, chunki V8 parser baribir belgi-belgi (character by character) ishlaydi — qisqa nom (
n) yoki uzun nom (taxRate) parse qilish uchun deyarli bir xil vaqt ketadi (farq — necha baytni o'qish, bu mikrosekundlar darajasida). Asosiy yutuq bayt hajmi kamayishidan (tarmoq + xotira), parse algoritmik tezligidan emas.
Biroq, bilvosita foyda bor: kichikroq fayl V8'ning lazy parsing mexanizmiga (Code splitting mavzusida eslatilgan) yordam beradi — kichikroq funksiyalar V8'ning ichki heuristikasida tezroq "to'liq parse qilishga arziydi" deb baholanishi mumkin, lekin bu — ikkinchi darajali effekt, minifikatsiyaning asosiy maqsadi emas.
Amaliy vositalar
- Terser — hozirgi standart JS minifier (Webpack'da default, UglifyJS'ning vorisi — UglifyJS ES6+ sintaksisni to'liq qo'llab-quvvatlamagani uchun almashtirilgan).
- esbuild — Go tilida yozilgan, minifikatsiyani o'nlab marta tezroq bajaradi.
- SWC — Rust'da yozilgan, Next.js'da default ishlatiladigan minifier/compiler.