IlmHamroh
JavaScript Full-stack/23-qism. Next.js38/43-dars20 daqiqa
Mundarija (36)

Next.js performance: Lighthouse, brauzer yuklagan JS va client chegarasi

Qisqacha: Next.js ilovasining tezligi taxmin bilan emas, o'lchov bilan boshqariladi. Laboratoriyada — Lighthouse (mobil), haqiqiy foydalanuvchida — useReportWebVitals. Brauzerga ketadigan JS'ning katta qismini React va Next'ning o'zi oladi (portfolio da ~132 KB gzip). Sizning qo'lingizdagi asosiy dastak — client chegarasini kichik saqlash. Og'ir ish serverda, "use client" esa faqat kerakli kichik komponentda. Kanon portfolio da ikki o'zgarish o'lchangan natija berdi: next-intl client qismini o'z Link imiz bilan almashtirish (161.7 → 149.6 KB) va LCP'ni kechiktirgan kirish animatsiyasini olib tashlash (Performance 93–96 → 97–98).

Bu darsda

  • Lighthouse natijasini o'qiysiz va LCP qaysi qismlardan iboratini bilasiz.
  • Next 16.4 build jadvalida "First Load JS" yo'qligini va JS'ni boshqacha qanday o'lchashni bilasiz.
  • next analyze bilan og'ir modulni topasiz va client chegarasini toraytirib JS'ni kamaytirasiz.
  • next/dynamic (React lazy), prefetch va <Activity> ning foydasi va narxini tushuntirasiz.
  • Kirish animatsiyasining LCP narxini o'lchov bilan ko'rasiz — va LCP'ni kechiktirmaydigan variantini.

Oldin bilishingiz kerak: Core Web Vitals: LCP, INP, CLS, Yuklanishni optimallashtirish, lazy va code splitting, <Activity>, Layout va template, next.config chuqur.

1. Nega bu kerak?

Next.js nima darsida narxni ko'rgandingiz: bo'sh Next sahifasi brauzerga 132.4 KB (gzip) JS yuboradi. v1 portfolio — faqat HTML, CSS va kichik asosiy.js. Har qo'shilgan client komponent, har kutubxona bu raqamni oshiradi.

Layout va template darsida esa va'da berdik: 200 ms lik kirish animatsiyasi LCP'ni kechiktirdi, va "LCP'ni kechiktirmaydigan variantini Performance darsida sinab ko'ramiz". Bu dars — o'sha.

Telefon va sekin internet — Aziz'ning o'quvchilari (va ish beruvchilari) aynan shunday ochadi. Lighthouse mobil profili shuni taqlid qiladi: o'rtacha telefon, sekin 4G.

O'xshatish: chamadon. Safarga hamma narsani olsangiz, chamadon og'ir — aeroportda kechikasiz. Tajribali sayohatchi avval tarozida o'lchaydi, keyin keraksizini chiqaradi. Lighthouse — tarozi, next analyze — chamadon ichini ko'rsatadigan rentgen.

2. O'lchash: nima va qanday

2.1 Ikki xil o'lchov

Laboratoriya (lab) Maydon (field)
Vosita Lighthouse, DevTools useReportWebVitals, Speed Insights, CrUX
Qayerda Sizning kompyuteringizda, taqlid Haqiqiy foydalanuvchilar brauzerida
Afzalligi Takrorlanadi, o'zgarishni solishtirish oson Haqiqat
Kamchiligi Taqlid — haqiqiy telefon emas Ko'p tashrif kerak, kechikib keladi

Core Web Vitals darsida uchtasini o'rgangansiz: LCP (eng katta element chizilishi), INP (bosishga javob), CLS (sakrash). Kanon laboratoriya o'lchovini qildi: Lighthouse 13.5.0, mobil, Chrome 155.

2.2 Build jadvalida JS hajmi yo'q

Next 15 gacha next build har sahifa yonida "First Load JS" ustunini chiqarardi. Next 16.0 da bu raqamlar olib tashlangan (CLI hujjatining versiya tarixi), 16.4 da ham yo'q — kanon buni build chiqishida ko'rdi. Holat 37 build jadvalidan parcha:

text
Route (app)                                       Revalidate  Expire
┌ ○ /_not-found
├   /[locale]
│ ├ ◐ /[locale]
│ ├ ○ /uz
│ └ ○ /en
├   /[locale]/blog                                       30d      1y
├ ƒ /api/qayta-yangila
└ ○ /sitemap.xml                                         30d      1y

Faqat render turi (○, ◐, ƒ) va kesh muddati. Shuning uchun kanon JS'ni brauzerda o'lchadi: sahifani headless Chrome'da ochib, tarmoqdan kelgan JS fayllarni (gzip) qo'shib chiqdi. Bu raqam "foydalanuvchi aslida nimani yuklaydi" degan savolga eng halol javob.

2.3 JS yo'li: 132.4 dan 149.6 gacha

portfolio bosh sahifasining JS hajmi asosiy holatlarda (pastdagi raqam — holat, ya'ni dars raqami):

Bosh sahifa JS (gzip)
JS, KB
161,7132,4238holat/: 2 → 132,4 KB/: 6 → 137,4 KB/: 8 → 143,4 KB/: 23 → 145,6 KB/: 30 → 146,5 KB/: 34 → 161,7 KB/: 38 → 149,6 KB
Bosh sahifa JS (gzip)
holat/
2132,4
6137,4
8143,4
23145,6
30146,5
34161,7
38149,6

Manba: IlmHamroh kanoni, sahifalar.mjs (Chrome 155, gzip tarmoq baytlari), 2026-10-21

Grafikda 7 ta nuqta; oraliq holatlar (04 — 135.4, 13 — 143.9 KB) tushirib qoldirildi, yo'nalish o'zgarmaydi. Chiziqqa qarang: deyarli tekis, bitta keskin sakrash — holat 34 (next-intl, +15.2 KB) va keyingi tushish — holat 38 (bu dars). 132.4 KB — Next va React'ning o'zi, uni olib tashlab bo'lmaydi. Qolgan 17 KB — butun portfolio: modal, filtr, tema, forma.

Tekshirib ko'ring: Blog posti sahifasi Markdown'ni HTML'ga aylantirish uchun marked kutubxonasini (540 KB node_modules) ishlatadi. U brauzer JS'iga qancha qo'shadi?

Javob

Nol. marked Server Component'da ishlaydi: Markdown build vaqtida serverda HTML'ga aylanadi, brauzerga faqat tayyor HTML boradi. Blog sahifasining JS'i (144.7 KB) eng kichiklardan. "Og'ir ishni serverda qiling" — Next hujjatining asosiy performance maslahati ham shu.

3. JS ichida nima bor

3.1 next analyze

Next 16.1 dan beri Turbopack uchun o'z bundle tahlilchisi bor (16.1 da next experimental-analyze nomi bilan qo'shilgan, 16.4 hujjatida — next analyze). Biz portfolio (holat 43 nusxasi) da ishga tushirdik:

bash
npx next analyze --output
text
✓ Running next.config.ts took 70ms
  Analyzing a production build...
✓ Analyze completed in 2.8s. Results written to C:\Users\…\p\.next\diagnostics\analyze.
To explore the analyze results interactively, run `next analyze` without `--output`.

--output siz npx next analyze brauzerda interaktiv xarita ochadi: har modul — to'rtburchak, maydoni — hajmi. Modulni bossangiz, uni kim import qilganini (import zanjiri) ko'rsatadi. --output esa natijani diskka yozadi (bizda 8.9 MB papka) — jamoadoshga yuborish yoki "oldin/keyin" solishtirish uchun. Kanon kuzatdi: natija ikkilik ma'lumot, matnli hisobot yo'q — tahlil UI orqali.

Webpack bilan ishlaydigan loyihalarda (eski) — @next/bundle-analyzer plagini; Next hujjati uni alohida bo'limda beradi.

3.2 Kanon topgan eng katta bo'laklar (holat 37, gzip)

Bo'lak Hajm Kimniki
react-dom 73.3 KB React
Next runtime (ikki chunk) 39.4 + 35.7 KB Next.js router, RSC klienti
next-intl / use-intl 14.3 KB i18n kutubxonasi
modal 5.9 KB bizning RasmOynasi

Birinchi ikkitasi — framework, ularni olib tashlab bo'lmaydi. Uchinchisi — next-intl — kanonni qiziqtirdi: NextIntlClientProvider ga messages={null} berilgan, ya'ni brauzerda tarjima umuman ishlatilmaydi. Lekin 14.3 KB baribir yuklanadi (IntlMessageFormat va boshqalar).

4. Client chegarasini kichik saqlash

4.1 Muammo

next-intl darsida portfolio da brauzerga kerak bo'lgan yagona i18n narsasi — havolalarga /en prefiksini qo'shish edi. Tarjima esa serverda (getTranslations). next-intl'ning client qismi buning uchun butun xabar formatlash dvigatelini olib keldi.

Kanon holat 38 da NextIntlClientProvider ni olib tashladi va src/i18n/navigation.tsx ni yozdi — next/link ustida yupqa o'ram:

tsx
"use client";

import NextLink from "next/link";
import { useParams } from "next/navigation";
import type { ComponentProps } from "react";
import { routing } from "./routing";
import { tilYoli } from "./yol";

function joriyTil(
  params: Record<string, string | string[] | undefined>,
): string {
  const t = params.locale;
  return typeof t === "string" ? t : routing.defaultLocale;
}

/** href — tilsiz ichki yo'l; joriy til prefiksi o'zi qo'shiladi */
export function Link({
  href,
  ...props
}: Omit<ComponentProps<typeof NextLink>, "href"> & { href: string }) {
  const til = joriyTil(useParams());
  return <NextLink href={tilYoli(til, href)} {...props} />;
}

Faylda yana usePathname o'rami bor (/en/blog → /blog); bu yerda qisqartirildi. Kanon izohi: "next-intl client qismi brauzerga 14.3 KB gzip qo'shardi, bizga esa faqat /en prefiksi kerak".

Natija (kanon o'lchovi): bosh sahifa JS 161.7 → 149.6 KB gzip (−12.1), xom 524.2 → 485.1 KB. Regressiya: til almashtirgich, lang atributi, inglizcha forma xatolari — o'zgarmadi.

4.3 Qoida

Client chegarasi — daraxtdagi "use client" qo'yilgan nuqta: undan pastdagi hamma import brauzerga ketadi (Client Components). Uch amaliy savol:

Savol Agar "ha" bo'lsa
Bu komponentga bosish, state, effekt kerakmi? Client — lekin faqat shu kichik qism
Kutubxona ma'lumotni UI'ga aylantiradimi (Markdown, grafik, kod rang berish)? Serverda qiling
Kutubxona'ning client qismidan nimadir 10% ishlatilyaptimi? O'z kichik o'ramingizni yozing (o'lchab!)

Uchinchisida "o'lchab" so'zi muhim. O'z kodingiz — xizmat ko'rsatish narxi: next-intl yangilansa, o'ram o'zgarmaydi; createNavigation ning ba'zi imkoniyatlari (masalan typed pathnames) yo'q. Kanon −12 KB uchun shu narxni qabul qildi va sababni kodga yozdi.

5. Kechiktirib yuklash: next/dynamic

5.1 G'oya

Ba'zi komponent sahifada bor, lekin darhol kerak emas: tugma bosilgandagina ochiladigan grafik, xarita, muharrir. Uning kodini sahifa bilan birga yuklash — isrof. lazy darsida React'ning lazy + Suspense ini ko'rgansiz. Next'da uning o'rami — next/dynamic:

tsx
"use client";
import dynamic from "next/dynamic";

const Grafik = dynamic(() => import("./Grafik"), {
  loading: () => <p>Yuklanmoqda…</p>,
});

ssr: false qo'shilsa, komponent serverda umuman chizilmaydi (faqat brauzer API'siga muhtoj kutubxonalar uchun). Bu variant faqat client komponent ichida ishlaydi.

5.2 Jonli: kod faqat kerak bo'lganda

Natija oynasida next/dynamic yo'q, lekin u ichida aynan React lazy ishlaydi. «Ishga tushir» ni bosing — konsolga qarang:

tsx
import { lazy, Suspense, useState } from "react";

function Chart() {
  return <p>Grafik: 3 ta ustun</p>;
}

const LazyChart = lazy(() => {
  console.log("grafik kodi yuklanmoqda");
  return Promise.resolve({ default: Chart });
});

export default function App() {
  const [show, setShow] = useState(false);
  return (
    <section>
      <h1>Loyiha statistikasi</h1>
      <button onClick={() => setShow(true)}>
        Grafikni ko'rsatish
      </button>
      {show && (
        <Suspense fallback={<p>Yuklanmoqda…</p>}>
          <LazyChart />
        </Suspense>
      )}
    </section>
  );
}

Konsolda:

text
grafik kodi yuklanmoqda

Ekranda:

text
Loyiha statistikasi
Grafikni ko'rsatish
Grafik: 3 ta ustun

"grafik kodi yuklanmoqda" — faqat tugma bosilgach. Tugmani bosmagan foydalanuvchi grafik kodini umuman yuklamaydi. Haqiqiy loyihada import("./Grafik") alohida JS fayl (chunk) bo'lib, tarmoqdan keladi; bu yerda Promise.resolve uni taqlid qiladi.

portfolio da next/dynamic yo'q — og'ir client komponent yo'q (eng kattasi modal, 5.9 KB). Kechiktirish ham bepul emas: tugma bosilganda kutish paydo bo'ladi. U 30–50 KB dan katta, darhol ko'rinmaydigan narsalar uchun.

6. Prefetch va <Activity>: tezlikning yashirin narxi

6.1 Prefetch

<Link> ekranda ko'ringan zahoti Next uning sahifasini oldindan yuklaydi (prefetch) — bossangiz, o'tish bir zumda. portfolio da partialPrefetching: true (Navigatsiya): sahifaning statik qismi oldindan olinadi. Kanon o'lchadi — sahifa ochilganda prefetch so'rovlari:

text
/: RSC prefetch 13 ta, 59.0 KB (xom)
/loyihalar: RSC prefetch 22 ta, 60.7 KB (xom)
/blog: RSC prefetch 14 ta, 56.2 KB (xom)

Har ko'rinadigan havola — bitta RSC so'rovi. 22 ta so'rov, ~60 KB — foydalanuvchi hech qayerni bosmasa ham. Mobil internet paketida bu sezilarli. Kanon o'zgartirmadi: sayt kichik, navigatsiya tezligi muhimroq. Lekin ro'yxat 200 ta havola bo'lsa (masalan katta katalog), <Link prefetch={false}> — bosilganda yuklash — to'g'ri tanlov bo'ladi.

6.2 <Activity>: eski sahifa yashirin yashaydi

Activity darsida aytgandik: framework'lar <Activity> dan navigatsiyada foydalanadi. Next 16 hujjati aniq yozadi: Cache Components yoqilganda Next sahifadan chiqqanda uni o'chirmaydi, <Activity> bilan yashiradi (display: none) — state va DOM saqlanadi. Ko'pi bilan 3 ta marshrut; undan eskisi o'chiriladi. Natija oynasida mexanizmni ko'ring — «+1» ni ikki marta bosib, Blog'ga o'ting va qaytib keling:

tsx
import { Activity, useState } from "react";

function HomePage() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>Bosh sahifa: {count}</p>
      <button onClick={() => setCount(count + 1)}>+1</button>
    </div>
  );
}

export default function App() {
  const [page, setPage] = useState("/");
  return (
    <>
      <nav>
        <button onClick={() => setPage("/")}>Bosh sahifa</button>{" "}
        <button onClick={() => setPage("/blog")}>Blog</button>
      </nav>
      <Activity mode={page === "/" ? "visible" : "hidden"}>
        <HomePage />
      </Activity>
      {page === "/blog" && <p>Blog sahifasi</p>}
    </>
  );
}

Ekranda:

text
Bosh sahifa Blog
Bosh sahifa: 2
+1

Qaytganda hisob 2 — sahifa o'chirilmagan, yashiringan edi. Foydasi: orqaga qaytish bir zumda, yozilgan forma, scroll joyida. Narxi: xotira. Uchta sahifa DOM'i va state'i bir vaqtda yashaydi. Shuning uchun Next chegarani 3 ta bilan qo'ygan. Ochiq qolib ketgan menyular kabi "vaqtinchalik" holatni esa effekt tozalashida yopish kerak (Next hujjatidagi "Preserving UI state" qo'llanmasi).

7. LCP va animatsiya: va'da bajarildi

7.1 Kanon o'lchovi

Holat 37 da hamma sahifada template.tsx dagi 200 ms kirish animatsiyasi bor edi (opacity: 0 + translate). Lighthouse (mobil), 5 sahifa:

Performance LCP TBT
holat 37 (animatsiya bilan) 93–96 2.7–3.2 s 40–80 ms
holat 38 (animatsiyasiz, o'z Link) 97–98 2.4–2.6 s 40–90 ms

Bosh sahifaning LCP elementi — kirish paragrafi (main > p). Lighthouse LCP'ni qismlarga ajratdi: "Element render delay" (elementni chizish kechikishi) 345 ms — paragraf opacity: 0 dan boshlanadi, brauzer uchun shaffof matn "hali chizilmagan".

7.2 Biz o'lchadik: uch variant

Layout va template darsida taxmin aytgandik: animatsiyani faqat translate bilan qilsa (opacity siz), LCP kechikmasligi kerak. Tekshirdik. portfolio holat 43 nusxasiga template.tsx ni qaytardik va uch variantni bir xil sharoitda o'lchadik — har biri 3 marta, Lighthouse 13.5.0 mobil, Chrome 155:

text
yoq #1 /: perf 98 | LCP 2.4 s, FCP 0.8 s, TBT 50 ms, CLS 0 | timeToFirstByte 21 ms, elementRenderDelay 111 ms
yoq #2 /: perf 98 | LCP 2.4 s, FCP 0.8 s, TBT 40 ms, CLS 0 | timeToFirstByte 6 ms, elementRenderDelay 86 ms
yoq #3 /: perf 98 | LCP 2.4 s, FCP 0.8 s, TBT 40 ms, CLS 0 | timeToFirstByte 15 ms, elementRenderDelay 88 ms
opacity #1 /: perf 97 | LCP 2.6 s, FCP 0.8 s, TBT 40 ms, CLS 0 | timeToFirstByte 17 ms, elementRenderDelay 317 ms
opacity #2 /: perf 93 | LCP 3.2 s, FCP 0.8 s, TBT 100 ms, CLS 0 | timeToFirstByte 7 ms, elementRenderDelay 275 ms
opacity #3 /: perf 94 | LCP 3.0 s, FCP 0.8 s, TBT 90 ms, CLS 0 | timeToFirstByte 8 ms, elementRenderDelay 319 ms
translate #1 /: perf 98 | LCP 2.4 s, FCP 0.8 s, TBT 50 ms, CLS 0 | timeToFirstByte 17 ms, elementRenderDelay 150 ms
translate #2 /: perf 98 | LCP 2.4 s, FCP 0.8 s, TBT 40 ms, CLS 0 | timeToFirstByte 6 ms, elementRenderDelay 60 ms
translate #3 /: perf 98 | LCP 2.4 s, FCP 0.8 s, TBT 50 ms, CLS 0 | timeToFirstByte 8 ms, elementRenderDelay 86 ms

Mediana (o'rtadagi qiymat) bilan:

Bosh sahifa: LCP elementining chizilish kechikishi (3 o'lchov, mediana)
  • animatsiyasizperf 98, LCP 2.4 s88 ms
  • opacity + translateperf 94, LCP 3.0 s317 ms
  • faqat translateperf 98, LCP 2.4 s86 ms

Manba: IlmHamroh, biz ishga tushirdik: portfolio holat 43 + template, Lighthouse 13.5.0 mobil, Chrome 155, 2026-10-21

Taxmin tasdiqlandi. opacity siz animatsiya LCP'ga ta'sir qilmadi — natija animatsiyasiz variant bilan bir xil. Sababi: LCP "element ekranda ko'rindi" paytini o'lchaydi. Siljiyotgan, lekin ko'rinadigan matn — ko'rindi; shaffof matn — yo'q.

Kanon baribir animatsiyani olib tashladi (holat 38) — sodda yo'l. Siz portfolio ingizda translate variantni qoldirsangiz ham, endi narxi nol ekanini bilasiz. Asosiysi — o'lchov taxminni tasdiqladi yoki rad etdi, bahs emas.

E'tibor bering: bitta o'lchov aldaydi. opacity #1 da Performance 97 — yaxshi ko'rinadi. Uchta o'lchov 93–97 oralig'ini berdi. Lighthouse natijasi har safar biroz o'zgaradi — xulosani bir nechta o'lchovdan chiqaring.

7.3 SEO 92 — nega 100 emas

Hamma o'lchovda SEO 92 edi, sababi bitta: canonical havola example.com ga ishora qiladi, Lighthouse esa localhost ni o'lchaydi. Kanon SAYT_URL=http://localhost:3127 bilan build qildi — SEO 100. Bu Env o'zgaruvchilar darsidagi "build vaqtida yoziladi" faktining yana bir ko'rinishi.

8. Qolgan vositalar

8.1 React Compiler

reactCompiler: true (next.config chuqur) — komponentlarni avtomatik memo qiladi (React Compiler). U qayta render muammosini yechadi — INP va interaktivlik. portfolio da bunday muammo o'lchanmagan: client komponentlar kichik, TBT 40–90 ms. Kanonga kirmadi. Qoida o'sha: avval DevTools Profiler'da sekin render'ni toping, keyin yoqing.

8.2 Maydon o'lchovi: useReportWebVitals

Haqiqiy foydalanuvchilarda Web Vitals'ni yig'ish uchun Next hook beradi:

tsx
"use client";
import { useReportWebVitals } from "next/web-vitals";

export function WebVitals() {
  useReportWebVitals((metric) => {
    // metric.name: "LCP" | "INP" | "CLS" | "FCP" | "TTFB"
    navigator.sendBeacon("/api/vitals", JSON.stringify(metric));
  });
  return null;
}

Komponent root layout'ga qo'yiladi. Callback har safar yangi funksiya bo'lmasligi kerak. Hujjat ogohlantiradi: aks holda bir o'lchov ikki marta yuboriladi. Core Web Vitals darsida web-vitals kutubxonasi bilan qilgan ishning Next'dagi o'rni shu. portfolio da yo'q: o'lchovni yig'adigan joy (backend) hali yo'q. Vercel'ning Speed Insights xizmati xuddi shuni tayyor qiladi — Vercel hisobi kerak, biz sinamadik.

9. Portfolio qadami: holat 38 va commit

O'zgarish Natija
template.tsx va sahifa-kirish animatsiyasi olib tashlandi LCP 2.7–3.2 → 2.4–2.6 s
src/i18n/navigation.tsx — o'z Link va usePathname; NextIntlClientProvider olib tashlandi JS 161.7 → 149.6 KB

Kanon tekshiruvi: lint, tip, format — 0; axe 0, hydration 0; regressiya (filtr, modal, tema, forma, i18n, CSP) — o'tdi. Holat 38 jadvali:

Sahifa JS gzip Lighthouse Perf
/, /loyihalar 149.6 KB 98
/loyihalar/vazifalar 155.3 KB 97
/blog/portfolio-v2 144.7 KB 98
/en/aloqa 144.1 KB 98
bash
git add -A
git commit

Commit (kanon): Perf: next-intl client qismi o'z Link/usePathname bilan almashtirildi (−12 KB), template animatsiyasi olib tashlandi (LCP).

10. Ko'p uchraydigan xatolar

Belgi Sabab Davosi
Build jadvalida "First Load JS" yo'q Next 16.4 uni olib tashlagan Brauzerda o'lchang yoki next analyze
Bitta Lighthouse o'lchovidan xulosa Natija har safar o'zgaradi 3+ o'lchov, mediana
LCP kechikdi, JS kichik opacity: 0 dan boshlanuvchi animatsiya LCP elementida opacity siz yoki LCP bo'lmagan elementga
Kutubxona brauzer JS'ini oshirdi, lekin faqat ma'lumotni o'zgartiradi U client komponentda Server Component'ga ko'chiring
Sahifa ochilganda o'nlab RSC so'rovi Prefetch — har ko'rinadigan <Link> Ko'p havolali ro'yxatda prefetch={false}
Qaytganda menyu ochiq qolgan <Activity> state'ni saqlagan Vaqtinchalik holatni effekt tozalashida yoping
useReportWebVitals ikki marta yuboradi Callback har render'da yangi Funksiyani komponentdan tashqarida e'lon qiling

11. Mashqlar

Mashqlar kurs/mashqlar/23/38-performance/ da. Jonli yechimlarni «Ishga tushir» bilan sinang.

1-mashq (oson): qaysi vosita?

  • Laboratoriyada Performance, LCP, TBT o'lchaydigan vosita —
  • Next 16.1+ dagi Turbopack bundle tahlilchisi buyrug'i — next
  • Komponent kodini kerak bo'lganda yuklaydigan Next API — next/
  • Havolani oldindan yuklamaslik — <Link prefetch={}>
  • Next eski sahifalarni yashirib saqlaydigan React komponenti —
Yechim
  • Lighthouse — mobil profil, taqlid qilingan sekin telefon.
  • analyze — --output bilan diskka yozadi.
  • dynamic — ichida React lazy + Suspense.
  • false — havola bosilgandagina yuklanadi.
  • Activity — ko'pi bilan 3 ta marshrut.

2-mashq (o'rta): «Yana ko'rsatish» kechiktirib

«Kod faqat kerak bo'lganda» blokidagi naqsh bilan Comments komponentini kechiktirib yuklang. Sahifada post sarlavhasi va «Izohlarni ochish» tugmasi bor. Bosilganda Suspense fallback'i «Izohlar yuklanmoqda…», keyin ikki izoh chiqsin. Yuklash 200 ms davom etsin (setTimeout bilan Promise). Konsolga yuklash boshlanganini yozing va oraliq holatni ekran(…) bilan tekshiring.

Yechim
tsx
import { lazy, Suspense, useState } from "react";

function Comments() {
  return (
    <ul>
      <li>Malika: Zo'r maqola!</li>
      <li>Bobur: Kodini GitHub'ga qo'ying</li>
    </ul>
  );
}

const LazyComments = lazy(() => {
  console.log("izohlar kodi yuklanmoqda");
  return new Promise<{ default: typeof Comments }>((resolve) =>
    setTimeout(() => resolve({ default: Comments }), 200),
  );
});

export default function App() {
  const [open, setOpen] = useState(false);
  return (
    <article>
      <h1>Portfolio v2: Next.js'ga ko'chish</h1>
      <button onClick={() => setOpen(true)}>Izohlarni ochish</button>
      {open && (
        <Suspense fallback={<p>Izohlar yuklanmoqda…</p>}>
          <LazyComments />
        </Suspense>
      )}
    </article>
  );
}

Konsolda:

text
izohlar kodi yuklanmoqda

Ekranda:

text
Portfolio v2: Next.js'ga ko'chish
Izohlarni ochish
Malika: Zo'r maqola!
Bobur: Kodini GitHub'ga qo'ying

ekran("Izohlar yuklanmoqda…") qadami oraliq holatni tasdiqlaydi: 200 ms davomida fallback ko'rindi. Next'da dynamic(() => import("./Comments"), { loading: … }) aynan shu xulqni beradi, faqat fallback loading parametrida yoziladi.

3-mashq (qiyin): JS byudjeti

Performance budget (tezlik byudjeti) — "bu sahifa X KB dan oshmasin" degan qoida. Funksiya yozing: checkBudget(pages, budgetKb) — har sahifa uchun "/yo'l: 149.6 KB — ok" yoki "/yo'l: 161.7 KB — +11.7 KB oshdi" qaytarsin; oxirida oshgan sahifalar sonini chiqaring. Kanon raqamlari bilan sinang: holat 34 (/ 161.7, /blog/portfolio-v2 156.8) va holat 38 (/ 149.6, /blog/portfolio-v2 144.7), byudjet 155 KB. Sonlarni toFixed(1) bilan yozing.

Yechim
js
function checkBudget(pages, budgetKb) {
  const lines = pages.map(({ path, kb }) => {
    const over = kb - budgetKb;
    const size = `${path}: ${kb.toFixed(1)} KB`;
    return over > 0
      ? `${size} — +${over.toFixed(1)} KB oshdi`
      : `${size} — ok`;
  });
  const failed = pages.filter(({ kb }) => kb > budgetKb).length;
  return { lines, failed };
}

const runs = {
  "holat 34": [
    { path: "/", kb: 161.7 },
    { path: "/blog/portfolio-v2", kb: 156.8 },
  ],
  "holat 38": [
    { path: "/", kb: 149.6 },
    { path: "/blog/portfolio-v2", kb: 144.7 },
  ],
};

for (const [name, pages] of Object.entries(runs)) {
  const { lines, failed } = checkBudget(pages, 155);
  console.log(`${name}: ${failed} ta sahifa oshdi`);
  for (const line of lines) console.log(`  ${line}`);
}

Konsolda:

text
holat 34: 2 ta sahifa oshdi
  /: 161.7 KB — +6.7 KB oshdi
  /blog/portfolio-v2: 156.8 KB — +1.8 KB oshdi
holat 38: 0 ta sahifa oshdi
  /: 149.6 KB — ok
  /blog/portfolio-v2: 144.7 KB — ok

Bunday tekshiruv CI'da har PR'da ishlaydi: kimdir og'ir kutubxona qo'shsa, PR qizil bo'ladi. Holat 34 da next-intl aynan shunday "qizil" bo'lardi — muammo kanon o'lchovida emas, byudjet qoidasida ham ko'rinardi. toFixed — son metodlari.

4-mashq: Portfolio qadami

O'z portfolio ingizni npm run build && npm run start qiling va Chrome DevTools → Lighthouse (Mobile, Performance) bilan bosh sahifani 3 marta o'lchang. LCP elementi qaysi? "LCP breakdown" da "Element render delay" qancha? Keyin kanon qadamini qiling: template.tsx animatsiyasini olib tashlang (yoki opacity ni olib tashlab, faqat translate qoldiring) va NextIntlClientProvider o'rniga o'z Link ingizni yozing. Qayta 3 marta o'lchang, farqni yozib qo'ying, commit qiling.

Yechim

Kutilgan yo'nalish (kanon raqamlari, sizniki biroz farq qiladi): Performance 93–96 → 97–98, LCP 2.7–3.2 → 2.4–2.6 s, render delay ~300 ms → ~90 ms. JS — DevTools → Network → "JS" filtri, "transferred" ustuni yig'indisi: ~161 → ~150 KB. Lighthouse'ni yashirin (inkognito) oynada ishga tushiring — brauzer kengaytmalari natijani buzadi. Natijalarni commit xabariga yoki README ga yozing: keyingi o'zgarishda solishtirish uchun.

12. Real ishda

  • Performance — mahsulot ko'rsatkichi. Do'konlarda sekin sahifa sotuvni kamaytiradi; Google qidiruvi Core Web Vitals'ni hisobga oladi. Katta jamoalarda JS byudjeti CI'da tekshiriladi.
  • "Use client" auditi — Next loyihasini tezlashtirishning birinchi qadami: qaysi komponent keraksiz client bo'lgan, qaysi kutubxona brauzerga tushib qolgan. next analyze aynan shu ish uchun.
  • Intervyu savollari: "LCP qanday qismlardan iborat?", "Next ilovasida JS'ni qanday kamaytirasiz?", "Prefetch'ning narxi nima?", "Lab va field ma'lumot farqi?".
  • O'lchov madaniyati — "bu tezroq" degan gapga "qancha va necha o'lchovda?" deb so'rash — tajribali muhandisning belgisi. Bu darsdagi uch variantli tajriba shu madaniyatning kichik namunasi.

Xulosa

  • Tezlik o'lchanadi: Lighthouse (lab, 3+ o'lchov) va useReportWebVitals (field); Next 16.4 build jadvalida JS hajmi yo'q.
  • portfolio JS'ining ~132 KB i — React va Next; sizning dastagingiz — client chegarasini kichik saqlash va og'ir ishni serverda qilish.
  • next-intl client qismi o'rniga o'z Link — 161.7 → 149.6 KB; next analyze og'ir modulni topadi.
  • next/dynamic (lazy) — darhol kerak bo'lmagan katta komponentlar uchun; prefetch va <Activity> tezlik beradi, lekin trafik va xotira narxi bor.
  • opacity: 0 dan boshlanadigan animatsiya LCP'ni ~230 ms kechiktiradi; faqat translate — kechiktirmaydi (biz o'lchadik).

Keyingi dars: Runtime'lar: Node va Edge — Next server kodi qayerda ishlaydi, nega Next 16 hujjati Edge'ni "eskirgan" deydi va serverless'da bazaga ulanish muammosi.

Manbalar

  • Next.js hujjati — Package Bundling (next analyze, @next/bundle-analyzer): https://nextjs.org/docs/app/guides/package-bundling (16.4.0 bilan kelgan nusxa, 2026-10-21 da o'qildi)
  • Next.js hujjati — Lazy Loading (next/dynamic), useReportWebVitals, Prefetching, Preserving UI state (Activity, 3 ta marshrut): https://nextjs.org/docs/app/guides
  • web.dev — Optimize LCP (LCP qismlari): https://web.dev/articles/optimize-lcp
  • Kanon: portfolio v2, holat 37/38 Lighthouse va JS o'lchovlari, prefetch o'lchovi; next analyze --output va animatsiyaning uch varianti — biz ishga tushirdik (next 16.4.0, Lighthouse 13.5.0 mobil, Chrome 155).
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Next.js performance: Lighthouse, brauzer yuklagan JS va client chegarasi — IlmHamroh