@scribe-atp/nuxt
v1.2.0
Published
Nuxt 3 module for reading Scribe CMS content from the AT Protocol.
Maintainers
Readme
@scribe-atp/nuxt
Nuxt 3 module for reading Scribe CMS content from the AT Protocol. Requires Nuxt 3 or later.
Wraps @scribe-atp/core with Nuxt-idiomatic useAsyncData composables and auto-imports — no explicit imports needed in your components or pages.
Installation
npm install @scribe-atp/nuxtRegister the module in nuxt.config.ts:
export default defineNuxtConfig({
modules: ["@scribe-atp/nuxt"],
});Usage
The composables are auto-imported globally — no import statement needed:
useScribeSite
<!-- pages/blog/index.vue -->
<script setup lang="ts">
const { data: site, pending, error } = await useScribeSite(
"alice.bsky.social",
"https://alice.bsky.social"
);
</script>
<template>
<div v-if="pending">Loading…</div>
<div v-else-if="error">{{ error.message }}</div>
<ul v-else>
<li v-for="group in site!.groups" :key="group.slug">
{{ group.title }}
</li>
</ul>
</template>useScribeArticle
<!-- pages/blog/[slug].vue -->
<script setup lang="ts">
const route = useRoute();
const { data: article, pending, error } = await useScribeArticle(
"alice.bsky.social",
route.params.slug as string
);
</script>
<template>
<article v-if="article">
<h1>{{ article.title }}</h1>
<div v-html="article.content" />
</article>
</template>The composables return the full useAsyncData result shape: { data, pending, error, refresh, ... }.
Deferred loading with lazy
Pass useAsyncData options as an optional third argument:
const { data: site, pending } = useScribeSite(
"alice.bsky.social",
"https://alice.bsky.social",
{ lazy: true }
);ISR (Incremental Static Regeneration)
Use Nuxt's routeRules in nuxt.config.ts to control revalidation:
export default defineNuxtConfig({
modules: ["@scribe-atp/nuxt"],
routeRules: {
"/blog/**": { swr: 3600 }, // revalidate every hour
},
});Open Graph and Twitter Card meta tags
articleSeoMeta and siteSeoMeta return a camelCase object shaped for Nuxt's useSeoMeta() composable. They produce Open Graph and Twitter Card tags for rich link previews when sharing article URLs on Bluesky and other platforms.
<!-- pages/blog/[slug].vue -->
<script setup lang="ts">
import { articleSeoMeta } from "@scribe-atp/nuxt";
import { fetchArticleBySlug, fetchSite } from "@scribe-atp/core";
const route = useRoute();
const [{ article }, site] = await Promise.all([
fetchArticleBySlug("alice.bsky.social", "https://alice.bsky.social", route.params.slug as string),
fetchSite("alice.bsky.social", "https://alice.bsky.social"),
]);
useSeoMeta(articleSeoMeta(article, site));
</script>siteSeoMeta covers index and group pages:
import { siteSeoMeta } from "@scribe-atp/nuxt";
useSeoMeta(siteSeoMeta(site));These functions are not auto-imported — use an explicit import from @scribe-atp/nuxt.
Auto-imports
Only the data composables are auto-imported: useScribeSite and useScribeArticle.
Utility functions and meta helpers require an explicit import:
import { toSlug, flattenArticles } from "@scribe-atp/core";
import { articleSeoMeta, siteSeoMeta } from "@scribe-atp/nuxt";TypeScript types
All types from @scribe-atp/core are re-exported:
import type { Site, Article, ArticleRef, SiteGroup } from "@scribe-atp/nuxt";