Skip to content

Content Management Systems

Integrate VitePress with various CMS solutions for dynamic content management.

Headless CMS Integration

  • Strapi: Open-source headless CMS
  • Contentful: Cloud-based CMS
  • Sanity: Real-time collaborative CMS
  • Ghost: Publishing-focused CMS
  • Forestry: Git-based CMS

Strapi Integration

Setup

  1. Install Strapi:
bash
npx create-strapi-app@latest my-cms --quickstart
  1. Create content types and entries

  2. Fetch content in VitePress:

javascript
// .vitepress/config.js
export default {
  async transformPageData(pageData) {
    if (pageData.relativePath === 'blog/index.md') {
      const posts = await fetch('http://localhost:1337/api/posts')
        .then(res => res.json())
      
      pageData.frontmatter.posts = posts.data
    }
  }
}

Dynamic Pages

Generate pages from CMS content:

javascript
// .vitepress/config.js
export default {
  async buildEnd() {
    const posts = await fetchPosts()
    
    for (const post of posts) {
      await writeFile(
        `docs/blog/${post.slug}.md`,
        generateMarkdown(post)
      )
    }
  }
}

Contentful Integration

Configuration

javascript
// utils/contentful.js
import { createClient } from 'contentful'

const client = createClient({
  space: process.env.CONTENTFUL_SPACE_ID,
  accessToken: process.env.CONTENTFUL_ACCESS_TOKEN
})

export async function getEntries(contentType) {
  const entries = await client.getEntries({
    content_type: contentType
  })
  return entries.items
}

Content Fetching

vue
<script setup>
import { data } from './posts.data.js'
</script>

<template>
  <div v-for="post in data" :key="post.id">
    <h2>{{ post.title }}</h2>
    <p>{{ post.description }}</p>
  </div>
</template>
javascript
// posts.data.js
import { getEntries } from '../utils/contentful.js'

export default {
  async load() {
    return await getEntries('blogPost')
  }
}

Git-based CMS

Forestry/TinaCMS

Configure for Git-based editing:

yaml
# .forestry/settings.yml
new_page_extension: md
auto_deploy: false
admin_path: 
version: 0.0.1

sections:
- type: directory
  path: docs
  label: Pages
  create: all
  match: "**/*"

NetlifyCMS

Add NetlifyCMS configuration:

yaml
# public/admin/config.yml
backend:
  name: git-gateway
  branch: main

media_folder: "public/images"
public_folder: "/images"

collections:
  - name: "blog"
    label: "Blog"
    folder: "docs/blog"
    create: true
    slug: "{{year}}-{{month}}-{{day}}-{{slug}}"
    fields:
      - {label: "Title", name: "title", widget: "string"}
      - {label: "Date", name: "date", widget: "datetime"}
      - {label: "Body", name: "body", widget: "markdown"}

Content Synchronization

Build-time Fetching

Fetch content during build:

javascript
// scripts/sync-content.js
import { writeFile } from 'fs/promises'
import { fetchFromCMS } from './cms-client.js'

async function syncContent() {
  const posts = await fetchFromCMS('posts')
  
  for (const post of posts) {
    const markdown = `---
title: ${post.title}
date: ${post.date}
---

${post.content}
`
    
    await writeFile(`docs/blog/${post.slug}.md`, markdown)
  }
}

syncContent()

Webhook Integration

Set up webhooks for content updates:

javascript
// api/webhook.js
export default async function handler(req, res) {
  if (req.method === 'POST') {
    // Trigger rebuild
    await fetch(process.env.BUILD_HOOK_URL, {
      method: 'POST'
    })
    
    res.status(200).json({ message: 'Build triggered' })
  }
}

Content Validation

Schema Validation

Validate content structure:

javascript
// utils/validate-content.js
import Joi from 'joi'

const postSchema = Joi.object({
  title: Joi.string().required(),
  date: Joi.date().required(),
  content: Joi.string().required(),
  tags: Joi.array().items(Joi.string())
})

export function validatePost(post) {
  return postSchema.validate(post)
}

Content Processing

Process and transform content:

javascript
// utils/process-content.js
import { marked } from 'marked'
import { sanitize } from 'dompurify'

export function processContent(rawContent) {
  // Convert markdown to HTML
  const html = marked(rawContent)
  
  // Sanitize HTML
  const clean = sanitize(html)
  
  // Extract metadata
  const wordCount = rawContent.split(' ').length
  const readingTime = Math.ceil(wordCount / 200)
  
  return {
    html: clean,
    wordCount,
    readingTime
  }
}

Best Practices

Performance

  • Cache CMS responses
  • Use incremental builds
  • Optimize image delivery
  • Implement lazy loading

Security

  • Validate all content
  • Sanitize HTML output
  • Use environment variables for API keys
  • Implement rate limiting

Content Management

  • Version control content changes
  • Implement content review workflows
  • Use content staging environments
  • Monitor content performance

VitePress Development Guide