IlmHamroh
JavaScript Full-stack/23-qism. Next.js7/43-dars15 daqiqa
Mundarija (29)

Next.js route groups va private papkalar: (guruh), _papka va loyiha tashkili

Qisqacha: Qavs ichidagi papka — route group ((sayt)) — URL'ga kirmaydi: app/(sayt)/haqimda/page.tsx baribir /haqimda. U sahifalarni guruhlash va guruhga o'z layout'ini berish uchun kerak. Pastki chiziq bilan boshlangan papka — private papka (_komponentlar) — routing'dan butunlay chiqariladi: ichidagi hech bir fayl sahifa bo'lmaydi. Ikkalasi ham URL'ga tegmasdan app/ ni tartibga soladi. Ikki guruhda bir xil manzil bo'lsa — build xatosi.

Bu darsda

  • (guruh) papka yaratasiz va URL o'zgarmaganini build jadvali bilan tasdiqlaysiz.
  • Guruhga layout yoki template berib, uni faqat bir qism sahifalarga qo'llaysiz.
  • _papka va oddiy colocation farqini tushuntirasiz.
  • Bir nechta root layout qachon kerakligini va narxini bilasiz.
  • portfolio ni kanondagi tuzilmaga keltirasiz: (sayt) guruhi va loyihalar/_komponentlar/.

Oldin bilishingiz kerak: Navigatsiya, Layout va template, Maxsus fayllar, Fayl-asosli routing.

1. Nega bu kerak?

Holat 06 dagi app/ papkasiga qarang:

text
src/app/
├── aloqa/page.tsx
├── haqimda/page.tsx
├── loyihalar/
│   ├── [slug]/loading.tsx
│   ├── [slug]/page.tsx
│   └── page.tsx
├── error.tsx
├── global-error.tsx
├── globals.css
├── icon.svg
├── layout.tsx
├── not-found.tsx
├── page.tsx
└── template.tsx

Ikki xil narsa aralashib ketgan: sahifalar (aloqa, haqimda, page.tsx) va butun ilovaga tegishli fayllar (not-found, global-error, icon.svg). Keyingi darslarda bu ro'yxatga sitemap.ts, robots.ts, opengraph-image.tsx qo'shiladi — tartib yanada buziladi.

Ikkinchi muammo — template.tsx. U Layout va template darsidagi kirish animatsiyasini beradi. Lekin root'da turgani uchun 404 sahifasi ham "uchib kiradi". Xato sahifasiga animatsiya kerakmi? Kanon "yo'q" dedi. Sayt sahifalariga — ha, xizmat sahifalariga — yo'q. Buning uchun sahifalarni bir guruhga ajratib, template'ni faqat o'sha guruhga berish kerak.

Uchinchisi — komponentlar. LoyihaKartasi va TegFiltri faqat «Loyihalar» bo'limida ishlatiladi, lekin umumiy src/komponentlar/ da yotibdi — header bilan yonma-yon.

Papka qo'shsak, URL o'zgaradi: app/sayt/haqimda/ — bu /sayt/haqimda. Bizga esa URL'ga tegmaydigan papka kerak.

Hayotiy o'xshatish: kitob javoni. Kitoblarni rangli qutilarga solib, "badiiy", "darslik" deb belgiladingiz. Kitobning nomi (URL) o'zgarmadi — faqat siz uni topishingiz osonlashdi. Qutining yorlig'i kitob muqovasiga yozilmaydi.

2. Route groups: (guruh)

2.1 Qavs — URL'dan tashqarida

Papka nomini qavsga olsangiz, Next.js uni URL'ga qo'shmaydi. Bu — route group (marshrut guruhi). Kanon sahifalarni app/(sayt)/ ga ko'chirdi:

flowchart LR
  A["app/(sayt)/page.tsx"] --> U1["/"]
  B["app/(sayt)/haqimda/page.tsx"] --> U2["/haqimda"]
  C["app/(sayt)/loyihalar/page.tsx"] --> U3["/loyihalar"]
  D["app/not-found.tsx"] --> U4["404 sahifasi"]

URL'lar — avvalgidek. Kanon buni build jadvali bilan tasdiqladi: holat 06 va holat 08 jadvallarida /, /aloqa, /haqimda, /loyihalar qatorlari bir xil, (sayt) so'zi jadvalda umuman yo'q.

Biz ham tekshirdik — holat 08 ni next build + next start, keyin curl:

text
/haqimda -> 200 h1: Men haqimda
/(sayt)/haqimda -> 404 h1: Sahifa topilmadi

Guruh nomi bilan manzil yozilsa — 404. Qavs URL'da hech qachon ko'rinmaydi.

2.2 Guruhning o'z layout'i va template'i

Guruh papkasiga ham layout.tsx yoki template.tsx qo'yish mumkin. U faqat shu guruhdagi sahifalarni o'raydi. Kanon template.tsx ni (sayt) ga ko'chirdi:

text
src/app/
├── (sayt)/
│   ├── template.tsx      ← faqat sayt sahifalari
│   ├── page.tsx
│   ├── haqimda/  aloqa/  loyihalar/
├── layout.tsx            ← hammasi
├── not-found.tsx         ← template'siz
├── error.tsx
└── global-error.tsx

Endi kirish animatsiyasi faqat sayt sahifalarida. not-found.tsx va error.tsx root darajada qoldi — ularni template o'ramaydi.

Bu naqshning nomi hujjatda: "opting segments into a layout" — ba'zi segmentlarni layout'ga "yozdirish", qolganlarini tashqarida qoldirish. Masalan, onlayn do'konda (dokon)/ dagi sahifalarda savatcha paneli bor, (kirish)/ dagi login sahifasida esa yo'q.

Mantiqan header va footer ham "sayt"ga tegishli — ularni (sayt)/layout.tsx ga ko'chirsa bo'lmaydimi? Kanon bunga yo'q dedi, sababi aniq.

Maxsus fayllar darsini eslang: hech bir papkaga mos kelmagan manzil (/yoq) uchun root app/not-found.tsx chiziladi. U root layout ichida chiziladi, lekin (sayt) guruhining layout'iga tushmaydi — /yoq guruh ichidagi hech bir sahifaga mos emas. Header (sayt)/layout.tsx da bo'lsa, 404 sahifasi menyusiz, footer'siz qoladi. Foydalanuvchi adashgan joyda unga eng kerakli narsa — menyu — yo'qoladi.

Qoida: hamma sahifada (404 ham) kerak bo'lgan narsa — root layout'da. Faqat bir guruhga kerak bo'lgani — guruh layout'ida.

Tekshirib ko'ring: app/(sayt)/template.tsx bor. /loyihalar/yoq (noma'lum slug, notFound() chaqiriladi) da animatsiya o'ynaydimi?

Javob

Ha. /loyihalar/yoq (sayt)/loyihalar/[slug]/ ga mos keladi — u guruh ichidagi marshrut, template uni o'raydi. notFound() ning UI'si shu marshrut ichida chiziladi. Template'siz qoladigani — hech bir papkaga mos kelmagan manzillar (/yoq) va root darajadagi xato sahifalari.

2.4 Biz sinadik: ikki guruhda bir xil manzil

Guruh URL'ga kirmagani uchun ikki guruhda bir xil yo'l yozish mumkin bo'lib qoladi: (a)/ikki/page.tsx va (b)/ikki/page.tsx — ikkalasi ham /ikki. Next.js qaysi birini ko'rsatsin? Build:

text
Error: Turbopack build failed with 1 error:
./src/app/(b)
Error: You cannot have two parallel pages that resolve to the same path. Please check /(a)/ikki and /(b).

Tarjimasi: "Bitta manzilga olib keladigan ikkita sahifa bo'lishi mumkin emas. /(a)/ikki va /(b) ni tekshiring". Xabarning oxiri g'alati qisqargan (/(b) — to'liq yo'l emas), lekin yo'nalish aniq: ikkala guruhni qarang. Yechim — bittasini olib tashlash yoki nomini o'zgartirish.

2.5 loading.tsx ni bitta sahifaga cheklash

Route group'ning yana bir kam ma'lum ishlatilishi bor — Next.js hujjatida alohida misol sifatida keltirilgan. Maxsus fayllar darsidan bilasiz: loading.tsx o'z papkasidagi sahifani va hamma ichki papkalarni o'raydi. Faraz qiling, blog ro'yxati sekin ochiladi va unga skelet kerak:

text
app/blog/
├── loading.tsx        ← skelet
├── page.tsx           → /blog (sekin)
└── [slug]/page.tsx    → /blog/salom (tez, statik)

Muammo: loading.tsx endi /blog/salom ni ham o'raydi. Maqoladan maqolaga o'tganda ro'yxat skeleti chaqnab ketishi mumkin — maqolaga umuman o'xshamaydigan rasm.

Yechim — ro'yxat sahifasini va uning skeletini alohida guruhga olish:

text
app/blog/
├── (royxat)/
│   ├── loading.tsx    ← faqat /blog uchun
│   └── page.tsx       → /blog
└── [slug]/page.tsx    → /blog/salom (skeletsiz)

URL'lar o'zgarmadi: (royxat) qavsda. Lekin endi loading.tsx ning "hududi" faqat guruh ichi — [slug] unga kirmaydi. Bitta qoida yana ishladi: maxsus fayl o'z papkasini o'raydi, guruh esa papkani URL'ga ta'sir qilmasdan ajratadi.

portfolio da bunday holat yo'q: blog ro'yxati statik, skelet kerak emas. Lekin katta loyihalarda bu naqsh tez-tez uchraydi — ayniqsa dashboard'larda, bosh sahifa sekin, ichki sahifalar tez bo'lganda.

Tekshirib ko'ring: app/(sayt)/ va app/_sayt/ — ikkalasi ham URL'ga kirmaydi. Farqi nima?

Javob

(sayt) ichidagi page.tsx lar sahifa bo'ladi — faqat guruh nomisiz URL bilan (/haqimda). _sayt ichidagi hech narsa sahifa bo'lmaydi: private papka butunlay routing'dan tashqarida. Birinchisi — sahifalarni guruhlash uchun, ikkinchisi — sahifa bo'lmagan kodni saqlash uchun.

3. Bir nechta root layout

3.1 Qachon kerak?

Ba'zan saytning ikki qismi butunlay boshqacha: ochiq sayt va admin panel. Har birining o'z <html>, shrifti va CSS'i bo'lishi kerak. Route groups bunga imkon beradi: har guruhda o'z root layout'i, app/layout.tsx esa umuman yo'q.

text
app/
├── (sayt)/
│   ├── layout.tsx     ← <html lang="uz"> + sayt CSS
│   └── page.tsx       → /
└── (admin)/
    ├── layout.tsx     ← <html> + admin CSS
    └── panel/page.tsx → /panel
tsx
// app/(admin)/layout.tsx — o'zi root layout
export default function AdminLayout({ children }: LayoutProps<"/">) {
  return (
    <html lang="uz">
      <body className="admin">{children}</body>
    </html>
  );
}

Har ikkala layout <html> va <body> yozadi — ular endi root (Layout va template qoidasi). Bosh sahifa (/) guruhlardan birining ichida bo'lishi shart, aks holda / uchun root layout topilmaydi.

3.2 Narxi: to'liq qayta yuklash

Hujjatdagi muhim ogohlantirish: turli root layout'lar orasida o'tish sahifani to'liq qayta yuklaydi. / dan /panel ga <Link> bilan o'tsangiz ham, brauzer butun sahifani yangidan oladi — Navigatsiya darsidagi prefetch va qayta yuklashsiz o'tish yo'qoladi. Root layout — butun hujjat (<html>), uni almashtirishning boshqa yo'li yo'q.

Shuning uchun bir nechta root layout — kamdan-kam, ataylab tanlov. portfolio da bitta root layout yetarli, kanon uni ishlatmadi.

4. Private papkalar: _papka

4.1 Pastki chiziq — routing'dan tashqari

Papka nomi _ bilan boshlansa, Next.js uni va ichidagi hamma papkalarni routing'dan chiqaradi. Bu — private papka (yopiq papka). Ichida page.tsx bo'lsa ham, u sahifa bo'lmaydi.

Biz tajriba qildik: app/(sayt)/_qoralama/page.tsx yaratdik, build qildik:

text
/_qoralama -> 404 h1: Sahifa topilmadi
/qoralama -> 404 h1: Sahifa topilmadi

Build jadvalida _qoralama umuman yo'q. Oddiy papkada esa page.tsx darhol sahifa bo'lardi.

4.2 Colocation'dan farqi nima?

Fayl-asosli routing darsida ko'rgandik: page.tsx bo'lmagan papkadagi komponent baribir ochilmaydi (/sinov/Tugma — 404). Unda _ ga nima hojat?

Oddiy papka (colocation) _papka
Tugma.tsx ochiladimi yo'q yo'q
Ichiga page.tsx tushib qolsa sahifa bo'ladi sahifa bo'lmaydi
Kelajakdagi maxsus nomlar to'qnashishi mumkin to'qnashmaydi
Muharrirda saralash aralash _ lar birga turadi

Hujjat to'rtta sabab keltiradi: routing va UI mantiqini ajratish, butun loyihada bir xil tartib, muharrirda saralash va kelajakdagi Next.js fayl nomlari bilan to'qnashmaslik. Masalan, komponentlar papkasida loading.tsx degan oddiy komponentingiz bo'lsa — oddiy papkada Next.js uni maxsus fayl deb oladi. _komponentlar/loading.tsx esa xavfsiz.

4.3 Pastki chiziqli URL kerak bo'lsa

Agar URL'ning o'zi _ bilan boshlanishi kerak bo'lsa (/_maxfiy), papka nomini %5Fmaxfiy deb yozasiz: %5F — pastki chiziqning foiz-kodlangan shakli. Kamdan-kam kerak bo'ladi, lekin "nega _ li papkam ochilmayapti?" degan savolga javob shu.

5. Modelda: papka yo'lidan URL

Next.js fayl yo'lidan URL'ni qanday chiqaradi? Soddalashtirilgan model (haqiqiy kod emas), lekin qoidalari yuqoridagi tajribalarga mos:

js
function fileToUrl(file) {
  const parts = file.split("/").slice(1); // "app" ni tashlaymiz
  if (parts.at(-1) !== "page.tsx") return null;
  const segments = [];
  for (const part of parts.slice(0, -1)) {
    if (part.startsWith("_")) return null; // private papka
    if (part.startsWith("(") && part.endsWith(")")) continue; // guruh
    segments.push(part.replace(/^%5F/, "_"));
  }
  return "/" + segments.join("/");
}

const files = [
  "app/(sayt)/page.tsx",
  "app/(sayt)/haqimda/page.tsx",
  "app/(sayt)/loyihalar/[slug]/page.tsx",
  "app/(sayt)/_qoralama/page.tsx",
  "app/(sayt)/loyihalar/_komponentlar/TegFiltri.tsx",
  "app/%5Fmaxfiy/page.tsx",
];
for (const f of files) console.log(fileToUrl(f), "←", f);

Konsolda:

text
/ ← app/(sayt)/page.tsx
/haqimda ← app/(sayt)/haqimda/page.tsx
/loyihalar/[slug] ← app/(sayt)/loyihalar/[slug]/page.tsx
null ← app/(sayt)/_qoralama/page.tsx
null ← app/(sayt)/loyihalar/_komponentlar/TegFiltri.tsx
/_maxfiy ← app/%5Fmaxfiy/page.tsx

Uch qoida bir funksiyada: guruh — o'tkazib yuboriladi (continue), private papka — butun yo'l bekor (null), %5F — pastki chiziqqa aylanadi. parts.at(-1) — massivning oxirgi elementi (manfiy indeks oxiridan sanaydi).

6. Loyihani tashkil qilish usullari

Next.js qat'iy tuzilma talab qilmaydi. Hujjat uchta strategiyani ko'rsatadi:

Usul Qanday Qachon qulay
app/ dan tashqarida app/ faqat marshrutlar; kod src/komponentlar, src/malumot da Kichik va o'rta loyiha
app/ ichida yuqori papkalar app/_komponentlar, app/_lib Hammasi bir joyda bo'lsin
Bo'lim (feature) bo'yicha Har bo'lim o'z komponentlari bilan: loyihalar/_komponentlar Katta loyiha, ko'p jamoa

Kanon aralash yo'lni tanladi:

  • Butun saytga umumiy narsalar — src/komponentlar/ (SaytSarlavhasi, NavHavola, OrqagaTugmasi) va src/malumot/ (loyihalar.ts, sana.ts).
  • Faqat bir bo'limga tegishli — o'sha bo'lim ichida: app/(sayt)/loyihalar/_komponentlar/ (LoyihaKartasi, TegFiltri, keyingi darsda RasmOynasi).

Qoida oddiy: komponent bitta joyda ishlatilsa — o'sha joyga yaqin; ikki va undan ko'p bo'limda — umumiy papkaga. Bu "feature folders" (bo'lim papkalari) g'oyasi: bo'limni o'chirsangiz, uning hamma kodi birga ketadi.

src/ papkasining o'zi ham ixtiyoriy (Loyiha yaratish darsida --src-dir bilan tanlagandik): u ildizdagi config fayllarni ilova kodidan ajratadi.

Tekshirib ko'ring: NavHavola ni app/(sayt)/_komponentlar/ ga ko'chirsak bo'ladimi?

Javob

Texnik jihatdan — ha, lekin noto'g'ri joy. NavHavola ni root layout'dagi SaytSarlavhasi ishlatadi, u esa (sayt) guruhidan tashqarida. Root darajadagi fayl guruh ichidagi papkadan import qilsa, tuzilma chalkashadi: "guruhga tegishli" degan va'da buziladi. Umumiy komponent — umumiy papkada (src/komponentlar/).

7. Portfolio qadami: (sayt) guruhi va _komponentlar

Bu dars va keyingi dars portfolio ning holat 08 ini quradi. Commit hali qilmang — u keyingi darsda, modal bilan birga.

7.1 Ko'chirish

git mv bilan ko'chiring — Git o'zgarishni "ko'chirildi" deb taniydi va fayl tarixi uzilmaydi:

bash
mkdir "src/app/(sayt)"
git mv src/app/page.tsx src/app/template.tsx "src/app/(sayt)/"
git mv src/app/haqimda src/app/aloqa src/app/loyihalar "src/app/(sayt)/"
mkdir "src/app/(sayt)/loyihalar/_komponentlar"
cd src/komponentlar
git mv LoyihaKartasi.tsx TegFiltri.tsx \
  "../app/(sayt)/loyihalar/_komponentlar/"
cd ../..

Qavsli yo'llar qo'shtirnoq ichida: terminalda ( va ) maxsus belgilar. Keyin loyihalar/page.tsx dagi importlar:

diff
-import { LoyihaKartasi } from "@/komponentlar/LoyihaKartasi";
-import { TegFiltri } from "@/komponentlar/TegFiltri";
+import { LoyihaKartasi } from "./_komponentlar/LoyihaKartasi";
+import { TegFiltri } from "./_komponentlar/TegFiltri";

Nisbiy import (./) — "bu komponent shu yerniki" degan signal. Umumiy komponentlar @/ bilan qoladi.

7.2 Natija

text
src/app/
├── (sayt)/
│   ├── loyihalar/
│   │   ├── _komponentlar/   LoyihaKartasi, TegFiltri
│   │   ├── [slug]/          page.tsx, loading.tsx
│   │   └── page.tsx
│   ├── aloqa/  haqimda/
│   ├── page.tsx
│   └── template.tsx
├── error.tsx  global-error.tsx  not-found.tsx
├── globals.css  icon.svg
└── layout.tsx

Root'da faqat ilova darajasidagi fayllar qoldi. Keyingi darslarda sitemap.ts, robots.ts, opengraph-image.tsx ham shu yerga keladi.

npm run build — route jadvali holat 06 dagidek, bitta qator ham o'zgarmagan. Bu — ko'chirish to'g'ri bo'lganining isboti. Endi 404 sahifasini oching: animatsiya yo'q, menyu bor.

8. Ko'p uchraydigan xatolar

Belgi Sabab Davosi
You cannot have two parallel pages that resolve to the same path Ikki guruhda bir xil yo'l Bittasini o'chiring yoki nomlang
_papka/page.tsx ochilmaydi Private papka routing'dan tashqari Bu kutilgan; URL'da _ kerak bo'lsa — %5F
404 sahifasida menyu yo'q Header guruh layout'ida Hamma joyda kerak narsa — root layout'ga
Bo'limlar orasida sahifa to'liq qayta yuklanadi Ikki xil root layout Bitta root layout yoki bu narxni qabul qiling
/ 404 qaytaradi Ko'p root layout, / hech bir guruhda yo'q page.tsx ni guruhlardan biriga
Komponentlar papkasidagi loading.tsx sahifaga ta'sir qildi Oddiy papkada maxsus nom _komponentlar/ ga oling
Terminalda syntax error near unexpected token '(' Qavsli yo'l qo'shtirnoqsiz "src/app/(sayt)"

9. Mashqlar

Mashqlar kurs/mashqlar/23/07-route-groups/ da.

1-mashq (oson): fayldan URL

  • app/(dokon)/savat/page.tsx →
  • app/(dokon)/(katalog)/kiyim/page.tsx →
  • app/blog/_qismlar/Muallif.tsx →
  • app/blog/(yangilar)/page.tsx →
  • app/%5Fichki/page.tsx →
Yechim
  • /savat — guruh URL'ga kirmaydi.
  • /kiyim — ichma-ich ikki guruh ham kirmaydi.
  • yo'q — private papka va page.tsx emas.
  • /blog — guruh ichidagi page.tsx ota segmentning sahifasi bo'ldi.
  • /_ichki — %5F pastki chiziqqa aylanadi.

2-mashq (o'rta): qaysi layout'lar o'raydi?

Funksiya yozing: layoutsFor(page, layouts) — sahifa fayli va loyihadagi layout.tsx fayllari ro'yxatini oladi, sahifani o'raydigan layout'larni tashqaridan ichkariga qaytaradi. Qoida: layout'ning papkasi sahifa papkasining boshlanishi bo'lsa — o'raydi (Layout va template darsidagi "sahifadan ildizgacha" qoidasi). Guruh papkalari ham hisobga olinadi — URL emas, fayl yo'li muhim. Ishora: slice(0, -"layout.tsx".length) bilan papka yo'lini oling va startsWith bilan solishtiring.

Sinov: layouts = ["app/layout.tsx", "app/(sayt)/layout.tsx", "app/(admin)/layout.tsx", "app/(sayt)/loyihalar/layout.tsx"], sahifalar app/(sayt)/loyihalar/[slug]/page.tsx va app/(admin)/panel/page.tsx.

Yechim
js
function layoutsFor(page, layouts) {
  const dir = page.slice(0, -"page.tsx".length);
  return layouts
    .filter((l) => dir.startsWith(l.slice(0, -"layout.tsx".length)))
    .sort((a, b) => a.length - b.length);
}

const layouts = [
  "app/layout.tsx",
  "app/(sayt)/layout.tsx",
  "app/(admin)/layout.tsx",
  "app/(sayt)/loyihalar/layout.tsx",
];

const show = (page) =>
  console.log(layoutsFor(page, layouts).join(" > "));

show("app/(sayt)/loyihalar/[slug]/page.tsx");
show("app/(admin)/panel/page.tsx");

Konsolda:

text
app/layout.tsx > app/(sayt)/layout.tsx > app/(sayt)/loyihalar/layout.tsx
app/layout.tsx > app/(admin)/layout.tsx

Ikkala sahifaning URL'ida guruh yo'q (/loyihalar/…, /panel), lekin o'raydigan layout'lar har xil — chunki fayl yo'llari har xil. Route group'ning butun kuchi shu: URL bir xil tekislikda, layout'lar esa guruhga qarab. Saralash uzunlik bo'yicha: qisqa yo'l — tashqi layout.

3-mashq (qiyin): to'qnashuvni toping

Build xatosini o'zingiz yozing: findConflicts(files) — sahifa fayllari ro'yxatidan bir xil URLga tushadiganlarini topadi va "/ikki: app/(a)/ikki/page.tsx, app/(b)/ikki/page.tsx" ko'rinishidagi satrlar massivini qaytaradi. URL'ni «Modelda: papka yo'lidan URL» bo'limidagi fileToUrl hisoblaydi (null lar o'tkaziladi). Ishora: Map — kalit URL, qiymat fayllar massivi (Map).

Yechim
js
function fileToUrl(file) {
  const parts = file.split("/").slice(1);
  if (parts.at(-1) !== "page.tsx") return null;
  const segments = [];
  for (const part of parts.slice(0, -1)) {
    if (part.startsWith("_")) return null;
    if (part.startsWith("(") && part.endsWith(")")) continue;
    segments.push(part.replace(/^%5F/, "_"));
  }
  return "/" + segments.join("/");
}

function findConflicts(files) {
  const byUrl = new Map();
  for (const file of files) {
    const url = fileToUrl(file);
    if (url === null) continue;
    byUrl.set(url, [...(byUrl.get(url) ?? []), file]);
  }
  return [...byUrl]
    .filter(([, list]) => list.length > 1)
    .map(([url, list]) => `${url}: ${list.join(", ")}`);
}

console.log(
  findConflicts([
    "app/(a)/ikki/page.tsx",
    "app/(b)/ikki/page.tsx",
    "app/(sayt)/page.tsx",
    "app/page.tsx",
    "app/_eski/ikki/page.tsx",
    "app/haqimda/page.tsx",
  ]),
);

Konsolda:

text
[
  '/ikki: app/(a)/ikki/page.tsx, app/(b)/ikki/page.tsx',
  '/: app/(sayt)/page.tsx, app/page.tsx'
]

Ikkinchi to'qnashuv kutilmagan bo'lishi mumkin: app/page.tsx va app/(sayt)/page.tsx — ikkalasi ham /. Sahifalarni guruhga ko'chirib, eski app/page.tsx ni o'chirishni unutish — aynan shunday xato beradi. _eski/ikki esa to'qnashmadi: private papka routing'da yo'q.

4-mashq: Portfolio qadami

O'z portfolio ingizda sahifalar va template.tsx ni (sayt) guruhiga, faqat «Loyihalar» bo'limida ishlatiladigan komponentlarni loyihalar/_komponentlar/ ga ko'chiring (git mv bilan). Importlarni tuzating. Tekshiring: npm run build jadvali avvalgidek bo'lishi kerak; /yoq da menyu bor, kirish animatsiyasi yo'q.

Yechim

Namuna — «Portfolio qadami» bo'limidagi buyruqlar va daraxt. Build jadvali o'zgargan bo'lsa (yangi yoki yo'qolgan qator) — biror sahifa noto'g'ri joyga tushgan yoki eski fayl qolgan: 3-mashqdagi kabi to'qnashuvni qidiring. git status da fayllar renamed: deb ko'rinishi kerak — bu git mv tarixni saqlaganini bildiradi. Commit hali qilmang: keyingi darsda modal bilan birga.

10. Real ishda

  • Marketing va ilova — eng ko'p uchraydigan juftlik: (marketing)/ (bosh sahifa, narxlar, blog — SEO kerak) va (app)/ (kirgan foydalanuvchi paneli). Har birining o'z layout'i, ba'zan o'z root layout'i.
  • (auth) guruhi — kirish va ro'yxatdan o'tish sahifalari menyusiz, oddiy layout bilan. Sahifalar /login, /register bo'lib qoladi.
  • Katta jamoalar guruhlarni jamoa bo'yicha ham bo'ladi: (tolov)/, (profil)/ — har jamoa o'z papkasida ishlaydi, URL'lar tekis qoladi.
  • Private papkalar — kod tekshiruvida (code review) "nega komponent app/ ichida?" degan savolga javob: _ — "bu marshrut emas" degan aniq belgi.

Xulosa

  • (guruh) — URL'ga kirmaydi; sahifalarni guruhlab, guruhga o'z layout/template'ini berish uchun.
  • Hamma sahifaga (404 ham) kerak narsa — root layout'da; guruh layout'i mos kelmagan manzilni o'ramaydi.
  • Ikki guruhda bir xil URL — build xatosi; har guruhda o'z root layout'i bo'lsa, ular orasida o'tish to'liq qayta yuklanadi.
  • _papka — butunlay routing'dan tashqari, ichidagi page.tsx ham; URL'da _ kerak bo'lsa — %5F.
  • Komponent bir bo'limniki bo'lsa — o'sha bo'lim yonida (_komponentlar), umumiy bo'lsa — src/komponentlar.

Keyingi dars: Parallel va intercepting routes — @modal slot va (.) bilan loyiha rasmini URL'li modal oynada ochamiz.

Manbalar

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Next.js route groups va private papkalar: (guruh), papka va loyiha tashkili — IlmHamroh