Lompat ke konten
dokumentasi.id
Commit 9a47d33
v2
Star3,4 rb

5

App Router, Layout, dan Metadata

src/app memakai App Router. Di akar segmen hanya ada satu layout.tsx; satu layout tambahan duduk di src/app/components/ bersama page.tsx milik segmen itu. Root layout memasang stylesheet global sekaligus mendefinisikan metadata dasar, sedangkan layout components menimpa judul untuk segmen /components. src/app/layout.tsx:1-8 src/app/components/layout.tsx:1-17

Peta route, layout, dan sumber metadata

Hanya tiga berkas di src/app yang mengekspor metadata: root layout, layout components, dan not-found. Berkas page.tsx sendiri tidak mendeklarasikan metadata apa pun, sehingga judulnya diwarisi dari layout terdekat. src/app/page.tsx:24-28 src/app/not-found.tsx:5-7

RouteBerkas routeLayout yang membungkusAsal metadata
/src/app/page.tsx:24-28RootLayoutmetadata di src/app/layout.tsx:12-50
/componentssrc/app/components/page.tsx:27RootLayout, lalu ComponentsLayoutmetadata di src/app/components/layout.tsx:6-9
route yang tidak cocoksrc/app/not-found.tsx:9-20RootLayoutmetadata di src/app/not-found.tsx:5-7

Halaman not-found dibahas lebih jauh di Halaman, Error Boundary, dan Endpoint API.

graph TD
  siteConfig["siteConfig (src/constant/config.ts)"]
  metaRoot["metadata (src/app/layout.tsx)"]
  rootLayout["RootLayout (src/app/layout.tsx)"]
  doc["<html> dan <body>"
  homePage["/ - src/app/page.tsx"]
  metaComponents["metadata title Components"]
  componentsLayout["ComponentsLayout (src/app/components/layout.tsx)"]
  componentsPage["/components - src/app/components/page.tsx"]

  siteConfig --> metaRoot
  metaRoot --> rootLayout
  rootLayout --> doc
  doc --> homePage
  doc --> componentsLayout
  metaComponents --> componentsLayout
  componentsLayout --> componentsPage

  style siteConfig fill:#f59e0b,color:#000
  style metaRoot fill:#f59e0b,color:#000
  style rootLayout fill:#2d7d46,color:#fff
  style doc fill:#2d7d46,color:#fff
  style metaComponents fill:#8b5cf6,color:#fff
  style componentsLayout fill:#8b5cf6,color:#fff
%% fig: Pewarisan layout dan metadata ke tiap route
%% desc: siteConfig mengisi metadata root, RootLayout merender html dan body, lalu segmen components menambahkan layout dan metadata sendiri.
Fig. 1: Pewarisan layout dan metadata ke tiap routesiteConfig mengisi metadata root, RootLayout merender html dan body, lalu segmen components menambahkan layout dan metadata sendiri.

RootLayout: satu-satunya tempat stylesheet global dipasang

RootLayout mengimpor @/styles/globals.css pada baris keempat dan @/styles/colors.css pada baris keenam. Komentar !STARTERCONF di atas impor kedua menyatakan berkas warna itu hanya untuk demo. src/app/layout.tsx:4-6

Isi globals.css yang dipakai seluruh halaman terbagi tiga blok. Blok @theme mendefinisikan --font-primary, palet --color-primary-50 sampai --color-primary-950, --color-dark, serta --animate-flicker dan --animate-shimmer. src/styles/globals.css:1-27 Dua keyframe yang dirujuk token animasi itu, flicker dan shimmer, dideklarasikan sesudahnya. src/styles/globals.css:30-62 @layer base memuat @font-face Inter dari /fonts/inter-var-latin.woff2, kelas tipografi .h0 sampai .h4 beserta body dan .p, kelas .layout dengan max-width: 68.75rem, dan .min-h-main. src/styles/globals.css:64-126

Kelas .layout itu yang dipakai halaman beranda pada elemen pembungkusnya, sehingga lebar konten konsisten di semua halaman. src/app/page.tsx:24-28 Rincian token warna dan token animasi ada di Styling, Token Warna, dan Tema.

⚠️ RootLayout merender <html> tanpa atribut lang dan <body> tanpa className. Kalau kamu menambahkan className global, pasang di body pada berkas ini, bukan di globals.css, karena globals.css sudah diimpor di sini dan tidak di tempat lain. src/app/layout.tsx:52-62

Metadata dasar yang dibangun dari siteConfig

Nilai metadata di root layout hampir seluruhnya berasal dari siteConfig, yang hanya berisi tiga field teks. src/constant/config.ts:1-7

Field metadataNilaiBaris
metadataBasenew URL(siteConfig.url)src/app/layout.tsx:12-13
title.defaultsiteConfig.titlesrc/app/layout.tsx:14-17
title.template``%s${siteConfig.title}``
descriptionsiteConfig.descriptionsrc/app/layout.tsx:18
robots{ index: true, follow: true }src/app/layout.tsx:19
icons/favicon/favicon.ico, /favicon/favicon-16x16.png, /favicon/apple-touch-icon.pngsrc/app/layout.tsx:22-26
manifest/favicon/site.webmanifestsrc/app/layout.tsx:27
openGraphurl, title, description, siteName, type: 'website', locale: 'en_US'src/app/layout.tsx:28-36
openGraph.images${siteConfig.url}/images/og.jpgsrc/app/layout.tsx:33
twittercard: 'summary_large_image' plus judul, deskripsi, dan gambar yang samasrc/app/layout.tsx:37-43

Dua bagian dinonaktifkan lewat komentar: twitter.creator dan seluruh array authors. Keduanya perlu dibuka kembali kalau kamu ingin atribut itu muncul di <head>. src/app/layout.tsx:42-49

Judul halaman anak menimpa template

title.template di root layout berbentuk %s | ${siteConfig.title}, jadi judul yang dideklarasikan segmen anak masuk ke slot %s. Layout components mendeklarasikan title: 'Components' dan description: 'Pre-built components with awesome default', sehingga rute /components memakai judul turunan itu, bukan judul default. src/app/components/layout.tsx:6-9

Layout components juga mengimpor @/styles/colors.css sekali lagi, padahal root layout sudah mengimpornya. Impor ganda ini tidak mengubah hasil, tetapi komentar !STARTERCONF di root layout tetap menyarankan penghapusan berkas warna demo tersebut. src/app/components/layout.tsx:1-4

sequenceDiagram
  participant B as Browser
  participant R as RootLayout
  participant S as siteConfig
  participant C as ComponentsLayout
  B->>R: GET /components
  R->>S: baca url, title, description
  R->>R: pasang title.default dan title.template
  R->>C: render children
  C->>C: metadata.title = "Components"
  C-->>B: head berisi "Components | Next.js + Tailwind CSS + TypeScript Starter"
%% fig: Resolusi metadata satu request ke /components
%% desc: Root layout menyusun judul default dan template dari siteConfig, lalu layout components mengisi slot judul untuk segmennya.
Fig. 2: Resolusi metadata satu request ke /componentsRoot layout menyusun judul default dan template dari siteConfig, lalu layout components mengisi slot judul untuk segmennya.

Satu hal yang perlu diingat: layout anak tidak mengganti seluruh objek metadata, ia hanya menimpa field yang dideklarasikannya. Karena components/layout.tsx hanya menulis title dan description, field seperti icons, manifest, dan openGraph tetap diwarisi dari root layout. src/app/components/layout.tsx:6-9 src/app/layout.tsx:12-50

Menyesuaikan untuk proyek sendiri

Ganti url, title, dan description di siteConfig lebih dulu; tiga field itu yang mengalir ke metadataBase, judul, deskripsi, openGraph, dan twitter. src/constant/config.ts:1-7 Setelah itu sesuaikan icons dan manifest, yang menunjuk berkas di direktori /favicon. Langkah deploy dan berkas SEO lain ada di SEO, Sitemap, dan Deploy.