Artikel Terkait Tanpa Waterfall di Halaman Blog
Commit 70a43a9 menambahkan artikel terkait, fetch paralel, timeline CSS, dan TOC file-tree ke halaman detail blog Next.js.
Saya tahu ada yang kurang begitu membuka halaman detail artikel: isi utamanya sudah rapi, tetapi pembaca mentok di footer tanpa petunjuk bacaan berikutnya. Commit 70a43a9 berangkat dari momen itu. Saya menambahkan RelatedArticles, lalu menjadikannya timeline kecil di atas footer. Bukan rekomendasi acak dan bukan mesin personalisasi. Artikel dengan tag pertama yang sama sudah cukup masuk akal untuk blog pribadi.
Masalah berikutnya muncul saat memikirkan data. Halaman detail sudah mengambil artikel utama. Kalau daftar related di-fetch setelah request pertama selesai, halaman mendapat waterfall yang sebenarnya tidak perlu. Solusinya adalah memasukkan fetch related ke Promise.all yang sudah ada di page.tsx. MDN menjelaskan bahwa Promise.all() mengembalikan satu promise yang selesai ketika seluruh input selesai, tetapi langsung reject jika salah satunya reject [1]. Dokumentasi Next.js juga mengingatkan bahwa kegagalan satu request di dalam Promise.all membuat seluruh operasi gagal [2]. Jadi pola ini memang paralel, tetapi bukan fallback otomatis.
Fetch paralel, payload tetap kecil
Saya tidak membuat endpoint rekomendasi baru. Data related memakai ringkasan artikel yang sudah tersedia: slug untuk link, title untuk judul, tags untuk pencocokan, categories untuk label, serta excerpt dengan fallback ke seo_description. Konten penuh tidak dibutuhkan oleh kartu kecil di bawah artikel. Ini keputusan yang lebih sehat daripada mengirim HTML panjang hanya untuk menampilkan dua baris teks.
Bentuk sederhananya kira-kira seperti ini:
const [article, related] = await Promise.all([
getArticle(slug, locale),
getRelatedArticles(firstTag, locale),
]);
Kuncinya bukan sekadar memakai API Promise.all, melainkan memulai dua pekerjaan yang tidak saling menunggu pada tempat yang sama. Kalau artikel utama gagal, halaman tetap gagal sesuai kontrak yang jelas. Kalau kebutuhan produk kelak berubah menjadi “tampilkan apa pun yang berhasil”, barulah Promise.allSettled() lebih cocok karena menunggu semua promise selesai [1]. Jangan menyamarkan perbedaan ini dengan catch yang mengembalikan array kosong tanpa alasan; itu bisa mengubah error nyata menjadi UI yang diam-diam kosong.
Komponen related juga tidak memaksakan tampilan kalau hasilnya kosong. RelatedArticles langsung mengembalikan null. Setiap item mendapat chip tanggal yang dibuat lewat Intl.DateTimeFormat: locale Indonesia memakai id-ID, sedangkan Inggris memakai en-US. API ini memang dirancang untuk format tanggal dan waktu yang peka bahasa [3], sehingga kita tidak perlu merakit nama bulan sendiri atau menyimpan dua format tanggal manual.
Timeline CSS dan TOC yang terasa seperti file tree
Timeline-nya sengaja tidak memakai library baru. Garis vertikal dibuat dengan elemen absolut selebar satu pixel, gradient, lalu titik dan garis pendek ditempatkan di tengah tile ikon. Pada layar kecil daftar menjadi satu kolom; di layar besar grid menjadi dua kolom dan tiap item memiliki spine sendiri. Tanggal, ikon stack, kategori, judul, dan excerpt disusun dari atas ke bawah agar mata punya jalur baca yang jelas.
Judul dan ringkasan tidak boleh membuat satu kartu menjulang jauh lebih tinggi dari yang lain. Karena itu saya memakai line-clamp-2 dan line-clamp-1 pada breakpoint yang lebih besar. Utility Tailwind tersebut memang dipakai untuk memotong teks multiline setelah jumlah baris tertentu [4]. Ini bukan pengganti penulisan excerpt yang baik, tetapi pagar layout yang praktis.
Perubahan kedua ada di sidebar. BlogToc sebelumnya hanya daftar anchor datar. Sekarang H2 diperlakukan seperti folder: ada chevron dan baris induk. H3 menjadi anak dengan indentasi, garis panduan vertikal, serta node stub yang menghubungkan teks ke spine. Anchor tetap statis dan komponen tetap Server Component. Saya sengaja belum menambahkan scrollspy; untuk TOC yang hanya perlu membawa pembaca ke heading, JavaScript tambahan belum memberi nilai yang sebanding dengan kompleksitasnya.
Hasil commit ini bukan sistem rekomendasi besar. Ia memperbaiki dua momen navigasi yang konkret: pembaca mendapat jalur lanjut yang relevan, dan pembaca yang sudah berada di artikel panjang bisa memahami strukturnya sekilas. Fetch paralel menjaga alur data tetap masuk akal, sementara CSS biasa menjaga bundle dan keputusan desain tetap sederhana.
Sumber yang saya pakai
[1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
[2] https://nextjs.org/docs/app/building-your-application/data-fetching/patterns
[3] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat