Learn how to seamlessly integrate Stubby CMS with Nuxt.js to create dynamic, revalidated blog content. This guide walks you through setting up Stubby CMS in your Nuxt project, enabling you to fetch and display content efficiently while leveraging the full potential of server-side rendering (SSR) and incremental static regeneration (ISR).
1. Setting up Nuxt.js with Tailwind CSS
Before integrating Stubby CMS, let's get a Nuxt.js project up and running with Tailwind CSS for styling.
- Create a Nuxt.js project — If you don't have a Nuxt project, create one using the Nuxt CLI:
npx nuxi@latest init stubby-demo
cd stubby-demo
- Install tailwind CSS — Add Tailwind CSS and its required dependencies:
npm install -D tailwindcss postcss autoprefixer @tailwindcss/typography
npx tailwindcss init
- Configure tailwind in nuxt.config.ts — Add Tailwind CSS and PostCSS configuration:
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
compatibilityDate: "2024-11-01",
css: ['~/assets/css/main.css'],
postcss: {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
},
});
- Tailwind configuration — Update the
tailwind.config.js
file to include all Nuxt template paths:
/** @type {import('tailwindcss').Config} */
export default {
content: [
"./components/**/*.{js,vue,ts}",
"./layouts/**/*.vue",
"./pages/**/*.vue",
"./plugins/**/*.{js,ts}",
"./app.vue",
"./error.vue",
],
theme: {
extend: {},
},
plugins: [
require('@tailwindcss/typography'),
],
};
- Add CSS directives — Create an
assets/css/main.css
file and include Tailwind's base, components, and utilities:
@tailwind base;
@tailwind components;
@tailwind utilities;
- Run the development server — Start your project with:
npm run dev
2. Adding stubby CMS environment variables
Add your Stubby CMS API credentials to a .env
file at the root of your project:
STUBBY_API_KEY="your_stubby_api_key"
STUBBY_SITE_ID="your_site_id"
STUBBY_BASE_URL="https://stubby.io/api/v1"
You can find these values in your Stubby CMS site settings.
3. Setting up API endpoints
To fetch data from Stubby CMS, create API handlers in the server/api
directory.
- Fetch all pages — Create a
server/api/all-pages.ts
file:
export default defineEventHandler(async (event) => {
const { STUBBY_API_KEY, STUBBY_SITE_ID, STUBBY_BASE_URL } = process.env;
const url = `${STUBBY_BASE_URL}/sites/${STUBBY_SITE_ID}/collections?apiKey=${STUBBY_API_KEY}`;
const res = await fetch(url);
return await res.json();
})
- Fetch a single page — Create another handler in
server/api/a-page.ts
:
export default defineEventHandler(async (event) => {
const { STUBBY_API_KEY, STUBBY_SITE_ID, STUBBY_BASE_URL } = process.env;
const { slug } = getQuery(event);
const res = await fetch(
`${STUBBY_BASE_URL}/sites/${STUBBY_SITE_ID}/pages/${slug}?apiKey=${STUBBY_API_KEY}`
);
return await res.json();
});
4. Installing Markdown rendering support
- To render content from Stubby CMS, install the nuxt-mdc module:
npx nuxi@latest module add mdc
- Update your
nuxt.config.ts
file to enable SSR and configure the module:
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
compatibilityDate: "2024-11-01",
devtools: { enabled: false },
css: ["~/assets/css/main.css"],
ssr: true,
routeRules: {
"/blog": { isr: true },
"/blog/:slug": { isr: true },
},
modules: ['@nuxtjs/mdc'],
postcss: {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
},
});
5. Building the blog pages
- Main blog page — Create a
pages/blog/index.vue
file to list all blog posts:
<template>
<main class="container pb-40 pt-16 mx-auto max-w-[65ch]">
<h1 class="text-3xl font-semibold mb-10">Blog</h1>
<ul class="flex flex-col space-y-10">
<li v-for="page in data" :key="page.metadata.slug">
<nuxt-link :to="`/blog/${page.metadata.slug}`" class="font-semibold text-lg">
{{ page.title }}
</nuxt-link>
<p>
{{ page.metadata.description }}
</p>
<NuxtLink :to="`/blog/${page.metadata.slug}`" class="mt-3 inline-block text-blue-700">
Read more →
</NuxtLink>
</li>
</ul>
</main>
</template>
<script lang="ts" setup>
const { data, status, error, refresh, clear } = await useFetch('/api/all-pages');
</script>
- Individual blog post page — Create a
pages/blog/[slug].vue
file to display individual blog posts:
<template>
<main class="container pb-40 pt-16 mx-auto max-w-[65ch]" v-if="status === 'success' && data">
<nuxt-link to="/blog" class="text-blue-700 mb-10 inline-block">← Back to blog</nuxt-link>
<h1 class="text-3xl font-semibold">{{data.title}}</h1>
<div class="prose">
<MDC :value="data.content" tag="article" />
</div>
</main>
</template>
<script lang="ts" setup>
const route = useRoute()
const slug = route.params.slug
const { data, status, error, refresh, clear } = await useFetch('/api/a-page?slug=' + slug);
</script>
- Update app.vue — Replace the default content in
app.vue
with:
<template>
<NuxtPage />
</template>
6. Conclusion
By integrating Stubby CMS with Nuxt.js, you can build dynamic, SEO-friendly applications with powerful content management capabilities. With SSR and ISR support, your content remains fresh and performant while Stubby CMS handles content creation and management. This setup ensures a smooth experience for both developers and users, making it an ideal solution for blogs, documentation sites, and more. Get started today and unlock the full potential of Stubby CMS with Nuxt.js!