Skip to content

多版本文档管理

Rspress 提供强大的版本管理功能,允许您为软件的不同版本维护多份文档。本章探讨如何设置和管理多版本文档站点。

什么是文档版本管理?

版本管理概述

文档版本管理允许您为产品的每个主要版本维护独立的文档:

  • 多个版本: 同时维护 v1.0, v2.0, v3.0 文档
  • 版本切换: 用户可以在版本之间切换
  • 版本归档: 保留旧版本供参考
  • 独立内容: 每个版本有自己的内容和配置

为什么需要版本管理?

用户场景:

  • 用户可能使用不同版本的软件
  • 升级需要时间,用户需要访问旧文档
  • API 更改需要不同的文档
  • 功能在版本之间变化

维护优势:

  • 清晰的版本历史
  • 更容易跟踪更改
  • 更好的用户体验
  • 避免混淆

基本版本设置

目录结构

组织多版本文档:

docs/
├── v1/                     # 版本 1.x 文档
│   ├── index.md
│   ├── guide/
│   │   ├── getting-started.md
│   │   └── api.md
│   └── examples/
├── v2/                     # 版本 2.x 文档
│   ├── index.md
│   ├── guide/
│   │   ├── getting-started.md
│   │   ├── new-features.md
│   │   └── api.md
│   └── examples/
├── v3/                     # 版本 3.x (最新)
│   ├── index.md
│   ├── guide/
│   │   ├── getting-started.md
│   │   ├── advanced.md
│   │   └── api.md
│   └── examples/
└── versions.json           # 版本配置

版本配置

创建 versions.json:

json
{
  "latest": "v3",
  "versions": [
    {
      "version": "v3",
      "label": "v3.x (Latest)",
      "path": "/v3"
    },
    {
      "version": "v2",
      "label": "v2.x",
      "path": "/v2"
    },
    {
      "version": "v1",
      "label": "v1.x",
      "path": "/v1"
    }
  ]
}

Rspress 配置

rspress.config.ts 中配置版本:

typescript
import { defineConfig } from 'rspress/config';
import versions from './versions.json';

export default defineConfig({
  title: 'My Documentation',

  // 版本配置
  themeConfig: {
    // 添加版本选择器
    versioning: {
      latestVersion: versions.latest,
      versions: versions.versions,
    },

    // 为每个版本配置导航
    nav: [
      { text: 'Home', link: '/' },
      { text: 'Guide', link: `/${versions.latest}/guide/` },
      { text: 'API', link: `/${versions.latest}/api/` },
      {
        text: `Version: ${versions.latest}`,
        items: versions.versions.map(v => ({
          text: v.label,
          link: v.path,
        })),
      },
    ],
  },
});

版本选择器

内置版本选择器

Rspress 提供内置的版本选择器组件:

typescript
export default defineConfig({
  themeConfig: {
    // 启用版本选择器
    versioning: {
      enabled: true,
      latestVersion: 'v3',
      versions: [
        { version: 'v3', label: 'v3.x (Latest)' },
        { version: 'v2', label: 'v2.x' },
        { version: 'v1', label: 'v1.x (LTS)' },
      ],
      // 版本选择器位置
      position: 'navbar', // 或 'sidebar'
    },
  },
});

自定义版本选择器

创建自定义版本切换组件:

tsx
// components/VersionSelector.tsx
import React from 'react';
import { useLocation } from 'rspress/runtime';
import versions from '../versions.json';

export function VersionSelector() {
  const location = useLocation();
  const currentVersion = location.pathname.split('/')[1] || versions.latest;

  const handleVersionChange = (version: string) => {
    const currentPath = location.pathname.replace(`/${currentVersion}`, `/${version}`);
    window.location.href = currentPath;
  };

  return (
    <div className="version-selector">
      <label htmlFor="version-select">Version:</label>
      <select
        id="version-select"
        value={currentVersion}
        onChange={(e) => handleVersionChange(e.target.value)}
        className="version-dropdown"
      >
        {versions.versions.map((v) => (
          <option key={v.version} value={v.version}>
            {v.label}
          </option>
        ))}
      </select>
    </div>
  );
}

样式化版本选择器:

css
/* styles/version-selector.css */
.version-selector {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem;
}

.version-selector label {
  font-size: 0.875rem;
  color: var(--rp-c-text-2);
}

.version-dropdown {
  padding: 0.375rem 0.75rem;
  border: 1px solid var(--rp-c-border);
  border-radius: 6px;
  background: var(--rp-c-bg);
  color: var(--rp-c-text-1);
  font-size: 0.875rem;
  cursor: pointer;
  transition: all 0.3s;
}

.version-dropdown:hover {
  border-color: var(--rp-c-brand);
}

.version-dropdown:focus {
  outline: none;
  border-color: var(--rp-c-brand);
  box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}

版本横幅

过时版本警告

为旧版本添加警告横幅:

tsx
// components/VersionBanner.tsx
import React from 'react';
import { useLocation } from 'rspress/runtime';
import versions from '../versions.json';

export function VersionBanner() {
  const location = useLocation();
  const currentVersion = location.pathname.split('/')[1];
  const isLatest = currentVersion === versions.latest;

  if (isLatest) {
    return null;
  }

  const latestVersionInfo = versions.versions.find(
    v => v.version === versions.latest
  );

  return (
    <div className="version-banner warning">
      <div className="banner-content">
        <span className="banner-icon">⚠️</span>
        <span className="banner-text">
          您正在查看 <strong>{currentVersion}</strong> 的文档。
          最新版本是{' '}
          <a href={latestVersionInfo?.path}>
            {latestVersionInfo?.label}
          </a>

        </span>
      </div>
    </div>
  );
}

样式化横幅:

css
/* styles/version-banner.css */
.version-banner {
  padding: 1rem;
  margin-bottom: 2rem;
  border-radius: 8px;
  background: #fff3cd;
  border: 1px solid #ffc107;
  color: #856404;
}

.version-banner.warning {
  background: #fff3cd;
  border-color: #ffc107;
  color: #856404;
}

.version-banner.info {
  background: #d1ecf1;
  border-color: #17a2b8;
  color: #0c5460;
}

.banner-content {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.banner-icon {
  font-size: 1.5rem;
  flex-shrink: 0;
}

.banner-text {
  line-height: 1.6;
}

.banner-text a {
  color: inherit;
  text-decoration: underline;
  font-weight: 600;
}

.banner-text a:hover {
  opacity: 0.8;
}

版本导航

每个版本的侧边栏

为不同版本配置不同的侧边栏:

typescript
export default defineConfig({
  themeConfig: {
    sidebar: {
      // v3 侧边栏
      '/v3/': [
        {
          text: '入门',
          items: [
            { text: '介绍', link: '/v3/guide/introduction' },
            { text: '快速开始', link: '/v3/guide/getting-started' },
            { text: '新功能', link: '/v3/guide/new-features' },
          ],
        },
        {
          text: 'API',
          items: [
            { text: 'API 参考', link: '/v3/api/reference' },
            { text: '高级用法', link: '/v3/api/advanced' },
          ],
        },
      ],

      // v2 侧边栏
      '/v2/': [
        {
          text: '入门',
          items: [
            { text: '介绍', link: '/v2/guide/introduction' },
            { text: '快速开始', link: '/v2/guide/getting-started' },
          ],
        },
        {
          text: 'API',
          items: [
            { text: 'API 参考', link: '/v2/api/reference' },
          ],
        },
      ],

      // v1 侧边栏
      '/v1/': [
        {
          text: '文档',
          items: [
            { text: '介绍', link: '/v1/guide/introduction' },
            { text: 'API', link: '/v1/api/reference' },
          ],
        },
      ],
    },
  },
});

版本特定链接

在每个版本中维护正确的链接:

markdown
<!-- v3/guide/introduction.md -->
---
title: 介绍
---

# 介绍 v3

欢迎使用版本 3!

## 下一步

- [快速开始](./getting-started.md)
- [新功能](./new-features.md)
- [API 参考](/v3/api/reference)

## 从 v2 迁移

查看我们的[迁移指南](./migration-from-v2.md)。

版本管理工作流

创建新版本

发布新主要版本时:

  1. 复制当前文档
bash
# 复制 v3 到 v4
cp -r docs/v3 docs/v4

# 将 v3 标记为旧版本
# 更新 v4 内容为新功能
  1. 更新版本配置
json
{
  "latest": "v4",
  "versions": [
    {
      "version": "v4",
      "label": "v4.x (Latest)",
      "path": "/v4"
    },
    {
      "version": "v3",
      "label": "v3.x",
      "path": "/v3"
    },
    {
      "version": "v2",
      "label": "v2.x (Archived)",
      "path": "/v2"
    }
  ]
}
  1. 更新配置文件
typescript
export default defineConfig({
  themeConfig: {
    versioning: {
      latestVersion: 'v4',
      // ...更新版本列表
    },
  },
});

维护多个版本

最佳实践:

  1. 主要更新: 仅更新最新版本
  2. 关键修复: 回溯到支持的版本
  3. 安全更新: 更新所有活跃版本
  4. 归档: 将非常旧的版本标记为已归档
bash
# 示例工作流
git checkout main           # 最新版本 (v4)
# 进行更改...

git checkout v3-docs        # 支持版本
# 回溯重要修复...

git checkout v2-archived    # 仅关键安全修复

长期支持 (LTS)

标记 LTS 版本

指示哪些版本是 LTS:

json
{
  "latest": "v4",
  "versions": [
    {
      "version": "v4",
      "label": "v4.x (Latest)",
      "path": "/v4",
      "lts": false
    },
    {
      "version": "v3",
      "label": "v3.x (LTS)",
      "path": "/v3",
      "lts": true,
      "endOfLife": "2025-12-31"
    },
    {
      "version": "v2",
      "label": "v2.x (EOL)",
      "path": "/v2",
      "lts": false,
      "endOfLife": "2024-06-30"
    }
  ]
}

LTS 横幅

显示 LTS 信息:

tsx
export function LTSBanner({ version }) {
  const versionInfo = versions.versions.find(v => v.version === version);

  if (!versionInfo) return null;

  if (versionInfo.lts) {
    return (
      <div className="version-banner info">
        <span className="banner-icon">✅</span>
        <span className="banner-text">
          此版本是 LTS(长期支持)。支持到{' '}
          {new Date(versionInfo.endOfLife).toLocaleDateString('zh-CN')}。
        </span>
      </div>
    );
  }

  if (versionInfo.endOfLife && new Date(versionInfo.endOfLife) < new Date()) {
    return (
      <div className="version-banner warning">
        <span className="banner-icon">⚠️</span>
        <span className="banner-text">
          此版本已达到生命周期终点 (EOL),不再接收更新。
        </span>
      </div>
    );
  }

  return null;
}

版本特定功能

功能标志

根据版本显示内容:

mdx
import { VersionFeature } from '../components/VersionFeature';

# API 参考

<VersionFeature minVersion="v3">

## 新的异步 API

v3 引入了新的基于 Promise 的 API:

````javascript
// v3+ 中可用
const result = await api.fetchData();
```

</VersionFeature>

<VersionFeature maxVersion="v2">

## 传统回调 API

v2 及更早版本使用回调:

```javascript
// v2 及更早版本
api.fetchData((error, result) => {
  if (error) {
    console.error(error);
  }
});
```

</VersionFeature>
```

实现 VersionFeature 组件:

```tsx
// components/VersionFeature.tsx
import React from 'react';
import { useLocation } from 'rspress/runtime';

interface VersionFeatureProps {
  minVersion?: string;
  maxVersion?: string;
  children: React.ReactNode;
}

export function VersionFeature({
  minVersion,
  maxVersion,
  children,
}: VersionFeatureProps) {
  const location = useLocation();
  const currentVersion = location.pathname.split('/')[1];

  // 简单版本比较
  const versionNumber = (v: string) => parseInt(v.replace('v', ''), 10);
  const current = versionNumber(currentVersion);

  if (minVersion && current < versionNumber(minVersion)) {
    return null;
  }

  if (maxVersion && current > versionNumber(maxVersion)) {
    return null;
  }

  return <>{children}</>;
}
```

## 版本重定向

### 自动重定向

将根路径重定向到最新版本:

```typescript
export default defineConfig({
  builderConfig: {
    html: {
      redirects: [
        {
          from: '/',
          to: '/v4/',
        },
        {
          from: '/guide',
          to: '/v4/guide/',
        },
      ],
    },
  },
});
```

### 智能版本检测

根据用户上下文重定向:

```tsx
// components/VersionRedirect.tsx
import { useEffect } from 'react';
import { useLocation } from 'rspress/runtime';

export function VersionRedirect() {
  const location = useLocation();

  useEffect(() => {
    // 检查是否访问已归档版本
    const currentVersion = location.pathname.split('/')[1];
    const savedVersion = localStorage.getItem('preferredVersion');

    // 如果用户有首选版本,重定向
    if (savedVersion && savedVersion !== currentVersion) {
      const newPath = location.pathname.replace(
        `/${currentVersion}`,
        `/${savedVersion}`
      );
      window.location.href = newPath;
    }
  }, [location]);

  return null;
}
```

## 版本搜索

### 每个版本的搜索

配置版本特定的搜索:

```typescript
export default defineConfig({
  themeConfig: {
    search: {
      versioned: true,
      // 为每个版本创建单独的搜索索引
      indexes: [
        { version: 'v4', path: '/v4' },
        { version: 'v3', path: '/v3' },
        { version: 'v2', path: '/v2' },
      ],
    },
  },
});
```

## 最佳实践

### 版本命名

1. **语义化版本**: 使用 v1.x, v2.x, v3.x
2. **清晰标签**: "v3.x (Latest)", "v2.x (LTS)", "v1.x (Archived)"
3. **一致性**: 在所有文档中使用相同的命名

### 内容管理

1. **保持同步**: 定期更新所有支持的版本
2. **清晰迁移指南**: 提供版本间迁移路径
3. **突出显示更改**: 标记每个版本中的新功能
4. **归档旧版本**: 清楚标记 EOL 版本

### 用户体验

1. **默认最新版本**: 新用户应看到最新文档
2. **保留用户选择**: 记住用户选择的版本
3. **清晰的视觉提示**: 显示当前版本
4. **简单切换**: 版本间切换应该容易

## 自动化版本管理

### 版本发布脚本

```bash
#!/bin/bash
# scripts/release-version.sh

NEW_VERSION=$1
CURRENT_VERSION=$(jq -r '.latest' versions.json)

if [ -z "$NEW_VERSION" ]; then
  echo "用法: ./release-version.sh v4"
  exit 1
fi

echo "创建新版本: $NEW_VERSION"

# 复制当前版本
cp -r "docs/$CURRENT_VERSION" "docs/$NEW_VERSION"

# 更新 versions.json
jq ".latest = \"$NEW_VERSION\"" versions.json > versions.tmp.json
jq ".versions |= [{
  version: \"$NEW_VERSION\",
  label: \"$NEW_VERSION.x (Latest)\",
  path: \"/$NEW_VERSION\"
}] + ." versions.tmp.json > versions.json

rm versions.tmp.json

echo "✅ 版本 $NEW_VERSION 已创建"
echo "现在更新 docs/$NEW_VERSION 中的内容"
```

### 版本归档脚本

```bash
#!/bin/bash
# scripts/archive-version.sh

VERSION=$1

if [ -z "$VERSION" ]; then
  echo "用法: ./archive-version.sh v2"
  exit 1
fi

echo "归档版本: $VERSION"

# 更新版本标签
jq "(.versions[] | select(.version == \"$VERSION\") | .label) |= . + \" (Archived)\"" \
  versions.json > versions.tmp.json

mv versions.tmp.json versions.json

echo "✅ 版本 $VERSION 已归档"
```

## 故障排除

### 版本链接损坏

**问题**: 链接指向错误的版本

**解决方案**:
```markdown
<!-- ✅ 使用绝对路径 -->
[API 参考](/v3/api/reference)

<!-- ❌ 避免相对路径跨版本 -->
[API 参考](../../v2/api/reference)
```

### 版本选择器未显示

**问题**: 版本选择器不出现

**检查**:
1. `versions.json` 格式正确
2. 配置中启用版本控制
3. 至少配置 2 个版本

### 搜索显示所有版本

**问题**: 搜索结果混合所有版本

**解决方案**:
```typescript
export default defineConfig({
  themeConfig: {
    search: {
      versioned: true, // 启用版本化搜索
    },
  },
});
```

---

## 下一步

- 探索[内置组件](./built-in-components.md)
- 学习[构建能力扩展](./build-extensions.md)
- 了解[自定义搜索](./custom-search.md)

---

::: tip 最佳实践
- 始终维护至少一个 LTS 版本
- 为每个版本提供清晰的迁移指南
- 自动化版本创建过程
- 保持版本 URL 结构一致
- 为旧版本添加清晰的警告横幅
:::

::: warning 常见陷阱
- 不要忘记更新内部链接
- 不要在版本间混合内容
- 不要无限期维护所有版本
- 不要使用模糊的版本标签
- 不要忘记更新搜索索引
:::

::: info 资源
- [语义化版本](https://semver.org/lang/zh-CN/)
- [文档版本管理最佳实践](https://www.writethedocs.org/)
- [Rspress 配置参考](https://rspress.dev/api/config)
:::