Frameworks
Astro
Read what you publish from an Astro site with @hollware/astro, at request time or at build time, and render it with your own Astro components.
Astro
@hollware/astro gives Astro's content layer two loaders, and two components that render what they load.
npm install @hollware/astroRead at request time
A live collection reads at request time, so what you publish shows on the next request, with no rebuild. On Cloudflare, bind your Hollware Worker in the site's wrangler.jsonc:
"services": [{ "binding": "HOLLWARE", "service": "my-cms", "entrypoint": "Hollware" }]// src/live.config.ts
import { env } from 'cloudflare:workers'
import { defineLiveCollection } from 'astro/content/config'
import { hollwareBinding, hollwareLiveLoader } from '@hollware/astro'
const blog = defineLiveCollection({
loader: hollwareLiveLoader({
site: 'my-site',
collection: 'blog',
locale: 'en',
reader: () => hollwareBinding(env.HOLLWARE),
}),
})
export const collections = { blog }Make one collection per locale. An entry's id is its slug and its data the frontmatter, with the fields Hollware fills already filled.
Read at build time
For a static site, hollwareLoader in src/content.config.ts reads every published entry once, at build time, over HTTP with a read token (npx hollware token create --read):
// src/content.config.ts
import { defineCollection } from 'astro:content'
import { hollwareLoader } from '@hollware/astro'
const blog = defineCollection({
loader: hollwareLoader({
site: 'my-site',
collection: 'blog',
locale: 'en',
url: 'https://cms.example.com',
token: process.env.HOLLWARE_TOKEN ?? '',
}),
})
export const collections = { blog }Give defineCollection a schema to validate the frontmatter, as with any loader.
Render an entry
---
import HollwareContent from '@hollware/astro/HollwareContent.astro'
import HollwareImage from '@hollware/astro/HollwareImage.astro'
import { getLiveEntry } from 'astro:content'
import Callout from '../components/Callout.astro'
const { entry } = await getLiveEntry('blog', Astro.params.slug!)
if (!entry) return new Response('Not found', { status: 404 })
---
<h1>{entry.data.title}</h1>
<HollwareImage entry={entry} field="img" />
<HollwareContent entry={entry} components={{ callout: Callout }} />HollwareContent.astrorenders the entry from its document, with your own Astro components for the components of your entries:::callout{type="tip"}givesCallout.astrothe proptypeand its content in the default<slot />. An element with no mapping renders as its plain tag. It goes through the same rules as the HTML Hollware makes, so nothing in an entry runs a script.HollwareImage.astrorenders the image a frontmatter field holds, with its alt, its size and thesrcsetof its copies. Any attribute you give wins.
You can also use Astro's own render(entry): its <Content /> is the HTML Hollware made, which needs no component of yours.
Lists and translations
getLiveCollection('blog', { tag, limit }) lists the entries, without their body, each with the images of its frontmatter for HollwareImage.astro. hollwareTranslations(options, group) gives the { locale, slug } of each entry of a translation group, to link to.
Previews
A live collection previews drafts. Add the middleware, which exchanges the admin's preview link for a cookie:
// src/middleware.ts
import { hollwarePreview } from '@hollware/astro'
export const onRequest = hollwarePreview()---
import { refusePreview } from '@hollware/astro'
const preview = Astro.locals.hollwarePreview
const { entry, error } = await getLiveEntry('blog', { id: Astro.params.slug!, preview })
if (error) refusePreview(Astro.locals, error)
---With a token, the entry is its latest revision, a draft included, and the page is never kept. A token that expired is an error, never the published version. A build-time collection has no previews: a static page is built once, for everyone.
A whole site
examples/astro-blog in the repository is an Astro blog on a Worker that reads the playground at request time, with its callout as a component of its own.