IlmHamroh
JavaScript Full-stack/23-qism. Next.js43/43-dars19 daqiqa
Mundarija (33)

Yakuniy Next.js loyiha: portfolio v2 — arxitektura, tanlovlar va natija

Qisqacha: portfolio v2 — 23-qismning hamma darsi bitta real loyihada: Server Components, Server Actions, Route Handler, proxy.ts, Cache Components, next-intl, SEO, CSP, testlar. 20 bosqich (commit), 63 ta oldindan tayyorlangan sahifa, faqat bitta dinamik API manzili. Yakuniy natija: Lighthouse mobil 97–98 / 100 / 100, axe 0, hydration ogohlantirishi 0, Vitest 10, Playwright 15, brauzer JS 144–155 KB gzip. Har texnologiya o'lchab tanlangan, kirmaganlari ham sababi bilan yozilgan. Oxirgi qadam — README va AGENTS.md: loyihani boshqa odam (yoki AI agent) to'g'ri davom ettira olishi uchun.

Bu darsda

  • portfolio v2 ning arxitektura qatlamlarini chizib, har faylning o'rnini tushuntira olasiz.
  • Har texnologiya tanlovini (kirgan va kirmagan) narxi va sababi bilan himoya qilasiz.
  • 20 bosqichli qurilish yo'lini va har bosqichda nima tekshirilganini ko'rasiz.
  • Yakuniy sifat ko'rsatkichlarini o'qiysiz va 14 ta haqiqiy topilmadan saboq olasiz.
  • README va AGENTS.md yozasiz va loyihani portfolio'ga tayyorlaysiz.

Oldin bilishingiz kerak: 23-qismning hamma darslari, ayniqsa Next.js nima, Server va Client kompozitsiyasi, Next.js performance, Next.js ilovani test qilish.

1. Nega bu kerak?

Kursning 04–09-qismlarida Aziz birinchi saytini qurdi: besh sahifa HTML, CSS va kichik asosiy.js. U GitHub Pages'da turibdi. 23-qism davomida o'sha saytni Next.js'da qaytadan qurdik — dizayn va mazmun o'sha, lekin ichi butunlay boshqa.

Yakuniy loyiha darsi yangi texnologiya o'rgatmaydi. U boshqa savolga javob beradi: "bularning hammasi birga qanday ishlaydi va nima uchun aynan shunday?". Ish beruvchi portfolio'ga qaraganda ham shuni so'raydi: "Nega Next? Nega Tailwind emas? Lighthouse necha? Testlar bormi?".

O'xshatish: uy qurib bo'lindi. Endi uning pasporti kerak — chizmalar, qaysi material nega tanlangani, sinov natijalari. Pasportsiz uy ham turadi, lekin uni sotish, ta'mirlash yoki kengaytirish qiyin.

2. Loyiha rejasi

2.1 Nima qurildi

Sahifa Nima bor Render
/ bosh sahifa kirish, so'nggi loyihalar, JSON-LD ○
/loyihalar, /loyihalar/[slug] teg filtri (URL'da), case study, rasm modal'da ○ (+◐ qobiq)
/blog, /blog/[slug] Markdown postlar, ulashish tugmasi, RSS ○, 30 kun kesh
/haqimda GitHub profili (kalitsiz API, zaxira bilan) ○, 1 soat kesh
/aloqa Server Action forma, JS'siz ham ishlaydi ○
/en/... hamma sahifaning inglizcha nusxasi ○
/api/qayta-yangila sirli kesh tozalash ƒ

2.2 Talablar (boshidanoq)

Kanon loyihani boshlashdan oldin talablarni yozdi va har bosqichda ularni tekshirdi:

  • JS'siz ishlaydi: matn, havolalar, forma — v1 dagi progressive enhancement saqlanadi.
  • Ochiq va tez: sahifalar statik, Lighthouse mobil 95+.
  • Hamma uchun: axe 0 buzilish, klaviatura, ekran o'quvchi.
  • Ikki til: uz (prefikssiz) va /en.
  • Halol: tashqi hisob, kalit, pullik xizmat yo'q — hammasi lokal o'lchanadi.

3. Arxitektura

3.1 Qatlamlar

flowchart TB
  R["so'rov"] --> PX["proxy.ts<br/>noma'lum slug → 404, til"]
  PX --> APP["app/[locale]/…<br/>sahifa va layout'lar"]
  APP --> SC["Server Components"]
  APP --> CC["client orollar<br/>filtr, tema, forma"]
  SC --> DAL["malumot/dal.ts<br/>server-only, cache()"]
  CC -->|"Server Action"| ACT["aloqa/_amal"]
  DAL --> SRC["Markdown fayllar,<br/>GitHub API, env.ts"]
  ACT --> LOG["log (instrumentation)"]

Yuqoridan pastga — so'rovning yo'li. Uch narsaga qarang. Birinchisi: ma'lumot faqat bitta joydan — DAL orqali olinadi (Data Access Layer); sahifalar fayl yoki API bilan to'g'ridan gaplashmaydi. Ikkinchisi: client qismlar — kichik orollar; ular serverga faqat Server Action orqali murojaat qiladi. Uchinchisi: env faqat env.ts da (Env).

3.2 Papkalar

README'dagi tuzilma (kanon):

text
src/app/[locale]/        root layout (til URL'da), not-found, error
src/app/[locale]/(sayt)/ sahifalar: bosh, haqimda, loyihalar, blog, aloqa
src/app/                 sitemap, robots, manifest, OG, rss, api, global-error
src/blog/*.md            blog postlari
src/malumot/             ma'lumot, DAL, GitHub, tezlik cheklovi
src/i18n/ messages/      next-intl (serverda)
src/proxy.ts             noma'lum slug → 404, til yo'naltirish
tekshiruv/ e2e/          Vitest va Playwright testlari

Kanondagi qatorlar telefonga sig'ishi uchun qisqartirildi. Qoidalar: (sayt) — route group (Route groups), _komponentlar va _amal — private papkalar (marshrut emas), har bo'lim o'z komponentlarini yonida saqlaydi.

4. Texnologiya tanlovlari va narxi

4.1 Kirganlar

Paket Versiya Nega
next, react 16.4.0, 19.3.0 Asos
next-intl 4.14.9 Tarjima serverda; client qismi o'rniga o'z Link (−12 KB)
zod 4.6.7 Forma va env tekshiruvi — bitta sxema ikki joyda
marked 18.1.1 Markdown → HTML serverda, brauzerga 0 KB
server-only 0.0.1 Sir va server modullari himoyasi

Hammasi --save-exact, va 7 kundan eski versiyalar (yangi versiyani darhol olmaslik — ta'minot zanjiri xavfsizligi, 16-qism).

4.2 Kirmaganlar — o'lchov bilan

Nima O'lchov Nega kirmadi
Tailwind node_modules +18 MB v1 dizayni CSS tokenlarda tayyor (Stil va tema)
@next/mdx 9.8 MB, 104 paket marked — 540 KB, postlar oddiy Markdown
gray-matter oxirgi reliz 2021 Faol emas; frontmatter o'zimiz o'qiymiz
TanStack Query — Client'da server holati yo'q (TanStack Query)
useOptimistic — JS'siz formani buzadi
next-themes — useSyncExternalStore + kichik skript yetdi
NextIntlClientProvider +14.3 KB Client'da tarjima kerak emas
template animatsiyasi LCP +0.5 s Performance o'lchovi
nonce CSP, SRI, Trusted Types hamma sahifa ƒ / 66 buzilish next.config tajribasi
Edge, standalone, next/font/google build xatosi / ortiqcha / tarmoq Runtime'lar, Deploy

Bu jadval — loyihaning eng qimmatli qismi. Ish beruvchi "nega X ishlatmadingiz?" deb so'rasa, javob "bilmayman" emas, raqam.

Tekshirib ko'ring: Nega marked qo'shildi-yu, next-intl ning client qismi olib tashlandi? Ikkalasi ham kutubxona-ku.

Javob

marked serverda ishlaydi — brauzerga 0 KB qo'shadi, foyda esa katta (Markdown postlar). next-intl'ning client qismi brauzerga 14.3 KB olib kelardi, lekin brauzerda faqat /en prefiksi kerak edi — o'z kichik Link imiz bilan almashtirildi. Savol "kutubxona yaxshimi?" emas, "u qayerda ishlaydi va qancha turadi?".

4.3 JS'ning yo'li

Brauzer yuklagan JS (bosh sahifa, gzip) bosqichma-bosqich o'sdi. Bo'sh skelet 132.4 → v1 sahifalari 135.4 → client komponentlar 137.4 → modal va next/image 143.4 → tema 143.9 → forma 145.6 → metadata 146.5 → next-intl 161.7 → o'z Link bilan 149.6 KB.

Yakuniy holat: brauzer yuklagan JS (gzip)
  • bo'sh Next skeleti132,4 KB
  • /haqimda, /aloqa144,1 KB
  • /blog144,7 KB
  • /, /loyihalar149,6 KB
  • /loyihalar/vazifalarnext/image155,3 KB

Manba: IlmHamroh kanoni, portfolio v2 holat 43, Chrome 155, 2026-10-21

Halol xulosa: v1 bilan solishtirganda Next'ning o'zi ~132 KB qo'shdi. Buning evaziga: HTML serverda tayyor, JS'siz forma va kontent ishlaydi, TTFB 4–12 ms, ikki til, kesh, testlar. Butun portfolio funksionalligi esa skelet ustiga atigi 12–23 KB.

5. Bosqichma-bosqich qurish

5.1 20 commit

Kanon loyihani 20 bosqichda qurdi. Har bosqich — bitta yoki bir nechta dars, bitta commit:

Darslar Commit (kanon xabari, qisqartirilgan)
#02 Next: create-next-app 16.4.0 skeleti, versiyalar qotirildi
#03–#04 Sahifalar; umumiy layout va template
#05–#06 not-found, error, loading; joriy havola, teg filtri URL'da
#07–#08 (sayt) guruhi; loyiha rasmi modal'da
#09–#11 Blog: Markdown serverda; Ulashish — client orol
#12–#13 Tema: TemaProvider, bo'yashdan oldingi skript
#14–#16 Haqimda: GitHub profili serverda, Suspense oqimi
#17–#19 Kesh: "use cache", cacheTag; /api/qayta-yangila
#20 DAL: server-only, cache(), DTO
#21–#23 Aloqa: Server Action, Zod, asal idish, tezlik cheklovi
#24 RSS — Route Handler
#26–#27 Proxy: noma'lum slug → 404; after() loglari
#29–#30 SEO: metadata, sitemap, OG rasmlar, JSON-LD
#31–#32 Rubik next/font/local, LCP rasmiga preload
#33 Stil: CSS Module
#34 i18n: next-intl, hreflang
#35–#37 instrumentation, CSP, redirect'lar, env Zod
#38 Perf: o'z Link (−12 KB), animatsiya olib tashlandi
#41 Test: Vitest + Playwright + axe
#43 Docs: README va AGENTS.md

Har commit'dan oldin bir xil tekshiruv: lint, tur, format, build, testlar, keyin next start ustida har sahifa — status, TTFB, JS, axe, hydration. Shuning uchun xato o'sha bosqichning o'zida ushlangan, oxirida "hammasi buzildi" bo'lmagan.

Tekshirib ko'ring: Nega #43 dagi commit faqat hujjat (README, AGENTS.md), kod esa holat 41 bilan bir xil?

Javob

Kod #41 da tayyor va testlar bilan himoyalangan edi. Hujjatni alohida commit qilish tarixni toza qiladi: kim git log ga qarasa, "bu commit hech narsani buzmaydi" deb biladi. Aralash commit (kod + hujjat) qaytarish va sharhlashni qiyinlashtiradi.

5.2 14 ta haqiqiy topilma

Qurilish davomida kanon 14 ta kutilmagan narsani topdi — hujjatda yo'q yoki hujjatdan farqli. Ular tegishli darslarda batafsil:

Topilma Dars
Cache Components build'ni "uncached data" bilan to'xtatadi Serverda ma'lumot olish, Streaming
Noma'lum slug birinchi so'rovda 200 (keyin 404) → proxy bilan tuzatildi Maxsus fayllar, proxy.ts
Proxy matcher .png ni ushlagan next/font
Hydration: matn farqi daraxtni qayta yaratadi, checked jim Hydration
try/catch prerender rad etishini yutadi → connection() Streaming
Sahifa openGraph i layout'nikini to'liq almashtiradi Metadata API
<Link locale> ikki header chizadi next-intl
OG rasmda "use cache" — Uint8Array/DataView muammosi SEO fayllari
SRI qat'iy CSP bilan hydration'ni o'ldiradi (66 buzilish) next.config
Trusted Types client navigatsiyani buzadi next.config
SAYT_URL build vaqtida yoziladi Env
Vitest async RSC'ni chiza olmaydi Test
pages/ papkasi hook turlarini | null qiladi Yangilash
axe peer playwright-core 1.64.1 — ikki nusxa, build yiqildi Test

Bu darslarni yozishda biz yana bir nechtasini topdik, ular ham "biz ishga tushirdik" deb belgilangan. Ro'yxat: typedRoutes [locale] bilan deyarli hech narsani tekshirmaydi (next.config), server-only xatosida chalg'ituvchi "Pages Router" matni (Env), faqat translate li animatsiya LCP'ni kechiktirmaydi (Performance), yuk ostida modal e2e testi beqaror (Test).

6. Jonli: loyihaning yuragi — aloqa formasi

Kanondagi AloqaFormasi ning soddalashtirilgan modeli. Haqiqiy loyihada send — Server Action (serverda Zod tekshiruvi, asal idish, tezlik cheklovi). Natija oynasida server yo'q, shuning uchun u oddiy async funksiya. useActionState va forma esa — aynan React'ning o'zi:

tsx
import { useActionState } from "react";

type State =
  | { status: "idle" }
  | { status: "error"; message: string }
  | { status: "sent"; name: string };

// Haqiqiy loyihada — "use server" fayldagi Server Action
async function send(_prev: State, form: FormData): Promise<State> {
  const name = String(form.get("ism") ?? "").trim();
  console.log(`server: ism="${name}"`);
  if (name.length < 2) {
    return { status: "error", message: "Ismingizni yozing" };
  }
  return { status: "sent", name };
}

export default function ContactForm() {
  const [state, action] = useActionState(send, { status: "idle" });
  if (state.status === "sent") {
    return <p role="status">Rahmat, {state.name}!</p>;
  }
  return (
    <form action={action}>
      <label htmlFor="ism">Ismingiz</label>
      <input id="ism" name="ism" />
      {state.status === "error" && (
        <p role="alert">{state.message}</p>
      )}
      <button type="submit">Yuborish</button>
    </form>
  );
}

Konsolda:

text
server: ism=""
server: ism="Malika"

Ekranda:

text
Rahmat, Malika!

Birinchi bosish — bo'sh ism, "server" xato qaytardi va forma xabar bilan qoldi. Ikkinchisi — muvaffaqiyat. Haqiqiy portfolio da bu oqim JS o'chiq bo'lsa ham ishlaydi (Playwright testi buni har safar tekshiradi), chunki <form action> — oddiy HTML forma ham (Server Actions I).

7. Sifat: yakuniy tekshiruv

7.1 Raqamlar (holat 43)

Tekshiruv Natija
lint / tur / format 0 / 0 / 0 (3 s, 3 s, 1 s)
build 11 s, 63 sahifa prerender
Vitest 10/10
Playwright 15/15, yana 3 marta 15/15 (8.5–8.7 s, flaky 0)
13 sahifa (uz/en, filtr, modal, 404) axe 0, hydration 0, TTFB 4–12 ms
Regressiya ssenariylari 9/9 (filtr, modal, tema, forma, RSS, CSP, i18n, SEO, rasm)

7.2 Lighthouse (mobil, 7 sahifa)

text
/: perf 98, acce 100, best 100, seo 92 | FCP 0.8 s, LCP 2.4 s, TBT 40 ms, CLS 0, SI 0.8 s
/en: perf 98, acce 100, best 100, seo 92 | FCP 0.8 s, LCP 2.4 s, TBT 60 ms, CLS 0, SI 0.8 s
/haqimda: perf 98, acce 100, best 100, seo 92 | FCP 0.8 s, LCP 2.4 s, TBT 40 ms, CLS 0, SI 0.8 s
/loyihalar: perf 98, acce 100, best 100, seo 92 | FCP 0.9 s, LCP 2.4 s, TBT 40 ms, CLS 0, SI 0.9 s
/loyihalar/vazifalar: perf 97, acce 100, best 100, seo 92 | FCP 0.8 s, LCP 2.6 s, TBT 40 ms, CLS 0, SI 0.8 s
/blog/portfolio-v2: perf 98, acce 100, best 100, seo 92 | FCP 0.8 s, LCP 2.4 s, TBT 40 ms, CLS 0, SI 0.8 s
/aloqa: perf 98, acce 100, best 100, seo 92 | FCP 0.8 s, LCP 2.4 s, TBT 50 ms, CLS 0, SI 0.8 s
Lighthouse 13.5.0, Chrome 155.0.8059.85, mobil

SEO 92 — faqat canonical example.com ga ko'rsatgani uchun (lokal o'lchov); to'g'ri SAYT_URL bilan 100 (Performance). Bu yerda "ataylab 100 qilish" emas, sababni bilish muhim.

7.3 Ochiq qolganlar (halol)

Loyiha "mukammal" emas — va buni yozish ham ishning bir qismi:

  • Aloqa xabari hozircha faqat logga yoziladi — qayerga yuborish (email, Telegram) backend qismlarida.
  • Tezlik cheklovi xotirada — ko'p instansiyada teshik (Deploy I: Vercel).
  • /en da loyiha va blog matni o'zbekcha (lang="uz" belgisi bilan) — tarjima sizning mashqingiz.
  • CSP'da 'unsafe-inline' — o'lchangan murosa.
  • Build'da metadataBase ogohlantirishi (Next'ning ichki /_not-found) — ta'siri yo'q.

8. README va AGENTS.md

8.1 README

Kanon README'si besh bo'lim: nima bu loyiha, buyruqlar, tuzilma, sozlash (.env.example, SAYT_URL build vaqtida yozilishi), deploy (Vercel va o'z server) va shrift litsenziyasi. Buyruqlar qismi:

bash
npm install
npm run dev          # http://localhost:3000
npm run check        # lint + tip + format:check + test (Vitest)
npm run build        # production build (route jadvali)
npm start            # production server
npm run test:e2e     # Playwright (avval npm run build)

README — loyihaning birinchi sahifasi. GitHub'da repoga kirgan ish beruvchi avval shuni o'qiydi.

8.2 AGENTS.md

Loyiha yaratish darsida AGENTS.md ni ko'rgandingiz — AI kod yordamchilari uchun qo'llanma. Next 16 uning boshiga rasmiy blok qo'yadi: "bu siz bilgan Next.js emas, node_modules/next/dist/docs/ dagi hujjatni o'qing". Kanon uning ostiga loyiha qoidalarini qo'shdi:

text
- Komponentlar sukut bo'yicha Server Component; "use client" faqat
  holat/hodisa/brauzer API kerak bo'lgan barg komponentda.
- Ichki havolalar — @/i18n/navigation dagi Link.
- Fayl/tarmoq o'qish: "use cache" + cacheLife yoki <Suspense>;
  argumentsiz new Date() — build xatosi.
- Env faqat src/env.ts orqali (Zod).
- O'zgarishdan keyin: npm run check, npm run build, npm run test:e2e.

Kanondan tanlangan qoidalar, qatorlar telefonga sig'ishi uchun bo'lingan. Bu qoidalar — butun qism davomida topilgan saboqlarning qisqa ko'rinishi. Ular faqat AI uchun emas: jamoaga qo'shilgan yangi dasturchi ham aynan shu ro'yxatdan boshlaydi.

8.3 Commit

bash
git add -A
git commit

Commit (kanon): Docs: README (tuzilma, sozlash, deploy) va AGENTS.md loyiha qoidalari. Kod holat 41 bilan bir xil — bu commit faqat hujjat.

9. Ko'p uchraydigan xatolar

Belgi Sabab Davosi
Loyiha oxirida "hammasi buzildi" Tekshiruv faqat oxirida Har commit'dan oldin npm run check + build
"Nega X ishlatmadingiz?" ga javob yo'q Tanlovlar yozilmagan Kirgan/kirmagan jadvali, raqam bilan
README faqat create-next-app matni Hujjat yangilanmagan Buyruqlar, tuzilma, env, deploy
Hamma komponent "use client" SPA odati Sukut — Server Component, client — barg
Lighthouse 100 uchun ma'nosiz o'zgarish Raqam maqsadga aylangan Har yo'qotilgan ball sababini biling
Portfolio'da faqat havola Loyiha hikoyasi yo'q Case study: muammo, qaror, natija, raqam

10. Mashqlar

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

1-mashq (oson): qatlamlar

  • Sahifalar ma'lumotni qaysi qatlamdan oladi —
  • Noma'lum slug'ni 404 ga yuboradigan fayl — .ts
  • Env qaysi faylda o'qiladi — src/.ts
  • Markdown qayerda HTML'ga aylanadi —
  • Faqat bitta dinamik (ƒ) manzil — /api/
Yechim
  • DAL — malumot/dal.ts, server-only va cache() bilan.
  • proxy — Next 16 da middleware o'rnida.
  • env — Zod bilan, server-only.
  • serverda — marked brauzerga 0 KB qo'shadi.
  • qayta-yangila — sirli kesh tozalash; qolgan hammasi ○.

2-mashq (o'rta): forma email bilan

«Aloqa formasi» blokiga email maydonini qo'shing (<label> bilan). "Server" ikkala maydonni tekshirsin: ism kamida 2 belgi, email @ belgisini o'z ichiga olsin. Xato bo'lsa — hamma xatolar bitta role="alert" ichida ; bilan. Sinang: avval faqat ism bilan yuboring, keyin email ham yozing.

Yechim
tsx
import { useActionState } from "react";

type State =
  | { status: "idle" }
  | { status: "error"; errors: string[] }
  | { status: "sent"; name: string };

async function send(_prev: State, form: FormData): Promise<State> {
  const name = String(form.get("ism") ?? "").trim();
  const email = String(form.get("email") ?? "").trim();
  const errors: string[] = [];
  if (name.length < 2) errors.push("Ismingizni yozing");
  if (!email.includes("@")) errors.push("Email noto'g'ri");
  console.log(`server: ${errors.length} ta xato`);
  if (errors.length) return { status: "error", errors };
  return { status: "sent", name };
}

export default function ContactForm() {
  const [state, action] = useActionState(send, { status: "idle" });
  if (state.status === "sent") {
    return <p role="status">Rahmat, {state.name}!</p>;
  }
  return (
    <form action={action}>
      <label htmlFor="ism">Ismingiz</label>
      <input id="ism" name="ism" />
      <label htmlFor="email">Email</label>
      <input id="email" name="email" type="email" />
      {state.status === "error" && (
        <p role="alert">{state.errors.join("; ")}</p>
      )}
      <button type="submit">Yuborish</button>
    </form>
  );
}

Konsolda:

text
server: 1 ta xato
server: 0 ta xato

Ekranda:

text
Rahmat, Malika!

Harakat qatoriga qarang: ikkinchi yuborishdan oldin ism qayta yozildi. Sababi — React 19: <form action={…}> bilan yuborilgan forma action tugagach o'z maydonlarini avtomatik tozalaydi. Biz avval ismni qayta yozmasdan sinab ko'rdik — natija ikki marta "1 ta xato" bo'ldi: email kiritildi, ism esa bo'sh qolgan edi. Foydalanuvchi uchun bu yoqimsiz: xato chiqdi va yozganlari yo'qoldi. Kanon formasi buni hal qilgan — xato holatida server yuborilgan qiymatlarni qaytaradi (qiymatlar), maydonlar esa ularni defaultValue bilan qayta oladi (Server Actions II).

3-mashq (qiyin): tanlov hisoblagichi

Har texnologiya tanlovini qoida bilan baholaydigan funksiya yozing: decide(option, budgetKb). option — { name, clientKb, benefit }, benefit — "zarur", "foydali" yoki "bezak". Qoida: zarur — doim qabul; foydali — clientKb byudjetga sig'sa qabul; bezak — faqat clientKb === 0 bo'lsa. Har qaror sababi bilan chiqsin. Byudjet — qolgan 10 KB. Kanon raqamlari bilan sinang: marked (0 KB, foydali), next-intl client (14.3 KB, foydali), modal (5.9 KB, foydali), template animatsiyasi (0 KB JS, lekin bezak), React (73.3 KB, zarur).

Yechim
js
function decide({ name, clientKb, benefit }, budgetKb) {
  if (benefit === "zarur") return `${name}: qabul (zarur)`;
  if (benefit === "foydali") {
    return clientKb <= budgetKb
      ? `${name}: qabul (${clientKb} KB sig'adi)`
      : `${name}: rad (${clientKb} KB > ${budgetKb} KB)`;
  }
  return clientKb === 0
    ? `${name}: qabul, lekin o'lchang (bezak)`
    : `${name}: rad (bezak)`;
}

const options = [
  { name: "marked", clientKb: 0, benefit: "foydali" },
  { name: "next-intl client", clientKb: 14.3, benefit: "foydali" },
  { name: "modal", clientKb: 5.9, benefit: "foydali" },
  { name: "template animatsiyasi", clientKb: 0, benefit: "bezak" },
  { name: "react-dom", clientKb: 73.3, benefit: "zarur" },
];
for (const o of options) console.log(decide(o, 10));

Konsolda:

text
marked: qabul (0 KB sig'adi)
next-intl client: rad (14.3 KB > 10 KB)
modal: qabul (5.9 KB sig'adi)
template animatsiyasi: qabul, lekin o'lchang (bezak)
react-dom: qabul (zarur)

To'rtinchi qator — eng qiziq: animatsiya JS qo'shmaydi, shuning uchun JS byudjeti uni o'tkazdi. Lekin uning narxi boshqa joyda — LCP'da (Performance). Bitta raqam (KB) hamma narxni ko'rsatmaydi; shuning uchun kanon JS ham, Lighthouse ham o'lchadi.

4-mashq: Portfolio qadami — yakun

  1. README.md ni yozing: nima bu, buyruqlar, tuzilma, sozlash, deploy.
  2. AGENTS.md ga o'z loyiha qoidalaringizni qo'shing (rasmiy blok ostida).
  3. Yakuniy tekshiruv: npm run check, npm run build, npm run test:e2e (3 marta), Lighthouse mobil 3 ta sahifada.
  4. "Kirgan va kirmagan texnologiyalar" jadvalini o'zingiz uchun to'ldiring.
  5. Commit, keyin Vercel'ga deploy (Deploy I) va manzilni README'ga yozing.
  6. vazifalar loyihasi uchun case study yozing — portfolio'dagi birinchi postingiz.
Yechim

Namuna — kanon README va AGENTS.md (yuqorida). Case study besh qismdan iborat. (1) Muammo — nima uchun bu ilova. (2) Texnologiyalar va nega. (3) Eng qiyin joy va qanday hal qilingan (masalan 22-qismda vizual test topgan «Qayta urinish» tugmasi xatosi). (4) Raqamlar — testlar soni, Lighthouse, bundle hajmi. (5) Nimani boshqacha qilardingiz. Raqamsiz case study — reklama; raqamli — muhandislik hujjati. Yakuniy tekshiruvdagi har ogohlantirishni README'ning "Ma'lum cheklovlar" bo'limiga yozing.

11. Real ishda

  • Portfolio — ishga kirish hujjati. Junior vakansiyada ish beruvchi ko'pincha bitta loyihani chuqur ko'radi: kod tuzilmasi, commit tarixi, README, testlar. portfolio v2 aynan shunday loyiha: 20 ma'noli commit, testlar, o'lchangan raqamlar.
  • Texnik intervyu "loyihangiz haqida gapirib bering" bilan boshlanadi. Tanlovlar jadvali va 14 topilma — tayyor hikoyalar: "Biz SRI'ni sinadik, hydration o'ldi, shuning uchun…".
  • ADR (Architecture Decision Record — arxitektura qarori yozuvi) — katta jamoalarda har muhim tanlov shunday hujjatlanadi. Bu darsdagi jadval — uning kichik ko'rinishi; arxitektura qismida batafsil.
  • Davomi: 39-qismda portfolio'ga yana case study'lar va CV qo'shiladi; backend qismlaridan keyin aloqa formasi haqiqiy manzilga xabar yuboradi.

Xulosa

  • portfolio v2 — 23-qismning hamma g'oyasi bitta loyihada: 63 statik sahifa, bitta ƒ API, ikki til, JS'siz ishlaydigan forma.
  • Arxitektura: proxy → sahifalar → Server Components va client orollar → DAL → manbalar; env faqat env.ts.
  • Har tanlov o'lchangan: kirmaganlar (Tailwind, MDX, nonce CSP, Edge…) ham sababi va raqami bilan yozilgan.
  • Natija: Lighthouse 97–98 / 100 / 100, axe 0, hydration 0, Vitest 10, Playwright 15, JS 144–155 KB.
  • 20 commit, har biridan oldin bir xil tekshiruv; 14 haqiqiy topilma darslarda saboqqa aylangan.
  • README va AGENTS.md — loyihani boshqalar (va siz o'zingiz, bir yildan keyin) davom ettira olishi uchun.

Keyingi dars: Node.js nima: runtime, V8 va libuv — 24-qism: endi server tomoniga to'liq o'tamiz. Next ichida ko'rgan node:fs, jarayon va oqimlarni o'zi alohida o'rganamiz.

Manbalar

  • Next.js hujjati (16.4.0 bilan kelgan nusxa, node_modules/next/dist/docs/), 2026-10-21 da o'qildi: https://nextjs.org/docs
  • Kanon: portfolio v2 (holat 43) — README, AGENTS.md, package.json; yakuniy tekshiruv, Lighthouse 13.5.0 (7 sahifa, mobil), e2e 3 marta, regressiya ssenariylari (2026-10-21); kurs qarorlari (CSP V1, next-intl serverda, /en matni, animatsiya "narxi").
  • Bu qism darslarida biz qo'shimcha ishga tushirgan tajribalar: typedRoutes, NEXT_PUBLIC_ inlining, .env tartibi, server-only xatosi, animatsiya uch varianti, codemod, e2e takrorlari (next 16.4.0, Node 24.21.0, Chrome 155).
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Yakuniy Next.js loyiha: portfolio v2 — arxitektura, tanlovlar va natija — IlmHamroh