Insights

Membangun Route SEO untuk Website Bergaya Desktop di Next.js

Bagian kedua dari seri website bergaya desktop dan SEO: implementasi satu URL publik yang melayani konten SEO semantik, membuka window UI yang sesuai, dan tetap scalable melalui Firestore, Storage, dan on-demand revalidation.

· 9 min

Membangun Route SEO untuk Website Bergaya Desktop di Next.js


Catatan tentang Membuat Website Desktop Tetap Jujur kepada Web

Dulu saya menjelaskan arsitektur ini sebagai dua layer.

Satu layer untuk desktop UI.

Satu layer lagi untuk full-page SEO route.

Penjelasan itu berguna di awal, karena membantu saya memisahkan dua hal yang mudah tercampur: interface yang dilihat manusia, dan makna yang perlu dibaca mesin.

Tapi setelah sistem ini berkembang, saya mulai merasa istilah "dua layer" bisa disalahpahami.

Ia bisa membuat route SEO terdengar seperti halaman cadangan.

Ia bisa membuat window UI terdengar seperti produk yang sebenarnya.

Dan pelan-pelan, cara berpikir seperti itu bisa membuat dua versi dari konten yang sama berjalan sendiri-sendiri.

Arsitektur yang sekarang lebih saya percaya sebenarnya lebih sederhana:

satu URL publik,

semantic content untuk web,

window UI untuk pengalaman manusia,

dan satu source of truth di belakang keduanya.

Alamatnya sama.

Tanggung jawabnya berbeda.

Perubahan kecil ini penting.

Website tetap terasa seperti desktop, tanpa berpura-pura bahwa web di bawahnya tidak ada.

Tulisan ini adalah pasangan teknis dari catatan sebelumnya: Website Bergaya Desktop dengan SEO yang Kuat.

Di sana saya membahas prinsipnya.

Di sini saya masuk ke cara sistemnya bekerja: content source, publish step, route semantik, metadata, sitemap, file AI-readable, dan on-demand revalidation.


1. Masalah pada Website yang Terlalu App-Like

Website yang terasa seperti aplikasi memang menyenangkan untuk dibuat.

Kita bisa membuat window.

Kita bisa membuat dock.

Kita bisa membuat icon, preview, folder, search, behavior seperti desktop, dan detail kecil yang membuat website terasa hidup.

Tapi web punya ekspektasi lain.

URL harus punya makna.

Halaman harus bisa dibaca tanpa menunggu aplikasi client-only menyusun semuanya.

Metadata harus sesuai dengan konten.

Sitemap harus menampilkan halaman penting.

Structured data harus menjelaskan peran halaman.

AI-readable files tidak boleh menceritakan hal yang berbeda dari website-nya sendiri.

Di titik inilah banyak website app-like menjadi rapuh.

UI terlihat kaya, tapi maknanya terjebak di dalam client components.

Kontennya ada, tapi baru muncul setelah JavaScript berjalan.

Route-nya ada, tapi tidak membawa konteks yang cukup.

Untuk beberapa dashboard atau private tools, itu tidak masalah.

Tapi untuk personal website, portfolio, store, dan notes system yang publik, saya tidak ingin konten tersembunyi di balik metafora.

Metafora seharusnya membuat pengalaman lebih hangat.

Bukan membuat web menjadi lebih lemah.


2. Satu URL Seharusnya Cukup

Ketika seseorang membuka:

/insights/membangun-route-seo-untuk-website-bergaya-desktop-di-nextjs

URL itu harus lengkap.

Ia tidak boleh hanya menjadi shell yang berkata, "Tunggu sebentar sampai aplikasi membuka artikel yang sebenarnya."

Ia harus sudah tahu title-nya.

Ia harus sudah tahu description-nya.

Ia harus punya canonical metadata.

Ia harus punya Open Graph dan Twitter card.

Ia harus punya JSON-LD.

Ia harus merender artikel sebagai semantic HTML.

Ia harus masuk sitemap.

Ia harus terwakili di llms.txt dan llms-full.txt.

Tapi di waktu yang sama, ketika manusia membuka URL itu di browser, saya tetap ingin experience-nya terasa seperti website ini.

Bukan seperti halaman artikel polos yang terpisah dari desktop.

Jadi route punya dua pekerjaan:

public URL
  -> semantic route content untuk SEO dan crawler
  -> desktop shell membuka window yang sesuai untuk user

URL adalah titik temu.

Itulah inti sistemnya.


3. Source Menulis vs Source Runtime

Saya masih suka menulis dengan MDX.

Sederhana.

Tulisan tetap dekat dengan repository.

Saya bisa mengedit di VS Code tanpa membuat proses content terasa seperti CMS yang berat.

Tapi ada perbedaan antara source yang saya pakai untuk menulis dan source yang dipakai website saat runtime.

Dulu, file MDX lokal punya dua peran sekaligus:

  • source untuk menulis.
  • source untuk runtime.

Untuk konten kecil, itu baik-baik saja.

Tapi jangka panjang, website bisa tumbuh menjadi ratusan atau ribuan notes, produk, dokumen, quotes, audio metadata, dan desktop items.

Kalau setiap file konten harus selalu diparse saat build, build akan menjadi semakin berat.

Maka flow yang baru lebih seperti ini:

content/notes
  -> publish script
  -> Firestore + Storage
  -> content loader
  -> route metadata + semantic HTML
  -> desktop window state
  -> sitemap + llms files

File lokal tetap menjadi CMS source.

Firestore menjadi runtime content source.

Storage atau CDN menjadi runtime asset source.

Dengan begitu, proses menulis tetap nyaman, sementara website yang sudah deploy tidak terlalu bergantung pada folder content lokal harus ikut dibundel ke build output.

Ini arsitektur yang lebih tenang.

Tidak heboh.

Tapi lebih kalem.


4. Apa yang Diselesaikan oleh Publish Step

Publish step mudah dianggap sebagai command tambahan saja.

Padahal ia menyelesaikan beberapa masalah praktis.

Ia mengupload gambar dari folder content ke Storage.

Ia mengganti referensi image lokal di MDX menjadi URL publik yang stabil.

Ia menulis dokumen yang sudah dinormalisasi ke Firestore.

Ia menandai konten yang dihapus sebagai inactive jika diperlukan.

Ia memanggil revalidation supaya route publik, sitemap, dan AI-readable files tidak tertinggal.

Poin pentingnya: website yang sudah deploy bisa menganggap Firestore sebagai source of truth runtime.

MDX lokal tetap menjadi source untuk menulis.

Perbedaan ini kecil, tapi membuat sistem lebih future-proof.

Kalau suatu hari saya menulis dari custom editor, bukan VS Code, arsitektur runtime tidak perlu ditulis ulang.

Selama hasil akhirnya tetap dipublish ke bentuk content yang sama, sistem tetap berjalan.

Karena itu saya suka flow ini.

Ia tidak terlalu terikat pada alat yang dipakai untuk menulis.

Ia lebih terikat pada kontrak konten.


5. Route Merender Konten SEO Semantik

Route page punya pekerjaan yang tenang.

Ia mengambil konten dari loader.

Ia membuat metadata.

Ia merender JSON-LD.

Ia menyediakan semantic HTML.

Untuk detail insight, bentuknya:

export const dynamic = "force-static";
export const dynamicParams = true;
export const revalidate = false;

Artinya, saya tidak perlu prebuild semua slug.

Saya juga tidak perlu server-render setiap request.

Route bisa dibuat on-demand, dicache sebagai static output, lalu disegarkan melalui revalidation eksplisit ketika konten berubah.

Ini terasa cocok untuk konten yang terus bertumbuh.

SSG sangat bagus kalau jumlah halaman kecil dan stabil.

SSR berguna kalau halaman harus selalu fresh di setiap request.

CSR cocok untuk account page, dashboard, dan interface yang tidak perlu ranking.

Tapi untuk notes, produk, quotes, audio pages, dan preview pages, saya ingin sesuatu di tengah.

Saya ingin makna yang sudah dirender tanpa memaksa semua kemungkinan halaman masuk ke setiap build.

On-demand static generation memberi keseimbangan itu.


6. Metadata Harus Dekat dengan Konten

Metadata drift adalah masalah kecil yang terasa biasa saja sampai ia menumpuk.

Title artikel berubah, tapi Open Graph title tidak ikut berubah.

Description diperbaiki, tapi sitemap masih menunjuk versi lama.

Body halaman mengatakan satu hal, sementara llms-full.txt menjelaskan hal lain.

Satu mismatch mungkin tidak fatal.

Tapi kalau berkumpul, website terasa kurang terawat.

Karena itu saya lebih suka metadata diturunkan dari content yang sama.

Untuk detail route, content source yang sama bisa dipakai untuk:

  • title
  • description
  • canonical URL
  • Open Graph
  • Twitter card
  • JSON-LD
  • article body
  • sitemap entry
  • AI-readable summary

Tidak semua field harus otomatis sepenuhnya.

Kontrol editorial tetap penting.

Tapi sumbernya harus cukup dekat supaya makna publik tidak pecah menjadi banyak versi.


7. DesktopShell Membaca Pathname yang Sama

Desktop UI tidak perlu route terpisah untuk tahu apa yang harus dibuka.

Ia membaca pathname yang sedang aktif.

Di desktop layout, route-specific content dirender lebih dulu:

{children}
<div className="fixed inset-0 overflow-hidden">
  <DesktopShell ... />
</div>

children adalah konten route: metadata, JSON-LD, dan semantic article HTML.

DesktopShell adalah layer interface yang berada di atasnya.

Di dalam shell, pathname dicocokkan dengan content:

const noteForPath = noteItems.find((item) => item.routePath === pathname);

Jika pathname adalah route insight, Notes window membuka insight itu.

Jika route work, Notes window membuka work item tersebut.

Jika route produk, Store window membuka produk itu.

Jika route audio, Music window membuka category, album, atau track yang sesuai.

Jika route preview, Preview window membuka item tersebut.

Artinya route tidak terpisah dari experience.

Route adalah pemicu experience.

Itulah kenapa model ini terasa lebih bersih daripada penjelasan lama: "SEO page vs window page."


8. Renderer SEO dan Renderer Window Tidak Perlu Dipaksa Jadi Satu

Ini batas yang menurut saya tetap penting.

Sumber konten bisa sama.

Tapi renderer harus menghormati konteksnya.

Renderer Notes window boleh peduli pada pengalaman membaca di dalam window.

Ia boleh peduli pada ritme, lebar panel, scroll behavior, dan mood visual.

Renderer SEO punya tanggung jawab berbeda.

Ia harus menghasilkan article HTML yang semantik.

Heading tetap heading.

Paragraf tetap paragraf.

Table tetap table.

Image punya URL stabil.

Code block tidak membuat mobile melebar.

Blockquote tetap bermakna.

Custom block seperti quote, hadith, atau quran tetap menjadi HTML yang bisa dibaca.

Memaksa renderer window dan renderer SEO menjadi benar-benar sama mungkin terlihat DRY, tapi belum tentu lebih baik.

Kadang "satu renderer untuk semuanya" justru membuat kompromi tersembunyi.

Batas yang lebih sehat adalah:

same content
  -> semantic SEO renderer
  -> desktop window renderer

Dua presentasi.

Satu kebenaran.


9. Sitemap Adalah Peta Formal

Di desktop UI, tidak semua route ditemukan melalui navigasi halaman biasa.

Sebagian konten dibuka lewat dock icon.

Sebagian lewat Spotlight.

Sebagian lewat desktop item.

Sebagian lewat folder.

Sebagian lewat window state.

Itu baik untuk experience.

Tapi crawler tetap butuh peta formal.

Sitemap harus memuat route publik yang nyata:

  • /insights
  • /insights/[slug]
  • /work
  • /work/[slug]
  • /doa
  • /doa/[slug]
  • /quotes
  • /quotes/[author]
  • /quotes/[author]/[quote]
  • /store
  • /store/[category]
  • /store/[category]/[slug]
  • /preview
  • /preview/[slug]
  • /audio
  • route audio category, album, dan track

Poin pentingnya bukan angka priority yang persis.

Poin pentingnya adalah content publik bisa ditemukan tanpa harus memahami metafora desktop.

Sitemap adalah peta formal.

Desktop adalah peta experience.

Keduanya harus menunjuk ke dunia yang sama.


10. Robots dan AI-Readable Files Sebaiknya Membosankan

Saya suka robots rules yang membosankan.

Kalau website ingin diindex, izinkan.

Kalau sitemap ada, arahkan ke sana.

Jangan membuat crawler memecahkan teka-teki.

Hal yang sama berlaku untuk llms.txt dan llms-full.txt.

File itu bukan pengganti HTML yang baik.

File itu bukan pengganti structured data.

File itu adalah peta yang mudah dibaca untuk mesin dan manusia yang ingin memahami website dengan cepat.

Untuk website ini, isinya harus mencakup content publik yang nyata:

  • profile dan about pages.
  • notes dan insights.
  • work.
  • doa.
  • quotes.
  • store products.
  • audio pages.
  • preview items.

Kalau file-file ini tertinggal, manfaatnya berkurang.

Maka file-file itu ikut direvalidate ketika content berubah.

Sekali lagi, intinya adalah keselarasan.

Satu website.

Satu makna publik.

Banyak permukaan.


11. On-Demand Revalidation Membuat Sistem Lebih Tenang

Flow publish content sebaiknya berakhir dengan menyegarkan halaman publik yang bergantung pada content itu.

Untuk notes, artinya route note yang berubah, collection routes, sitemap, llms.txt, dan llms-full.txt.

Untuk produk, artinya product routes, category routes, store index, sitemap, dan AI-readable files.

Untuk desktop items, artinya preview routes dan global content map.

Revalidation endpoint membuat itu mungkin:

publish content
  -> write Firestore / upload assets
  -> call /api/revalidate
  -> refresh affected paths

Ini menghindari dua ekstrem.

Saya tidak perlu rebuild seluruh website untuk setiap edit konten.

Saya juga tidak perlu membuat semua route menjadi SSR hanya supaya fresh.

Konten berubah ketika saya publish.

Static output segar ketika saya minta.

Rasanya ini kadar kontrol yang pas.


12. Apa yang Dilindungi oleh Arsitektur Ini

Tujuannya bukan supaya code terlihat keren.

Tujuannya melindungi website dari masalah-masalah kecil yang diam-diam melelahkan.

Konten tidak boleh terjebak di dalam komponen window.

SEO tidak boleh menjadi halaman terpisah yang pelan-pelan ketinggalan.

Metadata tidak boleh menceritakan versi lama dari artikel.

Sitemap tidak boleh lupa route yang bisa dibuka UI.

AI-readable files tidak boleh menjadi museum asumsi lama.

Build tidak boleh semakin berat hanya karena tulisan bertambah.

Dan desktop experience tidak boleh terlalu playful sampai lupa bahwa di bawahnya tetap ada web.

Keseimbangan itu yang saya coba jaga.

Saya ingin permukaannya terasa hidup.

Tapi struktur di bawahnya tetap membosankan dalam arti terbaik.

Routes.

Metadata.

Semantic HTML.

Sitemap.

Structured data.

Readable content.

Tidak perlu dramatis.

Cukup sistem yang jelas dan bekerja dengan baik.


13. Trade-Off Tetap Perlu Disebut

Arsitektur ini tidak gratis.

Ada publish step tambahan.

Content model harus konsisten.

Butuh revalidation endpoint.

Butuh disiplin supaya renderer SEO dan renderer window tidak saling melenceng.

Artinya juga folder content lokal bukan satu-satunya hal yang penting. Firestore dan Storage menjadi bagian dari cerita publishing.

Tapi menurut saya trade-off ini adil.

Build menjadi lebih ringan.

Content bisa bertumbuh.

UI tetap ekspresif.

Route tetap bermakna.

Dan SEO tidak bergantung pada menyembunyikan versi kedua dari halaman di tempat lain.

Itu cukup bagi saya.


Penutup

Saya masih suka metafora desktop.

Mungkin karena personal website jadi terasa tidak seperti brosur, tapi seperti ruang kecil yang bisa dijelajahi.

Tapi web punya martabatnya sendiri.

URL harus punya makna.

Halaman harus bisa dibaca.

Konten harus bisa dibagikan.

Search engine dan AI crawler tidak seharusnya menebak apa yang tersembunyi di balik interface.

Jadi arsitektur yang sekarang lebih saya percaya bukan "desktop dulu, SEO belakangan."

Melainkan:

one URL
  -> semantic web content
  -> desktop window experience
  -> one content source behind both

Bukan cerita yang terpisah.

Satu cerita, dirender dengan hati-hati.

Sandi Maulana Juhana