数据加载

导出一个 data() 函数,它的结果会作为 ctx.data 出现在渲染函数里。它在构建时运行,在开发服务器中则每次请求都会运行。

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,
    ),
  )

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() }
}

选项

缓存模式

默认只缓存 GET 请求(要缓存其他方法,请传入 cacheKey)。错误响应永远不会被缓存。

本地 JSON 文件

没有 API?把内容以 JSON 形式放在仓库里,用 sitelo/data 读取。

data/
├─ site.json
└─ posts/
   ├─ hello-world.json
   └─ why-static.json
import { 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')

集合选项

每个文件的读取结果都会被记住,因此 500 个页面的构建只解析每个文件一次。开发服务器则改为比对 mtime,并在页面读取过的 JSON 文件发生变化时刷新浏览器。slug 重复、文件缺失和 JSON 格式错误都会让构建失败,并指出对应路径。