Skip to content
Konsultasi

Dua Commit yang Saya Revert: generateSitemaps vs Route Next 16

Adityo Guni Waluyo

Build Next 16 menolak route folder sitemap.xml karena bentrok konvensi metadata. Dua commit saya revert, sistem /sitemaps/ lama via rewrite sudah cukup.

Build gagal karena nama folder

Commit terakhir malam itu kelihatan bagus: sitemap dipecah jadi file anak 200 URL pakai generateSitemaps(), lalu app/sitemap.xml/route.ts saya tulis sendiri buat mengeluarkan sitemap index di root. Dua jam kemudian dua-duanya saya revert. Build Next 16 menolak folder rute bernama sitemap.xml karena bentrok dengan konvensi file metadata sitemap.(xml|js|ts), dan pas saya tarik napas, saya sadar satu hal yang lebih memalukan: sistem yang lebih tua di repo ini udah ngerjain semua itu. Lewat rewrite.

Kronologinya begini. Blog ini pindah ke Vercel dua hari sebelumnya, dan dari dulu udah ada sistem sitemap di /sitemaps/: /sitemaps/index.xml jadi sitemap index, anak-anaknya di /sitemaps/pages.xml dan /sitemaps/articles-1.xml, masing-masing maksimal 200 URL. Root /sitemap.xml bukan route sama sekali, cuma rewrite di next.config.ts. Berfungsi, terindeks, robots.txt udah nunjuk ke sana. Lalu saya bikin versi paralel pakai API metadata bawaan Next dan lupa mematikan yang lama.

Bentroknya bukan hal baru

Yang bikin hati tenang: bentrok semacam ini terdokumentasi. Next.js memperlakukan sitemap.ts sebagai file konvensi metadata yang menghasilkan /sitemap.xml, dan folder rute yang namanya persis sitemap.xml ketangkap kasus khusus. Di issue vercel/next.js#94041, route handler di folder sitemap.xml malah nggak terdaftar di app output map, dan request jatuh ke route dinamis sebelahnya. Penulisnya nemu bahwa rename folder ke nama lain langsung memperbaiki build. Kasus serumpun juga pernah ada di vercel/next.js#78609: sitemap.ts bentrok dengan page di /sitemap saat Turbopack aktif, dan baru rapi di 16.2.0. Repo ini jalan di 16.2.12, jadi saya nggak sendirian, dan ini emang medan yang masih bergerak.

Dari sisi protokol, solusi lama di repo ini juga udah benar. Protokol sitemaps cuma minta semua file di host yang sama dengan indexnya, dan panduan Google menambahkan: sitemap yang direferensikan index harus di direktori yang sama atau lebih dalam. /sitemap.xml yang berupa rewrite menunjuk /sitemaps/*.xml. Patuh aturan, tinggal satu URL buat disubmit ke Search Console.

Revert, dan bentuk finalnya

Jadi dua commit itu saya bongkar: implementasi generateSitemaps() balik jadi sitemap.ts sederhana yang cuma nge-list rute statis, dan app/sitemap.xml/route.ts dihapus total. Yang tersisa di production bentuknya kecil banget:

// next.config.ts — /sitemap.xml itu rewrite, bukan route
async rewrites() {
  return [
    {
      source: "/sitemap.xml",
      destination: "/sitemaps/index.xml",
    },
  ];
}
// app/sitemaps/index.xml/route.ts — index beneran di sini
export const revalidate = 120;

export async function GET() {
  const siteUrl = await getSiteUrl();
  const chunks = chunkEntries(
    articleEntries(siteUrl, await fetchAllArticles()),
  );

  return xmlResponse(
    renderSitemapIndex([
      {
        loc: `${siteUrl}/sitemaps/pages.xml`,
        lastModified: newestOf(staticPageEntries(siteUrl)),
      },
      ...chunks.map((chunk, i) => ({
        loc: `${siteUrl}/sitemaps/articles-${i + 1}.xml`,
        lastModified: newestOf(chunk),
      })),
    ]),
  );
}

Cara saya ngecek semuanya masih sehat sekarang: curl root index-nya, pastikan dia ngelisting /sitemaps/pages.xml dan /sitemaps/articles-1.xml, lalu buka tiap anak dan hitung jumlah <loc> dibanding jumlah artikel published di API. Kalau angka anaknya lebih kecil, ada artikel yang bocor nggak ke-crawl. robots.txt saya baca sekalian: satu baris Sitemap: nunjuk ke index, bukan ke file anak. Tiga perintah, tiga puluh detik, dan ketimbang nunggu Google Search Console kasih laporan mingguan, ini jauh lebih cepat kebablasan.

Pelajaran yang saya bawa pulang bukan soal Next. Tapi soal ngecek dulu apa yang udah ada sebelum nulis versi baru. Cerita lengkap kenapa sitemap ini awalnya dipecah 200 URL per file pernah saya tulis di artikel sebelumnya, termasuk drama /sitemap.xml yang 404 karena Next nggak bikin index untuk generateSitemaps(). Kalau saya baca ulang tulisan itu sebelum commit malam itu, mungkin dua jam kerja bisa jadi lima menit. Rencana besar soal generateSitemaps saya simpan dulu, sampai issue #94041 ditutup dan perilaku folder sitemap.xml jadi stabil.

Artikel terkait