JSON local
Sur cette page
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
- Une page d’accueil listant chaque catégorie et chaque produit
/products/[slug]— une page statique par fichier dansdata/products//categories/[slug]— une page par clé dedata/categories.json- Ajouter un fichier JSON ajoute une page ; aucune route à déclarer
- Zéro JS envoyé — les fichiers sont lus dans Node au moment du build
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 { 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}</title>
<link rel="stylesheet" href="/css/styles.css">
</head>
<body>
<h1>${data.site.title}</h1>
<h2>Catégories</h2>
<ul>
${data.categories
.map(
(category) =>
`<li><a href="/categories/${category.slug}">${category.name}</a></li>`,
)
.join('')}
</ul>
<h2>Tous les produits</h2>
<ul>
${data.products
.map(
(product) =>
`<li><a href="/products/${product.slug}">${product.name}</a></li>`,
)
.join('')}
</ul>
</body>
</html>
`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)),
),
),
),
)import { getCategories, getProducts, getSite } from './lib/catalogue.js'
export async function data() {
return {
site: await getSite(),
categories: await getCategories(),
products: await getProducts(),
}
}
export default function Home({ data }) {
return (
<html lang="fr">
<head>
<title>{data.site.title}</title>
<link rel="stylesheet" href="/css/styles.css" />
</head>
<body>
<h1>{data.site.title}</h1>
<h2>Catégories</h2>
<ul>
{data.categories.map((category) => (
<li key={category.slug}>
<a href={`/categories/${category.slug}`}>{category.name}</a>
</li>
))}
</ul>
<h2>Tous les produits</h2>
<ul>
{data.products.map((product) => (
<li key={product.slug}>
<a href={`/products/${product.slug}`}>{product.name}</a>
</li>
))}
</ul>
</body>
</html>
)
}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 { 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}</title>
<link rel="stylesheet" href="/css/styles.css">
</head>
<body>
<h1>${data.product.name}</h1>
<p>${data.product.summary}</p>
<dl>
<dt>Catégorie</dt>
<dd>${data.product.category}</dd>
<dt>Sortie</dt>
<dd>${data.product.released}</dd>
<dt>Disponibilité</dt>
<dd>${data.product.inStock ? 'En stock' : 'Épuisé'}</dd>
</dl>
</body>
</html>
`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é'),
),
),
)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 function Product({ data }) {
return (
<html lang="fr">
<head>
<title>{data.product.name}</title>
<link rel="stylesheet" href="/css/styles.css" />
</head>
<body>
<h1>{data.product.name}</h1>
<p>{data.product.summary}</p>
<dl>
<dt>Catégorie</dt>
<dd>{data.product.category}</dd>
<dt>Sortie</dt>
<dd>{data.product.released}</dd>
<dt>Disponibilité</dt>
<dd>{data.product.inStock ? 'En stock' : 'Épuisé'}</dd>
</dl>
</body>
</html>
)
}5. Éditez et observez
npm install
npm run buildSous 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