Skip to content

Astro Setup

The @wollycms/astro package provides a typed client, components, and helpers for building Astro sites powered by WollyCMS.

Terminal window
npm install @wollycms/astro

Create src/lib/wolly.ts:

import { createClient } from '@wollycms/astro';
export const wolly = createClient({
apiUrl: import.meta.env.CMS_API_URL || 'http://localhost:4321/api/content',
});

Add the environment variable to your .env:

Terminal window
CMS_API_URL=http://localhost:4321/api/content

When deploying your Astro frontend to Cloudflare Workers, the import.meta.env approach works for build-time values. For runtime configuration (where the CMS URL might differ per environment), use middleware to read from cloudflare:workers env bindings.

Terminal window
npm install @astrojs/cloudflare
astro.config.mjs
import { defineConfig } from 'astro/config';
import cloudflare from '@astrojs/cloudflare';
export default defineConfig({
output: 'server',
adapter: cloudflare(),
});

Create src/middleware.ts:

import { defineMiddleware } from 'astro:middleware';
import { createClient } from '@wollycms/astro';
export const onRequest = defineMiddleware(async (context, next) => {
// On Cloudflare Workers, read the binding
const runtime = context.locals.runtime;
const cmsBaseUrl = runtime?.env?.CMS_API_URL
|| import.meta.env.CMS_API_URL
|| 'http://localhost:4321/api/content';
context.locals.wolly = createClient({ apiUrl: cmsBaseUrl });
return next();
});

Add the type declaration in src/env.d.ts:

/// <reference types="astro/client" />
declare namespace App {
interface Locals {
wolly: import('@wollycms/astro').WollyClient;
runtime?: {
env: {
CMS_API_URL?: string;
};
};
}
}

Then use Astro.locals.wolly in your pages instead of the static import:

---
const wolly = Astro.locals.wolly;
const page = await wolly.pages.getBySlug('home');
---
[vars]
CMS_API_URL = "https://cms.example.com/api/content"

Create src/lib/blocks.ts to map block type slugs to Astro components:

export { default as hero } from '../blocks/Hero.astro';
export { default as rich_text } from '../blocks/RichText.astro';
export { default as image } from '../blocks/ImageBlock.astro';
export { default as cta } from '../blocks/CTA.astro';

Create src/pages/[...slug].astro:

---
import Layout from '../layouts/Default.astro';
import BlockRenderer from '@wollycms/astro/components/BlockRenderer.astro';
import { wolly } from '../lib/wolly';
import * as blocks from '../lib/blocks';
const slug = Astro.params.slug || 'home';
const page = await wolly.pages.getBySlug(slug);
---
<Layout title={page.title}>
<BlockRenderer blocks={page.regions.hero ?? []} region="hero" components={blocks} />
<BlockRenderer blocks={page.regions.content ?? []} region="content" components={blocks} />
</Layout>

The WollyClient instance exposes these namespaces:

NamespaceMethods
pagesgetBySlug(slug), list(params?)
menusget(slug, depth?)
taxonomiesgetTerms(slug)
mediagetInfo(id), getVariant(id, variant), url(id, variant?)
searchquery(q, options?)
redirectslist()
configget()
schemasget()
trackingScriptsgetForPage(slug?)

All methods return typed responses matching the interfaces exported from @wollycms/astro.