SEO Deployment SvelteKit: Adapter, Prerender, dan Rendering Edge

Adapter SvelteKit dan pengaturan prerender per rute menentukan di mana dan kapan halaman dirender—yang memengaruhi TTFB, LCP, serta anggaran crawling. Pembahasan deployment yang mendalam ini mencakup pemilihan adapter-static/node/vercel/cloudflare/netlify, prerender = true/false/'auto', batasan runtime edge, serta pembuatan sitemap.xml dan robots.txt.

Adapter SvelteKit dan pengaturan prerender per rute menentukan di mana dan kapan halaman dirender—HTML statis pada waktu build, SSR di server, atau SSR pada edge—dan keputusan tersebut memengaruhi TTFB, yang berdampak pada LCP serta kapasitas crawling. Pilih adapter-static untuk situs konten murni; gunakan adapter node/vercel/cloudflare dengan prerender per rute untuk situs campuran konten dan aplikasi; dan gunakan adapter edge ketika TTFB global penting, sambil menerima inisialisasi dingin serta ketiadaan fs Node. prerender = 'auto' adalah alat untuk situs campuran. Runtime edge tidak dapat membaca sistem berkas. SvelteKit juga tidak menghasilkan sitemap.xml atau robots.txt—Anda membuatnya sebagai endpoint +server.js dengan strategi yang bergantung pada adapter.

TL;DR — Adapter tidak mengubah apa yang dirender SvelteKit—adapter mengubah di mana dan kapan: statis pada waktu build (adapter-static), saat diminta pada server yang Anda jalankan (adapter-node), atau saat diminta pada fungsi serverless/edge (adapter-vercel/-netlify/-cloudflare). prerender = true per rute membangun HTML statis dan menghapus rute dari manifest dinamis; prerender = 'auto' melakukan prerender dan tetap menyimpannya dalam manifest—alat untuk situs campuran /blog/[slug]. Runtime edge berjalan pada isolate V8: tidak ada fs Node, dan inisialisasi dingin merugikan TTFB, yang berdampak pada LCP serta (menurut dokumen anggaran crawling Google) kapasitas crawling. SvelteKit tidak menghasilkan sitemap.xml atau robots.txt—buat keduanya sebagai endpoint +server.js, dan perhatikan bahwa strateginya bergantung pada adapter. Artikel ini adalah pendamping yang lebih sempit dan berfokus pada deployment untuk artikel dasar-dasar SEO SvelteKit di bagian ini; saya menganggap Anda sudah tahu bahwa SvelteKit secara default menggunakan SSR dan tidak akan memperdebatkan hal itu lagi di sini.

Satu gagasan yang membuat semuanya mudah dipahami

Adapter tidak mengubah apa yang dirender. Adapter mengubah di mana dan kapan. Sesederhana itu. Dokumentasi SvelteKit menjelaskannya dengan tepat: adapter “take the built app as input and generate output for deployment.” (terjemahan) «mengambil aplikasi hasil build sebagai input dan menghasilkan keluaran untuk deployment.» Bukti untuk klaim ini SvelteKit adapters take the built application as input and generate deployment-specific output. Cakupan: Deployment output; adapter choice can still constrain supported runtime features. Tingkat keyakinan: tinggi · Diverifikasi: SvelteKit: Adapters Komponen, fungsi load, dan metadata <svelte:head> Anda sama persis pada setiap adapter. Perbedaannya adalah:

  • Kapan HTML dihasilkan: pada waktu build (statis/prerender) atau pada waktu permintaan (SSR di server, fungsi serverless, atau fungsi edge).
  • Di mana HTML dihasilkan: di satu server asal, fungsi serverless regional, atau jaringan edge yang dekat dengan pengunjung.

Semua hal di bawah ini merupakan akibat dari kedua sumbu tersebut.

Mengapa pilihan deployment merupakan pilihan SEO

Rantainya pendek dan terdokumentasi dengan baik: TTFB → LCP → kapasitas crawling.

Waktu hingga byte pertama adalah waktu yang diperlukan penyedia hosting untuk mulai mengirimkan respons. Berkas hasil prerender yang disajikan dari cache CDN memiliki TTFB yang mendekati nol. Peladen yang harus merender halaman memiliki TTFB lebih tinggi. Fungsi serverless atau edge yang mengalami inisialisasi dingin dapat memiliki TTFB yang jauh lebih tinggi pada kunjungan pertama. TTFB merupakan masukan langsung bagi Largest Contentful Paint—Anda tidak dapat menampilkan sesuatu yang belum diterima—dan LCP adalah sinyal Core Web Vitals.

Pada sisi crawling, penjelasan Google paling tegas. Dari dokumentasi anggaran crawling: “If the site responds quickly for a while, the limit goes up, meaning more connections can be used to crawl. If the site slows down or responds with server errors, the limit goes down and Google crawls less.” (terjemahan) «Jika situs merespons dengan cepat selama beberapa waktu, batasnya naik sehingga lebih banyak koneksi dapat digunakan untuk merayapi. Jika situs melambat atau merespons dengan error server, batasnya turun dan Google merayapi lebih sedikit.» Lalu baris praktik terbaiknya: “Make your pages efficient to load. If Google can load and render your pages faster, we might be able to read more content from your site.” (terjemahan) «Buat halaman Anda efisien untuk dimuat. Jika Google dapat memuat dan merender halaman Anda lebih cepat, kami mungkin dapat membaca lebih banyak konten dari situs Anda.» Fungsi edge dengan inisialisasi dingin yang lambat merespons menghadapi dinamika yang sama seperti server asal yang lambat.

Satu catatan kejujuran sejak awal: Google tidak menerbitkan panduan khusus SvelteKit. Tidak ada dokumen atau episode Search Off the Record yang menyebut adapter SvelteKit, prerender = 'auto', atau inisialisasi dingin pada edge. Di sini saya menerapkan panduan umum Google tentang rendering dan anggaran crawling pada mekanisme khusus SvelteKit—bukan mengutip perwakilan Google yang mengomentari SvelteKit karena memang tidak ada. Pernyataan Google bahwa “server-side or pre-rendering is still a great idea because it makes your website faster for users and crawlers, and not all bots can run JavaScript” (terjemahan) «rendering sisi server atau prerender tetap merupakan gagasan yang sangat baik karena membuat situs Anda lebih cepat bagi pengguna dan perayap, serta tidak semua bot dapat menjalankan JavaScript» adalah landasan resmi yang paling dekat, dan berlaku lintas framework.

Memilih adapter untuk hasil SEO

adapter-auto—pilihan default tanpa konfigurasi dan batasannya

Proyek SvelteKit baru dilengkapi dengan adapter-auto. Adapter ini mendeteksi platform—Vercel, Netlify, Cloudflare Pages, Azure, atau AWS—lalu memasang adapter yang sesuai pada waktu build. Ini merupakan titik awal yang baik, tetapi ada batas tegas yang perlu diketahui: adapter-auto “does not take any options.” (terjemahan) «tidak menerima opsi apa pun.» Begitu Anda memerlukan { edge: true }, binding Cloudflare, ISR Vercel, atau konfigurasi khusus platform apa pun, pasang adapter dasarnya (adapter-vercel, adapter-cloudflare, dan seterusnya) secara langsung. Perlakukan auto sebagai kerangka awal, bukan keputusan produksi.

adapter-static—SSG penuh untuk situs yang mengutamakan konten

adapter-static melakukan prerender pada seluruh situs Anda menjadi berkas statis pada waktu build. Tidak ada peladen yang berjalan; penyedia hosting menyajikan HTML datar. Bukti untuk klaim ini adapter-static prerenders a SvelteKit site as static files. Cakupan: Routes must be prerenderable; performance outcomes depend on hosting and page design. Tingkat keyakinan: tinggi · Diverifikasi: SvelteKit: Static site generation Untuk situs yang mengutamakan konten, inilah profil SEO terkuat yang bisa Anda dapatkan—TTFB terendah, tanpa inisialisasi dingin, dan tidak ada proses yang dapat tumbang. Satu persyaratannya adalah jebakan yang dibahas panjang dalam artikel dasar-dasar: SSR harus tetap aktif selama build, atau Anda akan mendapat kerangka kosong alih-alih HTML yang sudah dirender. Saya tidak akan mengulang penjelasannya di sini selain menandainya.

Kekurangannya adalah kekakuan. Apa pun yang benar-benar memerlukan logika server pada setiap permintaan (pencarian sungguhan, konten per pengguna, penanganan formulir tanpa endpoint pihak ketiga) tidak dapat berada dalam build yang sepenuhnya statis—dan itulah kegunaan adapter berikutnya.

adapter-node—server yang Anda kendalikan

adapter-node menghasilkan server Node.js mandiri. Anda menjalankannya, menskalakannya, dan bertanggung jawab atas TTFB-nya. Ini adalah opsi paling fleksibel dengan paling sedikit kejutan saat runtime—API Node lengkap, termasuk fs. Opsi ini cocok bila Anda sudah memiliki infrastruktur, membutuhkan pustaka Node yang tidak dapat berjalan di runtime edge, atau menginginkan waktu respons yang dapat diprediksi (tanpa inisialisasi dingin) dari server yang sudah hangat. Konsekuensinya bersifat operasional: Anda menjalankan server, dan kecepatan serta waktu aktifnya kini menjadi kapasitas crawling Anda.

adapter-vercel—serverless, edge, dan ISR

Secara default, adapter-vercel melakukan deployment ke fungsi serverless Vercel, dengan beberapa kendali yang relevan bagi SEO dan ditetapkan per rute melalui export const config:

  • runtime: 'edge' memindahkan rute tersebut ke runtime edge Vercel (selengkapnya di bawah).
  • regions mengendalikan lokasi fungsi serverless berjalan—lebih dekat ke pengguna (atau basis data) berarti latensi lebih rendah.
  • isr mengaktifkan Incremental Static Regeneration: isr: { expiration: 60 } menyajikan aset statis dari cache lalu menghasilkannya kembali setelah interval tersebut, sehingga memberi “the performance and cost advantages of prerendered content with the flexibility of dynamically rendered content.” (terjemahan) «keunggulan kinerja dan biaya dari konten hasil prerender dengan fleksibilitas konten yang dirender secara dinamis.» ISR merupakan jalur keempat yang nyata di antara sepenuhnya statis dan sepenuhnya SSR—tetapi perhatikan peringatan dokumentasinya sendiri: “Using ISR on a route with export const prerender = true will have no effect, since the route is prerendered at build time.” (terjemahan) «Menggunakan ISR pada rute dengan export const prerender = true tidak akan berpengaruh karena rute tersebut sudah diprerender pada waktu build.» ISR dan prerender adalah alternatif, bukan sesuatu yang dapat ditumpuk.

adapter-cloudflare—Workers/Pages dan edge global

adapter-cloudflare ditujukan untuk Cloudflare Workers dan Pages—SSR pada jaringan edge global, yang sering memberi TTFB terendah untuk audiens yang tersebar secara geografis. Batasan pentingnya adalah runtime: Workers berjalan di isolate V8, bukan Node. Menurut dokumentasi: “You can’t use fs in Cloudflare Workers.” (terjemahan) «Anda tidak dapat menggunakan fs di Cloudflare Workers.» Sejumlah API Node hanya berfungsi dengan flag kompatibilitas nodejs_compat, dan sekalipun demikian dukungannya tidak satu banding satu. Jika Anda membaca berkas pada waktu permintaan (peta pengalihan, berkas data, input gambar OG khusus), kode tersebut perlu dipikirkan ulang—hal ini dibahas dalam bagian edge di bawah.

(adapter-cloudflare-workers yang lebih lama sudah tidak digunakan lagi; proyek baru memakai adapter-cloudflare, yang menangani Workers dan Pages. Jika Anda masih menggunakan adapter lama, migrasi adalah jalur yang disarankan.)

adapter-netlify—fungsi atau Edge Functions (Deno)

Secara default, adapter-netlify melakukan deployment ke fungsi Netlify berbasis Node, atau ke Edge Functions berbasis Deno dengan edge: true. Polanya sama seperti Vercel: serverless secara default dengan edge sebagai pilihan. Ada satu catatan khusus SvelteKit—Netlify Forms mengharuskan halaman formulir diprerender agar Netlify dapat mendeteksi markup formulir pada waktu deployment. Ini merupakan persyaratan kecil “lakukan prerender pada rute ini” yang ditambahkan di atas pilihan adapter.

Keputusan untuk setiap kasus, masing-masing dalam satu baris

  • Situs konten murni → adapter-static, lakukan prerender pada semuanya.
  • Situs konten dengan beberapa bagian dinamis → adapter-node/-vercel/-cloudflare, gunakan prerender = true untuk konten dan false/'auto' untuk rute dinamis.
  • Aplikasi/dasbor dengan personalisasi → utamakan SSR (node atau edge), dan lakukan prerender hanya pada kerangka statis (pemasaran, login).
  • Audiens global yang sangat mengutamakan TTFB → gunakan adapter edge untuk rute dinamis sambil menerima batasan API Node dan kenyataan inisialisasi dingin.

(Tab Pohon Keputusan memandu Anda melewati pilihan ini sebagai alur bercabang.)

Strategi prerender untuk situs campuran

Apa yang sebenarnya dilakukan true / false / 'auto'

export const prerender adalah opsi halaman per rute (atau per layout), dan ketiga nilainya tidak sekadar aktif/nonaktif:

  • true—bangun rute ini menjadi HTML statis pada waktu build. Yang terpenting, rute tersebut “excluded from manifests used for dynamic SSR, making your server (or serverless/edge functions) smaller.” (terjemahan) «dikecualikan dari manifest yang digunakan untuk SSR dinamis sehingga server (atau fungsi serverless/edge) Anda menjadi lebih kecil.» Setelah diprerender, rute tersebut tidak dapat beralih kembali ke rendering dinamis—rute itu sepenuhnya statis.
  • false—selalu render ketika diminta. Tidak ada berkas statis.
  • 'auto'—alat untuk situs campuran. Nilai ini melakukan prerender pada rute dan mempertahankannya dalam manifest server dinamis, sehingga rute yang sama dapat disajikan secara statis bagi path yang diketahui dan dirender di server bagi path lainnya. Fitur ini dibuat tepat untuk kasus yang dijelaskan dokumentasi: rute seperti /blog/[slug] “where you want to prerender your most recent/popular content but server-render the long tail.” (terjemahan) «ketika Anda ingin melakukan prerender pada konten terbaru atau terpopuler, tetapi merender long tail di server.»

Karena rute hasil prerender memperkecil bundle server, situs yang sebagian besar diprerender dengan beberapa rute 'auto'/false akan menerapkan fungsi yang lebih kecil, murah, dan cepat—keuntungan efisiensi yang berdiri sendiri di luar SEO.

Rute dinamis memerlukan fungsi entries

Perayap prerender menemukan halaman dengan mengikuti tautan <a> dari titik masuk Anda. Cara ini berfungsi untuk rute statis, tetapi rute dinamis seperti /blog/[slug] tidak memiliki URL tetap yang dapat ditemukan perayap. Jika tidak ada yang menautkan ke slug tertentu, SvelteKit tidak akan mengetahui bahwa slug tersebut ada—dan Anda akan menemui error build klasik bahwa rute “were marked as prerenderable, but were not prerendered.” (terjemahan) «ditandai sebagai dapat diprerender, tetapi tidak diprerender.»

Solusinya adalah fungsi entries eksplisit (atau config.kit.prerender.entries) yang mencantumkan nilai parameter:

// src/routes/blog/[slug]/+page.server.js
export const prerender = true;

export function entries() {
  return [
    { slug: 'hello-world' },
    { slug: 'sveltekit-deployment-seo' },
  ];
}

Dalam praktiknya, Anda menghasilkan daftar tersebut dari CMS atau direktori konten. Tanpanya, prerender hanya mencakup slug yang kebetulan ditemukan oleh perayap tautan.

Pola /blog/[slug] dalam penggunaan nyata

Gabungkan keduanya untuk mendapatkan penyiapan baku situs campuran: prerender = 'auto' ditambah fungsi entries yang mengembalikan postingan terbaru dan populer. Postingan tersebut mendapatkan HTML statis pada waktu build; apa pun yang tidak ada dalam daftar akan beralih ke SSR sesuai permintaan. Postingan baru dirender secara dinamis sampai build berikutnya melakukan prerender. Ini adalah jalan tengah yang pragmatis antara “lakukan prerender pada semua 40,000 postingan setiap kali build” dan “render setiap postingan pada setiap permintaan”.

Batasan runtime edge yang memengaruhi SEO

config.runtime = 'edge' berlaku per rute (di Vercel)

Edge bukan pilihan yang harus diterapkan ke semuanya atau tidak sama sekali. Di Vercel, edge adalah opsi halaman per rute:

// +page.server.js or +server.js
export const config = { runtime: 'edge' };

Artinya, Anda dapat mendorong rute yang ramai dan dapat disimpan dalam cache ke edge untuk memperoleh TTFB rendah, sementara rute yang bergantung pada Node tetap menggunakan runtime serverless standar (Node) dalam deployment yang sama. Padukan keduanya dengan sengaja.

Tanpa fs, tanpa API Node sembarang

Runtime edge—Cloudflare Workers, Vercel Edge Functions, dan Edge Functions berbasis Deno milik Netlify—tidak menyediakan fs Node. Dokumentasi Cloudflare: “You can’t use fs in Cloudflare Workers.” (terjemahan) «Anda tidak dapat menggunakan fs di Cloudflare Workers.» Dokumentasi Vercel: “You can’t use fs in edge functions.” (terjemahan) «Anda tidak dapat menggunakan fs dalam fungsi edge.» Keduanya menunjukkan dua jalan keluar yang sama: gunakan helper read dari $app/server untuk mengakses aset yang dibundel, atau “prerender the routes in question” (terjemahan) «lakukan prerender pada rute yang dimaksud» agar akses berkas terjadi pada waktu build, bukan pada waktu permintaan.

Kasus yang berkaitan dengan SEO dan terdampak oleh batasan ini meliputi pembuatan gambar OG dinamis yang membaca berkas font atau templat, peta pengalihan berbasis berkas, atau endpoint sitemap yang membaca konten dari disk. Semua itu harus beralih ke helper $app/server bernama read() atau dipindahkan ke waktu prerender/build. Ini bukan penghambat—melainkan batasan yang harus diketahui sebelum memilih edge.

Cold start dan TTFB—kapan edge membantu dan kapan tidak

Fungsi edge tetap mengalami inisialisasi dingin. Fungsi edge yang dingin pada permintaan pertamanya dapat lebih lambat daripada server Node yang hangat, dan jauh lebih lambat daripada berkas hasil prerender yang disajikan dari cache. Edge unggul ketika fungsi tetap hangat atau ketika dipadukan dengan caching agresif sehingga sebagian besar permintaan tidak pernah mencapai fungsi tersebut. Edge tidak secara otomatis menjadi opsi tercepat—“melakukan deployment ke edge” tidak sama artinya dengan “lebih cepat”. Untuk situs konten, keluaran statis hasil prerender selalu mengalahkan SSR edge dalam TTFB karena tidak ada fungsi yang harus dimulai.

Menghasilkan sitemap.xml dan robots.txt (SvelteKit tidak melakukannya)

Inilah celah yang dilewatkan oleh sebagian besar tutorial SvelteKit dan ditemukan oleh sebagian besar audit. SvelteKit tidak menghasilkan sitemap.xml dan tidak menghasilkan robots.txt secara otomatis—apa pun adapternya dan berapa pun jumlah halaman yang Anda prerender. Situs yang sepenuhnya statis dengan ribuan halaman hasil prerender tetap dikirim tanpa sitemap kecuali Anda membuatnya.

Pola endpoint +server.js

Sitemap idiomatis berupa endpoint rute yang mengembalikan XML dengan Content-Type yang tepat:

// src/routes/sitemap.xml/+server.js
export const prerender = true; // needed on adapter-static

export async function GET() {
  const urls = await getAllUrls(); // from your CMS/content
  const body = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${urls.map((u) => `  <url><loc>${u}</loc></url>`).join('\n')}
</urlset>`;

  return new Response(body, {
    headers: { 'Content-Type': 'application/xml' },
  });
}

Strateginya bergantung pada adapter Anda

Inilah bagian yang menyatukan seluruh artikel ini: strategi sitemap Anda merupakan kelanjutan dari pilihan adapter.

  • Pada adapter-static, endpoint sitemap memerlukan export const prerender = true agar disertakan dalam keluaran statis—tidak ada server saat runtime untuk menghasilkannya ketika diminta. Sitemap dibentuk pada waktu build sehingga hanya akan semutakhir build terakhir Anda.
  • Pada adapter Node/serverless/edge, endpoint yang sama dapat menghasilkan sitemap secara dinamis pada setiap permintaan dari CMS atau basis data—selalu mutakhir tanpa memerlukan build ulang. (Pada adapter edge, ingat batasan fs: ambil URL dari API atau binding, bukan dengan membaca disk.)

Jadi, pertanyaan “haruskah sitemap saya statis atau dinamis?” bukan keputusan terpisah—jawabannya mengikuti adapter yang sudah Anda pilih.

robots.txt: berkas statis atau endpoint

Ada dua pilihan. Taruh robots.txt biasa dalam folder static/ (otomatis disajikan di /robots.txt), yang merupakan pilihan paling sederhana dan cocok untuk sebagian besar situs. Atau, hasilkan berkas itu dari endpoint src/routes/robots.txt/+server.js bila isinya perlu berbeda menurut lingkungan (misalnya memblokir perayap di staging dan mengizinkannya di produksi). Apa pun pilihannya, jangan blokir bundle /_app/ atau CSS Anda—tindakan itu merusak rendering bagi mesin yang memang melakukan rendering.

Jika Anda melihatnya dari sudut pandang SEO framework atau SEO JavaScript yang lebih luas, logika “di mana dan kapan rendering terjadi” di sini sama dengan logika yang mengatur SEO JavaScript secara umum. Artikel dasar-dasar SvelteKit di bagian ini membahas mode rendering dan pola metadata yang menjadi landasan artikel ini.

Tambahkan catatan pakar

Sematkan kutipan pakar

Orang baru? Buat profilnya yang belum diklaim di /admin/experts/ → Sematkan kutipan pakar terlebih dahulu.