Summary
Adds support for live data to content collections. Defines a new type of content loader that fetches data at runtime rather than build time, allowing users to get the data with a similar API.
Background & Motivation
In Astro 5, the content layer API added support for adding diverse content sources to content collections. Users can create loaders that fetch data from any source at build time, and then access it inside a page via getEntry and getCollection. The data is cached between builds, giving fast access and updates. However there is no method for updating the data store between builds, meaning any updates to the data need a full site deploy, even if the pages are rendered on-demand. This means that content collections are not suitable for pages that update frequently. Instead, today these pages tend to access the APIs directly in the frontmatter. This works, but means users don't benefit from the simple, unified API that content loaders offer. In most cases users tend to individually create loader libraries that they share between pages.
This proposal introduces a new kind of loader that fetches data from an API at runtime, rather than build time. As with other content loaders, these loaders abstract the loading logic, meaning users don't need to understand the details of how data is loaded. These loaders can be distributed as node modules, or injected by integrations.
Goals
- a new type of live content loader that is executed at runtime
- integration with
getEntry and getCollection, allowing developers to use a familiar, common API to fetch data
- optional integration with route caching, allowing loaders to define cache tags, TTL etc associated with the data, which the user could decide to use
- loader-specific query options
Non-goals
- server-side caching of the data. Instead it would integrate with the route cache and HTTP caches to cache the full page response
- updating the content layer data store. Live loaders return data directly and do not update the store
- support for existing loaders. They will have a different API. Developers could in theory use shared logic, but the loader API will be different
Example
It may need to be a different content config file, depending on what compiler magic we can do.
// src/livecontent.config.ts
import { defineLiveCollection } from "astro:content";
// Possibly a different name, or maybe use the same `defineCollection`
import { storeLoader } from "@mystore/astro-loader";
const products = defineLiveCollection({
loader: storeLoader({ field: "products", key: process.env.STORE_KEY })
})
export const collections = { products };
Define loaders in the site or in a shared library.
// storeloader.ts
import type { LiveLoader } from "astro/loaders";
import { loadStoreData } from "./lib/api.ts";
interface StoreCollectionFilter {
price: {
min?: number;
max?: number;
}
}
interface StoreEntryFilter {
slug?: string;
}
// Generic allows typing of the `filter` param
export function storeLoader({ field, key }): LiveLoader<StoreEntryFilter, StoreCollectionFilter> {
return {
loadCollection: async ({ logger, filter }) => {
// load from API
const entries = await loadStoreData({ field, key, filter });
return entries.map((entry) => ({
id: entry.id,
data: entry,
cache: {
tags: [field, `field:${entry.id}`]
}
}))
},
loadEntry: async ({ logger, id, filter }) => {
const entry = await loadStoreData({ field, key, filter: filter ? filter : { id }});
if (!entry) {
return
}
return {
id,
data: entry,
cache: {
tags: [field, `field:${entry.id}`]
}
}
},
schema: //...
}
}
Then use the data in pages.
---
// src/pages/products/[slug].astro
import { getEntry } from "astro:content";
// The `filter` prop allows getting by fields other than id. The avilable options will depend on the API
// and will be typed in the loader definition
const entry = await getEntry('products', { slug: Astro.params.slug });
// Possible API for setting cache headers from entry metadata
Astro.cache.fromEntry(entry);
// This will work in prerendered pages, but is designed for on-demand
export const prerender = false;
---
<h1>{ entry.data.title }</h1>
Summary
Adds support for live data to content collections. Defines a new type of content loader that fetches data at runtime rather than build time, allowing users to get the data with a similar API.
Background & Motivation
In Astro 5, the content layer API added support for adding diverse content sources to content collections. Users can create loaders that fetch data from any source at build time, and then access it inside a page via
getEntryandgetCollection. The data is cached between builds, giving fast access and updates. However there is no method for updating the data store between builds, meaning any updates to the data need a full site deploy, even if the pages are rendered on-demand. This means that content collections are not suitable for pages that update frequently. Instead, today these pages tend to access the APIs directly in the frontmatter. This works, but means users don't benefit from the simple, unified API that content loaders offer. In most cases users tend to individually create loader libraries that they share between pages.This proposal introduces a new kind of loader that fetches data from an API at runtime, rather than build time. As with other content loaders, these loaders abstract the loading logic, meaning users don't need to understand the details of how data is loaded. These loaders can be distributed as node modules, or injected by integrations.
Goals
getEntryandgetCollection, allowing developers to use a familiar, common API to fetch dataNon-goals
Example
It may need to be a different content config file, depending on what compiler magic we can do.
Define loaders in the site or in a shared library.
Then use the data in pages.