Carga de datos
Exporta una función data() y su resultado aparecerá como ctx.data en tu función de renderizado. Se ejecuta en tiempo de compilación, y en cada petición en el servidor de desarrollo.
export async function data({ params, dev }) {
const res = await fetch(`https://api.example.com/posts/${params.slug}`)
return await res.json()
}
export default ({ data }) => `
<html><body>
<h1>${data.title}</h1>
${data.body}
</body></html>
`import { html, body, h1 } from 'javascript-to-html'
export async function data({ params, dev }) {
const res = await fetch(`https://api.example.com/posts/${params.slug}`)
return await res.json()
}
export default ({ data }) =>
html(
body(
h1(data.title),
data.body,
),
)export async function data({ params, dev }) {
const res = await fetch(`https://api.example.com/posts/${params.slug}`)
return await res.json()
}
export default function Post({ data }) {
return (
<html>
<body>
<h1>{data.title}</h1>
<div dangerouslySetInnerHTML={{ __html: data.body }} />
</body>
</html>
)
}fetchWithCache
¿Generas muchas páginas contra la misma API? Importa fetchWithCache desde sitelo:
import { fetchWithCache } from 'sitelo'
export async function data({ params }) {
const res = await fetchWithCache(
`https://api.example.com/posts/${params.slug}`,
{ /* opciones estándar de fetch */ },
{ maxAge: 3600 }
)
return { post: await res.json() }
}Opciones
maxAge— TTL de la caché en segundos (por defecto3600)cacheKey— clave propia (por defecto: hash de URL + método + cabeceras + cuerpo)forceRefresh— ignora la cachécache—'auto'|'memory'|'fs'|'none'
Modos de caché
auto(por defecto) — memoria en desarrollo, sistema de archivos en compilaciones de producciónmemory— en el propio proceso; se borra al terminar el procesofs— persistido ennode_modules/.cache/none— siempre hace la petición
Por defecto solo se cachean las peticiones GET (pasa un cacheKey para cachear otros métodos). Las respuestas de error nunca se cachean.
Archivos JSON locales
¿Sin API? Guarda el contenido en el repositorio como JSON y léelo con sitelo/data.
data/
├─ site.json
└─ posts/
├─ hello-world.json
└─ why-static.jsonimport { readJsonCollection } from 'sitelo/data'
const posts = () => readJsonCollection('data/posts', { sort: '-date' })
export async function generateStaticParams() {
return (await posts()).map((post) => ({ slug: post.slug }))
}
export async function data({ params }) {
return (await posts()).find((post) => post.slug === params.slug)
}
export default ({ data }) => `
<html><body>
<h1>${data.title}</h1>
<time datetime="${data.date}">${data.date}</time>
${data.body}
</body></html>
`Las rutas relativas se resuelven desde la raíz del proyecto, así que data/posts significa lo mismo desde donde sea que ejecutes la CLI. readJson devuelve un archivo ya analizado; readJsonCollection devuelve un array de entradas, cada una con su slug — desde un directorio de archivos .json (uno por entrada, con el slug tomado del nombre del archivo) o desde un único archivo con un array de entradas o un objeto indexado por slug.
// data/posts/hello-world.json -> { slug: 'hello-world', ... }
await readJsonCollection('data/posts')
// data/posts.json: [{ "slug": "hello-world", ... }]
// data/posts.json: { "hello-world": { ... } }
await readJsonCollection('data/posts.json')
// data/site.json
await readJson('data/site.json')Opciones de la colección
slug— nombre de campo o función; por defecto el nombre del archivo, la clave del objeto, o elslug/idde la propia entradasort— nombre de campo ('date'ascendente,'-date'descendente) o una función de comparaciónrecursive— incluye archivos.jsonde subdirectorios, con su ruta como slugroot— directorio desde el que se resuelven las rutas relativascache—'auto'|'memory'|'none'
Las lecturas se memorizan por archivo, así que una compilación de 500 páginas analiza cada archivo una sola vez. El servidor de desarrollo comprueba la mtime en su lugar y recarga el navegador cuando cambia un archivo JSON que alguna página leyó. Los slugs duplicados, los archivos que faltan y el JSON mal formado hacen fallar la compilación, cada uno con su ruta.