Island server
Di halaman ini
Kadang satu bagian dari halaman yang selebihnya statis butuh data segar per permintaan — komentar di bawah pos blog yang disinggahkan, lencana stok di halaman produk. Island server membiarkan halaman tetap statis dan merender hanya bagian itu di server ketika halamannya dilihat.
1. Tulis island-nya
Island adalah modul fragmen di bawah src/islands/ — berkas .js atau .ts biasa (bukan .ht.js, karena island adalah fragmen, bukan halaman). Gagasannya sama seperti di semua tempat lain di sitelo: fungsi yang mengembalikan HTML.
export default async function comments({ props, request }) {
const comments = await fetchComments(props.postId)
return `<ul>${comments.map((c) => `<li>${c.text}</li>`).join('')}</ul>`
}Ia menerima { name, props, request } dan harus mengembalikan string HTML. Modul island hanya untuk server — kode yang tidak dirujuk di bawah src/ tidak pernah sampai ke peramban.
2. Tempatkan di sebuah halaman
Impor island() dari sitelo/islands. Build statis mengirim HTML cadangannya; props disematkan di penampung, jadi buatlah kecil dan bukan rahasia.
import { island } from 'sitelo/islands'
export default ({ params }) => `
<html>
<body>
<article>…konten statis…</article>
${island('comments', { postId: params.slug }, '<p>Memuat komentar…</p>')}
<script type="module" src="/islands.js"></script>
</body>
</html>
`import { html, body, article, script } from 'javascript-to-html'
import { island } from 'sitelo/islands'
export default ({ params }) =>
html(
body(
article('…konten statis…'),
island('comments', { postId: params.slug }, '<p>Memuat komentar…</p>'),
script({ type: 'module', src: '/islands.js' }),
),
)import { island } from 'sitelo/islands'
export default function Post({ params }) {
return (
<html>
<body>
<article>…konten statis…</article>
{island('comments', { postId: params.slug }, '<p>Memuat komentar…</p>')}
<script type="module" src="/islands.js" />
</body>
</html>
)
}3. Tambahkan pemuat klien
Skrip mungil mengambil tiap fragmen hasil render dan menukarnya masuk. Ia melewati jalur aset biasa, jadi entri src/islands.js sederhana sudah cukup:
import { mountIslands } from 'sitelo/islands/client'
mountIslands()Di sitelo (pengembangan) dan sitelo preview ini sudah berfungsi — keduanya menyajikan island di /_sitelo/islands/<name> dari src/islands/. Preview memuat modul .js / .mjs asli (sama seperti host Node); island TypeScript didukung saat pengembangan lewat Vite.
Produksi
Hosting statis Anda tetap menyajikan halamannya. Pasang penangan kecil di mana pun Anda menjalankan kode server — Node, tanpa server, atau fungsi edge — dan ia merender modul island yang sama. Untuk penelusuran lengkap dengan host Node yang bisa dijalankan plus kerangka Netlify dan Vercel, lihat contoh Island server.
// misalnya server Node, atau fungsi serverless/edge
import { createIslandsHandler } from 'sitelo/islands/server'
const handleIslands = createIslandsHandler({
islands: {
comments: () => import('./src/islands/comments.js'),
},
})
// Request web → Response | null (null = bukan permintaan island)
export default { fetch: (request) => handleIslands(request) }Pada Node http biasa atau express, gunakan createIslandsNodeHandler(options) sebagai gantinya — opsi yang sama, tanda tangan (req, res, next). Sambungkan otomatis setiap modul .js / .mjs di bawah src/islands/ dengan createIslandsFromDirectory. Jika pemuat mengambil dari asal atau jalur berbeda, berikan mountIslands({ endpoint: 'https://api.example.com/islands' }) dan cocokkan dengan opsi endpoint pada penangannya.
Daftar periksa kestabilan
island()/mountIslands()/createIslandsHandler/createIslandsNodeHandler— API publik, dianggap stabilsitelodansitelo previewsama-sama menyajikan/_sitelo/islandsdarisrc/islands/createIslandsFromDirectory— peta yang sama untuk host Node dan preview (.js/.mjs/.cjsasli)- Kerangka host di contoh Island server: Node
server.js, fungsi Netlify + penulisan ulang, Vercel tanpa server + penulisan ulang - Props tetap kecil dan bukan rahasia (string kueri GET) — ini disengaja; ambil rahasia di dalam island, di server
- Props berasal dari klien — validasi, atau tanda tangani dengan
SITELO_ISLANDS_SECRET
Strategi pemuatan
Secara bawaan setiap island mengambil begitu halaman dimuat, jadi halaman dengan delapan island membuat delapan permintaan serentak saat lukisan pertama. Berikan when untuk menunda yang tidak langsung terlihat.
// Muat begitu halaman dimuat — bawaannya.
island('cart', { id }, '<p>…</p>')
// Tunggu callback saat menganggur.
island('recommendations', { id }, '<p>…</p>', { when: 'idle' })
// Tunggu sampai tergulir ke tampilan.
island('comments', { postId }, '<p>Memuat komentar…</p>', {
when: 'visible',
rootMargin: '400px', // mulai memuat 400px lebih awal
})'load'(bawaan) — segera, bersama setiap island lain'idle'— padarequestIdleCallback(mundur ke tenggat waktu)'visible'— ketika tergulir ke dalam tampilan, lewat IntersectionObserver
rootMargin hanya berlaku untuk 'visible' dan bawaannya '200px'. Island juga kehabisan waktu alih-alih berputar selamanya:
mountIslands({
timeout: 5000, // per island; 0 menonaktifkan. Bawaan 10000
rootMargin: '300px', // bawaan untuk island `when: 'visible'`
})mountIslands() selesai begitu island langsung sudah tenang — yang ditunda dimuat belakangan sendiri dan sengaja tidak ditunggu. Island yang gagal atau kehabisan waktu mempertahankan HTML cadangannya.
Props adalah masukan tak tepercaya
Props island berasal dari klien. Mereka disematkan di halaman, dikirim balik pada permintaan, dan siapa pun bisa menyuntingnya lebih dulu:
GET /_sitelo/islands/profile?props={"userId":"someone-else"}Perlakukan props yang diterima island Anda persis seperti parameter kueri — validasi, dan jangan pernah memakainya untuk mencari data yang memang belum berhak dilihat pengunjung.
Ketika props memilih data istimewa, tanda tangani. Setel sebuah rahasia dan sitelo menandatangani setiap penampung saat build, menolak yang lain dengan 403:
SITELO_ISLANDS_SECRET=$(openssl rand -hex 32) sitelo buildVariabel yang sama dibaca oleh sitelo, sitelo preview, dan createIslandsHandler, jadi pengembangan, preview, dan produksi sepakat. Beri host produksi Anda rahasia yang sama. Lebih suka menyetelnya di kode?
import { configureIslands } from 'sitelo/islands'
configureIslands({ secret: process.env.MY_SECRET })Tanda tangan berupa HMAC-SHA256 atas nama island dan props-nya, jadi tanda tangan yang diterbitkan untuk satu island tidak bisa diputar ulang terhadap island lain. Penandatanganan membuktikan props berasal dari build Anda — ia tidak menyembunyikannya, jadi props tetap harus bukan rahasia. Tanpa rahasia, props diterima apa adanya dan memvalidasinya sepenuhnya menjadi tugas modul island Anda.
Baik untuk diketahui
- Belum menerapkan endpoint island? HTML cadangan cukup tetap di tempatnya — halaman merosot dengan anggun.
- Permintaannya berupa
GETdengan props di string kueri, jadi responsnya bisa disinggahkan — setel opsicacheControlpada penangan jika Anda ingin CDN menahan fragmen sebentar. - Selagi memuat, penampung membawa
data-sitelo-island-state="loading"(laluloadedatauerror) — praktis untuk CSS.