JSON local

Du contenu qui vit dans le dépôt en JSON, transformé en pages statiques par sitelo/data. Pas d’API, pas de base de données, pas de JavaScript côté client. Source complète dans examples/json.

Ce que vous obtenez

Structure du projet

my-site/
  sitelo.config.js
  data/
    site.json              # réglages globaux du site
    categories.json        # un objet, indexé par slug
    products/              # un fichier par produit
      aeron-chair.json
      jarvis-desk.json
      tolomeo-lamp.json
  src/
    lib/
      catalogue.js         # le seul module qui touche à sitelo/data
    index.ht.js            # / — catégories et tous les produits
    products/
      [slug].ht.js         # /products/:slug — une page par fichier JSON
    categories/
      [slug].ht.js         # /categories/:slug — une page par clé

Les données vivent hors de src/, sitelo ne les traite donc jamais comme des pages ou des ressources.

1. Mettez le contenu dans data/

Un fichier par produit. Le nom du fichier est le slug : aeron-chair.json devient /products/aeron-chair sans que rien dans le fichier ait à le dire :

{
  "name": "Aeron Chair",
  "category": "seating",
  "price": 1395,
  "released": "2022-04-01",
  "summary": "Mesh task chair with adjustable lumbar support.",
  "inStock": true
}

Les catégories tiennent au contraire dans un seul fichier : un objet indexé par slug, que readJsonCollection lit tout aussi bien comme une collection.

{
  "seating": {
    "name": "Seating",
    "description": "Chairs and stools for long working days."
  },
  "desks": {
    "name": "Desks",
    "description": "Fixed-height and sit-stand work surfaces."
  }
}

2. Lisez-le au même endroit

Un petit module côté serveur enveloppe les lectures. Rien dans le HTML n’y fait référence, il n’arrive donc jamais au navigateur — et comme sitelo/data mémorise par fichier, toutes les pages qui appellent ces helpers n’analysent chaque fichier JSON qu’une fois pour tout le build.

import { readJson, readJsonCollection } from 'sitelo/data'

/** Réglages globaux : un fichier JSON, analysé tel quel. */
export function getSite() {
  return readJson('data/site.json')
}

/** Une entrée par fichier, slug tiré du nom de fichier. */
export function getProducts() {
  return readJsonCollection('data/products', { sort: 'name' })
}

/** Un fichier contenant un objet indexé par slug — la clé devient le slug. */
export function getCategories() {
  return readJsonCollection('data/categories.json')
}

/** Les produits d’une catégorie, du moins cher au plus cher. */
export async function getProductsInCategory(slug) {
  const products = await readJsonCollection('data/products', { sort: 'price' })
  return products.filter((product) => product.category === slug)
}

3. Tout lister sur la page d’accueil

import { html, head, title, link, body, h1, h2, ul, li, a } from 'javascript-to-html'
import { getCategories, getProducts, getSite } from './lib/catalogue.js'

export async function data() {
  return {
    site: await getSite(),
    categories: await getCategories(),
    products: await getProducts(),
  }
}

export default ({ data }) =>
  html({ lang: 'fr' },
    head(
      title(data.site.title),
      link({ rel: 'stylesheet', href: '/css/styles.css' }),
    ),
    body(
      h1(data.site.title),
      h2('Catégories'),
      ul(
        ...data.categories.map((category) =>
          li(a({ href: `/categories/${category.slug}` }, category.name)),
        ),
      ),
      h2('Tous les produits'),
      ul(
        ...data.products.map((product) =>
          li(a({ href: `/products/${product.slug}` }, product.name)),
        ),
      ),
    ),
  )

4. Une page par fichier JSON

generateStaticParams renvoie un slug par fichier au moment du build ; data() charge l’entrée correspondante pour chaque page.

import { html, head, title, link, body, h1, p, dl, dt, dd } from 'javascript-to-html'
import { getProduct, getProducts } from '../lib/catalogue.js'

export async function generateStaticParams() {
  const products = await getProducts()
  return products.map((product) => ({ slug: product.slug }))
}

export async function data({ params }) {
  const product = await getProduct(params.slug)
  if (!product) throw new Error(`Unknown product: ${params.slug}`)
  return { product }
}

export default ({ data }) =>
  html({ lang: 'fr' },
    head(
      title(data.product.name),
      link({ rel: 'stylesheet', href: '/css/styles.css' }),
    ),
    body(
      h1(data.product.name),
      p(data.product.summary),
      dl(
        dt('Catégorie'),
        dd(data.product.category),
        dt('Sortie'),
        dd(data.product.released),
        dt('Disponibilité'),
        dd(data.product.inStock ? 'En stock' : 'Épuisé'),
      ),
    ),
  )

5. Éditez et observez

npm install
npm run build

Sous sitelo, changer un prix recharge la page ouverte — le serveur de développement surveille les fichiers JSON que les pages lisent réellement. Slugs en double, fichiers manquants et JSON invalide font échouer le build en nommant le chemin fautif.

Documentation du chargement de données · Documentation du routage · Documentation de la configuration