# VitePress 集成 Strapi 接口实现 SSR 渲染

URL: https://caijiao.org/posts/39
Source: docs/posts/39.md
Description: 如何在 VitePress 中集成 Strapi 数据源，通过 SSR 渲染部分动态内容（如文章列表、详情）

## 目标

在 VitePress 中集成 **Strapi** 数据源，通过 **SSR 渲染** 文章列表和单篇文章。构建时（Build-time）从 Strapi 拉取数据并生成静态页面，保留 VitePress 的静态化特性。

## 实现步骤

### 1. 准备 Strapi 接口

假设 Strapi 提供以下接口：

```bash
GET https://cms.example.com/api/articles?populate=*
````

返回数据结构：

```json
{
  "data": [
    {
      "id": 1,
      "attributes": {
        "title": "第一篇文章",
        "slug": "first-article",
        "content": "正文内容……"
      }
    }
  ]
}
```

### 2. 在 VitePress 构建前拉取数据

创建一个脚本 `scripts/fetch-strapi.js`，用于在构建前从 Strapi 拉取数据并生成 Markdown 文件。

```js
// scripts/fetch-strapi.js
import fs from 'fs';
import path from 'path';
import fetch from 'node-fetch';

const API_URL = 'https://cms.example.com/api/articles?populate=*';
const DOCS_DIR = path.resolve('./docs/articles');

async function main() {
  const res = await fetch(API_URL);
  const json = await res.json();
  const articles = json.data;

  if (!fs.existsSync(DOCS_DIR)) {
    fs.mkdirSync(DOCS_DIR, { recursive: true });
  }

  for (const item of articles) {
    const { title, slug, content } = item.attributes;
    const filePath = path.join(DOCS_DIR, `${slug}.md`);

    const md = `---
title: "${title}"
description: "来自 Strapi 的文章"
---

${content}
`;

    fs.writeFileSync(filePath, md);
  }

  console.log(`✅ 已生成 ${articles.length} 篇文章`);
}

main().catch(console.error);
```

然后在 `package.json` 中添加 `prebuild` 脚本：

```json
{
  "scripts": {
    "prebuild": "node scripts/fetch-strapi.js",
    "build": "vitepress build"
  }
}
```

### 3. 动态文章路由支持

VitePress 会自动将 `docs/articles/slug.md` 渲染成以下路由：

```
/articles/first-article.html
```

你可以创建 `docs/articles/index.md` 作为文章列表页：

```md
---
title: 文章列表
---



<ul>
  <li v-for="item in articles" :key="item.slug">
    <a :href="'/articles/' + item.slug">{{ item.title }}</a>
  </li>
</ul>
```

### 4. 构建时生成文章索引 JSON（可选）

在 `fetch-strapi.js` 中生成 `/public/articles.json`：

```js
const PUBLIC_DIR = path.resolve('./docs/.vitepress/public');

fs.writeFileSync(
  path.join(PUBLIC_DIR, 'articles.json'),
  JSON.stringify(
    articles.map(a => ({
      title: a.attributes.title,
      slug: a.attributes.slug,
    })),
    null,
    2
  )
);
```

### 5. SSR 渲染与预览

构建完成后：

```bash
npm run build
npm run serve
```

VitePress 会生成静态 HTML：

* `/articles/first-article.html`：由 Strapi 内容渲染的文章页面；
* `/articles/index.html`：文章列表页（使用客户端 fetch 更新）。

## 进阶功能：仅拉取部分路由

如果你只想拉取部分页面，可以在脚本中控制接口参数：

```js
const res = await fetch(`${API_URL}&pagination[limit]=5`);
```

## 目录结构示例

```
docs/
├─ .vitepress/
│  ├─ config.js
│  └─ public/
│     └─ articles.json
├─ articles/
│  ├─ first-article.md
│  └─ second-article.md
└─ index.md
scripts/
└─ fetch-strapi.js
```

## 结果

* VitePress 在构建时 SSR 渲染 Strapi 内容；
* 最终输出纯静态 [HTML](/html/)；
* 可通过 Cloudflare Pages / Vercel / GitHub Pages 部署。
