数据加载
导出一个 data() 函数,它的结果会作为 ctx.data 出现在渲染函数里。它在构建时运行,在开发服务器中则每次请求都会运行。
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
要基于同一个 API 生成很多页面?从 sitelo 引入 fetchWithCache:
import { fetchWithCache } from 'sitelo'
export async function data({ params }) {
const res = await fetchWithCache(
`https://api.example.com/posts/${params.slug}`,
{ /* 标准 fetch 选项 */ },
{ maxAge: 3600 }
)
return { post: await res.json() }
}选项
maxAge—— 缓存存活时间(秒),默认3600cacheKey—— 自定义键(默认取 URL + 方法 + 请求头 + 请求体的哈希)forceRefresh—— 跳过缓存cache——'auto'|'memory'|'fs'|'none'
缓存模式
auto(默认)—— 开发时用内存,生产构建时用文件系统memory—— 进程内,进程退出即清空fs—— 持久化到node_modules/.cache/none—— 每次都重新请求
默认只缓存 GET 请求(要缓存其他方法,请传入 cacheKey)。错误响应永远不会被缓存。
本地 JSON 文件
没有 API?把内容以 JSON 形式放在仓库里,用 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>
`相对路径从项目根目录解析,因此无论在哪里运行 CLI,data/posts 都指向同一处。readJson 返回解析后的单个文件;readJsonCollection 返回条目数组,每一项都带 slug —— 可以来自一个 .json 文件目录(每个条目一个文件,slug 取自文件名),也可以来自单个文件,其中是条目数组或以 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')集合选项
slug—— 字段名或函数;默认取文件名、对象的键,或条目自身的slug/idsort—— 字段名('date'升序,'-date'降序)或比较函数recursive—— 一并读取子目录中的.json文件,用路径作为 slugroot—— 相对路径的解析目录cache——'auto'|'memory'|'none'
每个文件的读取结果都会被记住,因此 500 个页面的构建只解析每个文件一次。开发服务器则改为比对 mtime,并在页面读取过的 JSON 文件发生变化时刷新浏览器。slug 重复、文件缺失和 JSON 格式错误都会让构建失败,并指出对应路径。