Frameworks

Nuxt

Read and render what you publish from a Nuxt site with @hollware/nuxt, over a service binding or a read token, with previews and images ready.

Nuxt

@hollware/nuxt is a Nuxt module: composables that read published content, components that render it, previews of drafts, and a cache that Hollware purges when you publish.

npm install @hollware/nuxt

Configure it

// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@hollware/nuxt'],
  hollware: { site: 'my-site' },
  nitro: { preset: 'cloudflare_module', cloudflare: { deployConfig: true, nodeCompat: false } },
})

On Cloudflare, bind your Hollware Worker in the site's wrangler.jsonc, and the module reads over it, with no network and no token:

"services": [{ "binding": "HOLLWARE", "service": "my-cms", "entrypoint": "Hollware" }]

Anywhere else, set hollware.url to the address of your Hollware and a read token (npx hollware token create --read) in NUXT_HOLLWARE_TOKEN. The token stays on the server: pages read through the site's own /_hollware/ routes.

Show an entry

<script setup lang="ts">
const route = useRoute()
const { data } = await useHollwareEntry('blog', 'en', route.params.slug as string)
</script>

<template>
  <article v-if="data">
    <h1>{{ data.entry.frontmatter.title }}</h1>
    <HollwareImage :entry="data.entry" field="img" />
    <HollwareContent :entry="data.entry" :components="{ callout: Callout }" />
  </article>
</template>
  • <HollwareContent> renders the entry from the document Hollware stored when it was written: no Markdown parser reaches the page. components maps the components of your entries (::callout) to your own Vue components; anything else renders as its plain tag. Its images come with their srcset, sizes, width and height.
  • <HollwareImage> renders the image a frontmatter field holds, such as a cover, with its alt, its size and the copies Hollware made of it. Any attribute you give wins: <HollwareImage :entry field="img" loading="lazy" sizes="50vw" />.

An entry that is not published answers a 404.

Lists, translations and the site

<script setup lang="ts">
const { data } = await useHollwareEntries('blog', { locale: 'en', limit: 10 })
</script>

<template>
  <ul>
    <li v-for="post in data?.entries" :key="post.id">
      <HollwareImage :entry="post" field="img" loading="lazy" />
      <NuxtLink :to="`/blog/${post.slug}/`">{{ post.frontmatter.title }}</NuxtLink>
    </li>
  </ul>
</template>
ComposableGives
useHollwareEntry(collection, locale, slug)a published entry, with its document
useHollwareEntries(collection, { locale, tag, limit, cursor })a page of published entries, newest first
useHollwareTranslations(collection, group)the entries of a translation group
useHollwareSite()the site: its locales and collections
useHollware(event) (server)the reader itself, for routes of your own

The fields your collection has Hollware fill, such as a date or the reading time, come filled in the frontmatter (Configure your content).

Previews

Preview on the site, in the admin, opens the entry's page with a signed link for that one entry, valid for an hour. The module exchanges the link for an HttpOnly cookie, reads the latest revision of the entry, a draft included, and keeps nothing it answers. It needs the site's url in the admin, under Site.

Cache

hollware.cache: 'purge' keeps the pages of your site in Workers Cache and lets Hollware purge them, by tag, the moment you publish. See Caching.

Every page carries <meta name="generator" content="Hollware">; hollware.generator: false leaves it out.

A whole site

examples/nuxt-blog in the repository is a Nuxt blog on a Worker that reads the playground over a service binding, previews included.