{
  "slug": "shared-snippets",
  "title": "Shared Snippets — Reusable Code Blocks",
  "description": "How we built a shared snippets system for docs.webhouse.app using our own CMS — and how you can do the same.",
  "category": "tips",
  "order": 0,
  "locale": "en",
  "translationGroup": "741a83d7-eb8d-414e-8788-ddaa1c862bb0",
  "helpCardId": null,
  "content": "## The problem\n\nDocumentation sites repeat the same code examples across multiple pages. The \"Quick Start\" page shows the install command. The \"Templates\" page shows it too. The \"CLI Reference\" shows it again. When the command changes, you update it in one place and forget the other two.\n\n## The solution: a snippets collection\n\nWe added a `snippets` collection to our CMS config:\n\n```typescript\ndefineCollection({\n  name: \"snippets\",\n  label: \"Shared Snippets\",\n  fields: [\n    { name: \"title\", type: \"text\", required: true },\n    { name: \"description\", type: \"textarea\" },\n    { name: \"code\", type: \"textarea\", required: true },\n    { name: \"lang\", type: \"text\" },\n  ],\n})\n```\n\nEach snippet is a JSON file in `content/snippets/`:\n\n```json\n{\n  \"slug\": \"create-project\",\n  \"status\": \"published\",\n  \"data\": {\n    \"title\": \"Create a new project\",\n    \"code\": \"npm create @webhouse/cms my-site\",\n    \"lang\": \"bash\"\n  }\n}\n```\n\n## Using snippets in markdown\n\nIn any doc page's content field, reference a snippet with:\n\n```\n{{snippet:create-project}}\n```\n\nAt render time, the token is resolved to the actual code block from the snippets collection. The snippet's `lang` field determines syntax highlighting.\n\n## Implementation in build.ts (static sites)\n\nFor static HTML sites using a custom `build.ts`, add a snippet resolver before markdown rendering:\n\n```typescript\nimport { readFileSync, existsSync } from 'fs';\nimport { join } from 'path';\n\nconst SNIPPETS_DIR = join(process.cwd(), 'content', 'snippets');\n\nfunction resolveSnippets(markdown: string): string {\n  return markdown.replace(\n    /\\{\\{snippet:([a-z0-9-]+)\\}\\}/g,\n    (_match, slug) => {\n      const file = join(SNIPPETS_DIR, slug + '.json');\n      if (!existsSync(file)) return '<!-- snippet not found -->';\n      const snippet = JSON.parse(readFileSync(file, 'utf-8'));\n      const lang = snippet.data.lang || 'text';\n      const code = snippet.data.code || '';\n      return '\\x60\\x60\\x60' + lang + '\\n' + code + '\\n\\x60\\x60\\x60';\n    }\n  );\n}\n\n// In your build pipeline:\nconst rawContent = doc.data.content;\nconst withSnippets = resolveSnippets(rawContent);\nconst html = marked.parse(withSnippets);\n```\n\n## Implementation in Next.js (server components)\n\nFor Next.js sites, resolve snippets in your content renderer:\n\n```typescript\n// components/doc-content.tsx\nimport { readFileSync, existsSync } from 'fs';\nimport { join } from 'path';\n\nconst SNIPPETS_DIR = join(process.cwd(), 'content', 'snippets');\n\nfunction resolveSnippets(content: string): string {\n  return content.replace(\n    /\\{\\{snippet:([a-z0-9-]+)\\}\\}/g,\n    (_match, slug) => {\n      const file = join(SNIPPETS_DIR, slug + '.json');\n      if (!existsSync(file)) return '';\n      const snippet = JSON.parse(readFileSync(file, 'utf-8'));\n      return '\\x60\\x60\\x60' + (snippet.data.lang || 'text') +\n        '\\n' + snippet.data.code + '\\n\\x60\\x60\\x60';\n    }\n  );\n}\n\n// Use before rendering markdown\nexport function DocContent({ content }) {\n  const resolved = resolveSnippets(content);\n  // ... render resolved markdown\n}\n```\n\n## Beyond code: other use cases\n\nSnippets don't have to be code. You could use them for:\n\n- **Disclaimers** — legal text that appears on multiple pages\n- **Version badges** — current version number updated in one place\n- **Feature matrices** — comparison tables shared across product pages\n- **Contact info** — address, phone, email used in footer and contact page\n- **Pricing** — price points referenced in features, pricing, and FAQ pages\n\n## Why this matters\n\nThis is dogfooding at its best. We built docs.webhouse.app with @webhouse/cms, and when we needed reusable content blocks, we used the CMS's own collection system. No plugins, no custom infrastructure — just another collection.\n\nThe same pattern works for any CMS-powered site. If you find yourself copy-pasting content between pages, create a snippets collection and reference it.",
  "excerpt": "The problem\n\nDocumentation sites repeat the same code examples across multiple pages. The \"Quick Start\" page shows the install command. The \"Templates\" page shows it too. The \"CLI Reference\" shows it again. When the command changes, you update it in one place and forget the other two.\n\n The solution",
  "seo": {
    "metaTitle": "Shared Snippets — Reusable Code Blocks — webhouse.app Docs",
    "metaDescription": "How we built a shared snippets system for docs.webhouse.app using our own CMS — and how you can do the same."
  },
  "createdAt": "2026-03-30T12:14:24.902Z",
  "updatedAt": "2026-03-30T12:14:24.903Z"
}