Sunucu adaları
Bu sayfada
sitelo statik HTML kurar. Sunucu adaları taze olması gereken parçaları doldurur — bir saat, yorumlar, stok, isteğe ihtiyaç duyan her şey. Bu tarif bir zaman adası olan bir sayfa kurar, sonra dist/ ve /_sitelo/islands adreslerini sunan küçük bir Node sunucusu çalıştırır.
Bu projenin bir kopyası sitelo deposunda examples/islands/ altında bulunur.
Elinize geçenler
- Ada yer tutucusu ve yedek HTML içeren statik bir ana sayfa
src/islands/altında, tarayıcıya hiç gönderilmeyen, yalnızca sunucuya ait bir ada modülü- Parçayı
/_sitelo/islands/<name>adresinden alıp yerine koyan bir istemci yükleyicisi - Üretim biçiminde bir
server.js— statik dosyalar +createIslandsNodeHandler
Proje düzeni
my-site/
sitelo.config.js
server.js # Node sunucusu: statik dist + adalar
netlify.toml # Netlify yeniden yazımı → function
vercel.json # Vercel yeniden yazımı → api rotası
package.json
netlify/functions/
islands.mjs # Netlify ada işleyicisi
api/islands/
[...path].js # Vercel ada işleyicisi
src/
index.ht.js # ada yer tutucusu olan sayfa
js/
islands.js # istemci yükleyicisi (dist/ içine paketlenir)
islands/
time.js # yalnızca sunucuda çalışan parça modülü
css/
styles.cssexport default {
site: 'https://example.com',
}1. Ada modülü
Düz .js (.ht.js değil). { name, props, request } alır ve bir HTML dizesi döndürür. Bu ada, her istekte işlendiğini görebilmeniz için istek zamanını ve tarayıcı kimliğini kullanır.
export default function time({ props, request }) {
const label = typeof props?.label === 'string' ? props.label : 'Sunucu saati'
const now = new Date().toISOString()
const ua = request?.headers?.get?.('user-agent') ?? 'unknown'
return `
<p><strong>${label}:</strong> <time datetime="${now}">${now}</time></p>
<p class="muted">İstek üzerine şunun için işlendi: <code>${escapeHtml(ua.slice(0, 48))}</code></p>
`
}
function escapeHtml(value) {
return value
.replaceAll('&', '&')
.replaceAll('<', '<')
.replaceAll('>', '>')
.replaceAll('"', '"')
}2. Adayı bir sayfaya yerleştirin
island() propları yer tutucuya gömer. Derleme yedeği yayımlar; uç nokta yanıt verdiğinde yükleyici onu değiştirir.
import { island } from 'sitelo/islands'
export default () => `
<html lang="tr">
<head>
<title>Sunucu adaları demosu</title>
<link rel="stylesheet" href="/css/styles.css">
</head>
<body>
<h1>Statik sayfa, canlı ada</h1>
<p>Bu HTML bir kez derlendi. Aşağıdaki kutu istek anında doldurulur.</p>
${island(
'time',
{ label: 'Şu anda' },
'<p>Sunucu saati yükleniyor…</p>',
)}
<script type="module" src="/js/islands.js"></script>
</body>
</html>
`import { html, head, title, link, body, h1, p, script } from 'javascript-to-html'
import { island } from 'sitelo/islands'
export default () =>
html({ lang: 'tr' },
head(
title('Sunucu adaları demosu'),
link({ rel: 'stylesheet', href: '/styles.css' }),
),
body(
h1('Statik sayfa, canlı ada'),
p('Bu HTML bir kez derlendi. Aşağıdaki kutu istek anında doldurulur.'),
island(
'time',
{ label: 'Şu anda' },
'<p>Sunucu saati yükleniyor…</p>',
),
script({ type: 'module', src: '/islands.js' }),
),
)import { island } from 'sitelo/islands'
export default function Home() {
return (
<html lang="tr">
<head>
<title>Sunucu adaları demosu</title>
<link rel="stylesheet" href="/css/styles.css" />
</head>
<body>
<h1>Statik sayfa, canlı ada</h1>
<p>Bu HTML bir kez derlendi. Aşağıdaki kutu istek anında doldurulur.</p>
{island(
'time',
{ label: 'Şu anda' },
'<p>Sunucu saati yükleniyor…</p>',
)}
<script type="module" src="/js/islands.js" />
</body>
</html>
)
}3. İstemci yükleyicisi
import { mountIslands } from 'sitelo/islands/client'
mountIslands()body {
font-family: system-ui, sans-serif;
max-width: 36rem;
margin: 2rem auto;
padding: 0 1rem;
line-height: 1.5;
}
[data-sitelo-island] {
margin: 1.5rem 0;
padding: 1rem 1.25rem;
border: 1px solid #ccc;
}
[data-sitelo-island-state='loading'] {
opacity: 0.7;
}
.muted {
color: #666;
font-size: 0.9rem;
}4. Node sunucusu
sitelo build sonrasında bu süreç dist/ dizinini sunar ve adaları sitelo/islands/server içindeki createIslandsNodeHandler ile işler. Ada modülleri dist/ dışında kalır — sunucu onları src/ içinden içe aktarır.
import fs from 'node:fs'
import http from 'node:http'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import { createIslandsFromDirectory, createIslandsNodeHandler } from 'sitelo/islands/server'
const root = path.dirname(fileURLToPath(import.meta.url))
const dist = path.join(root, 'dist')
const port = Number(process.env.PORT) || 3000
const handleIslands = createIslandsNodeHandler({
islands: createIslandsFromDirectory(path.join(root, 'src/islands')),
})
const MIME = {
'.html': 'text/html; charset=utf-8',
'.js': 'text/javascript; charset=utf-8',
'.css': 'text/css; charset=utf-8',
'.svg': 'image/svg+xml',
'.png': 'image/png',
'.ico': 'image/x-icon',
'.xml': 'application/xml',
'.json': 'application/json',
}
function sendFile(res, filePath) {
const ext = path.extname(filePath)
res.statusCode = 200
res.setHeader('Content-Type', MIME[ext] ?? 'application/octet-stream')
fs.createReadStream(filePath).pipe(res)
}
function resolveStatic(urlPath) {
const clean = decodeURIComponent(urlPath.split('?')[0])
const relative = clean === '/' ? 'index.html' : clean.replace(/^\/+/, '')
const candidate = path.normalize(path.join(dist, relative))
if (!candidate.startsWith(dist + path.sep) && candidate !== dist) {
return null
}
if (fs.existsSync(candidate) && fs.statSync(candidate).isFile()) {
return candidate
}
const asIndex = path.join(candidate, 'index.html')
if (fs.existsSync(asIndex) && fs.statSync(asIndex).isFile()) {
return asIndex
}
return null
}
const server = http.createServer(async (req, res) => {
await handleIslands(req, res, () => {
const file = resolveStatic(req.url ?? '/')
if (file) {
sendFile(res, file)
return
}
const notFound = path.join(dist, '404.html')
res.statusCode = 404
if (fs.existsSync(notFound)) {
sendFile(res, notFound)
} else {
res.setHeader('Content-Type', 'text/plain; charset=utf-8')
res.end('Bulunamadı')
}
})
})
server.listen(port, () => {
console.log(`Dinleniyor: http://localhost:${port}`)
})5. Derleyin ve çalıştırın
npm install
sitelo build
node server.jshttp://localhost:3000 adresini açın. Kısa bir an yedeği, sonra sunucu saatini görmelisiniz. Yenileyin — zaman damgası değişir. sitelo (geliştirme) ve sitelo preview içinde server.js gerekmez: CLI /_sitelo/islands adresini zaten sunar.
Dağıtım
Bu örnek, Node sunucusunun yanında sunucu taslaklarıyla gelir:
Node—npm run build && npm start(platformdaPORTayarlayın).createIslandsFromDirectorykullanır.Netlify—netlify.toml,/_sitelo/islands/*adresininetlify/functions/islands.mjsdosyasına yeniden yazar.Vercel—vercel.json,api/islands/[...path].jsdosyasına yeniden yazar.- Yalnızca statik sunucular (GitHub Pages, düz S3) — siz bir fonksiyon ekleyene dek yer tutucular yedeklerini korur.
Başka yerlerde sunucusuz ya da kenar için createIslandsHandler kullanın (web Request → Response) — bkz. Sunucu adaları belgeleri. Aynı kaynakta değilse mountIslands({ endpoint }) ifadesini o fonksiyonun URL’ine yöneltin.
Notlar
Tek başına statik sunucular
GitHub Pages, düz S3 ve benzeri sunucuların bir sunucu süreci yoktur. Ada uç noktası olmadan yedek HTML olduğu gibi kalır — sayfalar yine çalışır, yalnızca canlı parça olmadan.
Propları küçük tutun
Proplar HTML özniteliğinde ve istek sorgu dizesinde yolculuk eder. Oraya sır ya da büyük yükler koymayın — onları adanın içinde, sunucuda getirin.
Sunucu adaları belgeleri · Temel site / dağıtım · Tüm örnekler