从 VuePress 迁移
如果你有 VuePress(1.x 或 2.x)项目,本指南将帮助你完整迁移到 VitePress。
为什么迁移?
| 特性 | VuePress 1.x | VuePress 2.x | VitePress |
|---|---|---|---|
| 构建工具 | Webpack | Vite | Vite |
| 开发启动 | 较慢(秒级) | 快 | 极快(毫秒级) |
| 热更新 | 较慢 | 快 | 即时 |
| Vue 版本 | Vue 2 | Vue 3 | Vue 3 |
| 打包体积 | 较大 | 中等 | 更小 |
| 配置类型 | CommonJS | ESM | ESM + TS |
| Markdown 高亮 | Prism.js | Shiki | Shiki |
| 内置搜索 | 有 | 有 | 有(更优) |
| 主题系统 | extend | extends | extends + 插槽 |
| 官方维护 | 维护模式 | 维护模式 | 活跃开发 |
VuePress 状态
VuePress 目前处于维护模式,不再接受新功能。VitePress 是 Vue 生态推荐的文档站点生成器。
迁移概览
┌──────────────┐ 1. 评估 ┌──────────────┐ 2. 迁移 ┌──────────────┐
│ VuePress │ ─────────────→ │ 过渡项目 │ ─────────────→ │ VitePress │
│ 项目 │ 评估工作量 │ 基础迁移 │ 细节完善 │ 项目 │
└──────────────┘ └──────────────┘ └──────────────┘
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ 重命名文件 │ │ 优化功能 │
│ 转换配置 │ │ 利用新特性 │
│ 替换插件 │ │ 性能优化 │
└──────────────┘ └──────────────┘预估工作量
| 项目规模 | 页面数 | 预计时间 | 主要工作 |
|---|---|---|---|
| 小型 | < 20 页 | 2-4 小时 | 配置迁移 + 插件替换 |
| 中型 | 20-100 页 | 1-2 天 | 配置 + 自定义主题 + 组件 |
| 大型 | > 100 页 | 3-5 天 | 完整迁移 + 多语言 + 插件 |
第一步:项目评估
检查兼容性
迁移前先评估项目的复杂度:
# 检查项目使用的 VuePress 版本
cat package.json | grep vuepress
# 检查插件列表
cat package.json | grep @vuepress/plugin
# 检查自定义主题
ls -la docs/.vuepress/theme/
# 检查自定义组件数量
find docs/.vuepress -name "*.vue" | wc -l难度评估
| 因素 | 低难度 | 中难度 | 高难度 |
|---|---|---|---|
| 自定义主题 | 使用默认主题 | 少量覆盖 | 完全自定义 |
| 插件数量 | 0-3 个 | 3-10 个 | 10+ 个 |
| Vue 组件 | 简单展示 | 有状态组件 | 复杂交互 |
| 多语言 | 无 | 2 种语言 | 3+ 种语言 |
| 构建流程 | 简单 | 有自定义 | 复杂 CI/CD |
第二步:基础迁移
重命名文件和目录
#!/bin/bash
# migrate-rename.sh - 文件重命名脚本
# 1. 重命名配置目录
mv docs/.vuepress docs/.vitepress
# 2. 重命名配置文件
mv docs/.vitepress/config.js docs/.vitepress/config.mts
# 3. 重命名首页文件
find docs -name "README.md" -not -path "*/node_modules/*" | while read file; do
dir=$(dirname "$file")
mv "$file" "$dir/index.md"
done
# 4. 重命名主题入口
if [ -f docs/.vitepress/theme/index.js ]; then
mv docs/.vitepress/theme/index.js docs/.vitepress/theme/index.ts
fi
echo "文件重命名完成"更新依赖
# 移除 VuePress 依赖
npm uninstall vuepress @vuepress/core @vuepress/cli
# 移除 VuePress 插件(后面逐个替换)
npm uninstall @vuepress/plugin-back-to-top @vuepress/plugin-search
# 安装 VitePress
npm install -D vitepress
# 如果需要 Vue 运行时(使用自定义组件时)
npm install vue更新 package.json 脚本
{
"scripts": {
"dev": "vitepress dev docs",
"build": "vitepress build docs",
"preview": "vitepress preview docs"
}
}第三步:配置迁移
配置文件完整对照
VuePress 1.x (config.js):
module.exports = {
title: '我的站点',
description: '站点描述',
base: '/',
host: '0.0.0.0',
port: 8080,
head: [
['link', { rel: 'icon', href: '/favicon.ico' }]
],
markdown: {
lineNumbers: true
},
themeConfig: {
logo: '/logo.png',
nav: [
{ text: '指南', link: '/guide/' },
{ text: 'API', link: '/api/' }
],
sidebar: {
'/guide/': [
{
title: '入门',
collapsable: true,
children: [
'/guide/intro',
'/guide/getting-started'
]
}
]
},
search: true,
searchMaxSuggestions: 10,
lastUpdated: '最后更新',
repo: 'user/repo',
editLinks: true,
editLinkText: '编辑此页',
smoothScroll: true
},
plugins: [
'@vuepress/back-to-top',
'@vuepress/medium-zoom',
['@vuepress/search', { searchMaxSuggestions: 10 }]
]
}VitePress (config.mts):
import { defineConfig } from 'vitepress'
export default defineConfig({
title: '我的站点',
description: '站点描述',
base: '/',
host: '0.0.0.0',
port: 8080,
head: [
['link', { rel: 'icon', href: '/favicon.ico' }]
],
markdown: {
lineNumbers: true
},
themeConfig: {
logo: '/logo.png',
nav: [
{ text: '指南', link: '/guide/' },
{ text: 'API', link: '/api/' }
],
sidebar: {
'/guide/': [
{
text: '入门', // title → text
collapsed: true, // collapsable → collapsed
items: [ // children → items
{ text: '介绍', link: '/guide/intro' },
{ text: '开始', link: '/guide/getting-started' }
]
}
]
},
search: {
provider: 'local' // 内置搜索,无需插件
},
lastUpdated: {
text: '最后更新于' // 更灵活的配置
},
socialLinks: [ // repo → socialLinks
{ icon: 'github', link: 'https://github.com/user/repo' }
],
editLink: { // editLinks + editLinkText → editLink
pattern: 'https://github.com/user/repo/edit/main/docs/:path',
text: '编辑此页'
},
externalLinkIcon: true // 替代 smoothScroll(已移除)
}
})配置字段映射
| VuePress 字段 | VitePress 字段 | 说明 |
|---|---|---|
themeConfig.nav[].link | themeConfig.nav[].link | 相同 |
themeConfig.sidebar[].title | themeConfig.sidebar[].text | 名称变更 |
themeConfig.sidebar[].collapsable | themeConfig.sidebar[].collapsed | 拼写修正 |
themeConfig.sidebar[].children | themeConfig.sidebar[].items | 名称变更 |
themeConfig.sidebar[].children[] (字符串) | themeConfig.sidebar[].items[] (对象) | 必须用 { text, link } |
themeConfig.repo | themeConfig.socialLinks | 结构变更 |
themeConfig.editLinks | themeConfig.editLink | 合并为对象 |
themeConfig.editLinkText | themeConfig.editLink.text | 移入 editLink |
themeConfig.search | themeConfig.search.provider | 结构变更 |
themeConfig.searchMaxSuggestions | themeConfig.search.options | 配置方式变更 |
themeConfig.smoothScroll | 移除 | VitePress 默认平滑滚动 |
themeConfig.lastUpdated | themeConfig.lastUpdated.text | 结构变更 |
侧边栏自动转换脚本
// scripts/convert-sidebar.ts
// 将 VuePress 侧边栏配置转换为 VitePress 格式
interface VPSidebarItem {
text: string
link?: string
collapsed?: boolean
items?: VPSidebarItem[]
}
interface VPSidebarGroup {
title: string
collapsable?: boolean
children?: (string | { title: string; children: string[] })[]
}
function convertSidebarItem(item: any): VPSidebarItem {
const result: VPSidebarItem = {
text: item.title || item.text || ''
}
if (item.collapsable !== undefined) {
result.collapsed = item.collapsable
}
if (item.children) {
result.items = item.children.map((child: any) => {
if (typeof child === 'string') {
// 字符串转为对象格式
const parts = child.split('/')
const fileName = parts[parts.length - 1] || parts[parts.length - 2]
return {
text: fileName
.replace(/[-_]/g, ' ')
.replace(/\b\w/g, c => c.toUpperCase()),
link: child
}
}
if (child.children) {
return convertSidebarItem(child)
}
return {
text: child.title || child.text || '',
link: child.link
}
})
}
return result
}
function convertSidebar(vuepressSidebar: Record<string, VPSidebarGroup[]>): Record<string, VPSidebarItem[]> {
const result: Record<string, VPSidebarItem[]> = {}
for (const [path, groups] of Object.entries(vuepressSidebar)) {
result[path] = groups.map(convertSidebarItem)
}
return result
}
// 使用示例
const vuepressSidebar = {
'/guide/': [
{
title: '入门',
collapsable: true,
children: [
'/guide/intro',
'/guide/getting-started'
]
}
]
}
console.log(JSON.stringify(convertSidebar(vuepressSidebar), null, 2))第四步:主题迁移
默认主题覆盖
VuePress 使用 styles/ 目录覆盖样式:
/* .vuepress/styles/palette.styl */
$accentColor = #3eaf7c
$textColor = #2c3e50
$borderColor = #eaecef
$codeBgColor = #282c34VitePress 使用 CSS 变量:
/* .vitepress/theme/styles/index.css */
:root {
--vp-c-brand-1: #3eaf7c;
--vp-c-brand-2: #4ab58a;
--vp-c-brand-3: #5cc49b;
--vp-c-brand-soft: rgba(62, 175, 124, 0.14);
}样式变量映射
| VuePress 变量 | VitePress 变量 | 说明 |
|---|---|---|
$accentColor | --vp-c-brand-1 | 主题色 |
$textColor | --vp-c-text-1 | 正文颜色 |
$borderColor | --vp-c-border | 边框颜色 |
$codeBgColor | --vp-c-bg-soft + Shiki 主题 | 代码背景 |
$bgColor | --vp-c-bg | 背景色 |
$sidebarWidth | --vp-sidebar-width | 侧边栏宽度 |
自定义主题迁移
VuePress 自定义主题结构:
.vuepress/theme/
├── index.js # 主题入口
├── Layout.vue # 主布局
├── NotFound.vue # 404 页面
└── components/ # 主题组件VitePress 扩展默认主题:
// .vitepress/theme/index.ts
import DefaultTheme from 'vitepress/theme'
import './styles/index.css'
export default {
extends: DefaultTheme, // 注意:extends 而非 extend
enhanceApp({ app }) {
// 注册全局组件
},
setup() {
// 布局级 setup
}
}Layout 组件迁移
VuePress Layout.vue:
<!-- VuePress Layout.vue -->
<template>
<div class="theme-container">
<Navbar />
<Sidebar />
<Home v-if="$page.frontmatter.home" />
<Page v-else />
</div>
</template>VitePress 使用布局插槽:
<!-- .vitepress/theme/Layout.vue -->
<script setup lang="ts">
import DefaultTheme from 'vitepress/theme'
const { Layout } = DefaultTheme
</script>
<template>
<Layout>
<template #layout-top>
<!-- 全局顶部内容 -->
</template>
<template #doc-after>
<!-- 文档底部内容 -->
</template>
</Layout>
</template>第五步:插件替换
插件对照表
| VuePress 插件 | VitePress 替代方案 | 迁移难度 |
|---|---|---|
@vuepress/plugin-back-to-top | 内置支持 | ⭐ |
@vuepress/plugin-search | search.provider: 'local' | ⭐ |
@vuepress/plugin-medium-zoom | medium-zoom 包 | ⭐⭐ |
@vuepress/plugin-pwa | vite-plugin-pwa | ⭐⭐ |
@vuepress/plugin-google-analytics | head 配置 | ⭐ |
@vuepress/plugin-comment | Giscus / Utterances | ⭐⭐ |
@vuepress/plugin-feed | 自行实现 RSS | ⭐⭐⭐ |
@vuepress/plugin-i18n-ui | VitePress 内置 i18n | ⭐⭐ |
@vuepress/plugin-container | VitePress 内置容器 | ⭐ |
@vuepress/plugin-nprogress | 自定义进度条组件 | ⭐⭐ |
@vuepress/plugin-smooth-scroll | 内置支持 | ⭐ |
@vuepress/plugin-registration | enhanceApp | ⭐ |
中等复杂度替换示例
Medium Zoom
npm install medium-zoom// .vitepress/theme/index.ts
import DefaultTheme from 'vitepress/theme'
import mediumZoom from 'medium-zoom'
import { onMounted, watch, nextTick } from 'vue'
import { useRoute } from 'vitepress'
export default {
extends: DefaultTheme,
setup() {
const route = useRoute()
const initZoom = () => {
mediumZoom('.main img', { background: 'var(--vp-c-bg)' })
}
onMounted(initZoom)
watch(() => route.path, () => nextTick(initZoom))
}
}PWA 支持
npm install -D vite-plugin-pwa// .vitepress/config.mts
import { defineConfig } from 'vitepress'
import { VitePWA } from 'vite-plugin-pwa'
export default defineConfig({
vite: {
plugins: [
VitePWA({
registerType: 'autoUpdate',
manifest: {
name: '我的文档站',
short_name: 'MyDocs',
theme_color: '#3eaf7c',
icons: [
{ src: '/pwa-192x192.png', sizes: '192x192', type: 'image/png' },
{ src: '/pwa-512x512.png', sizes: '512x512', type: 'image/png' }
]
}
})
]
}
})第六步:组件迁移
Vue 2 → Vue 3 变更
生命周期
// Vue 2(VuePress 1.x)
export default {
mounted() { },
destroyed() { }
}
// Vue 3(VitePress)
import { onMounted, onUnmounted } from 'vue'
setup() {
onMounted(() => { })
onUnmounted(() => { })
}| Vue 2 | Vue 3 | 说明 |
|---|---|---|
beforeCreate | setup() | Composition API |
created | setup() | Composition API |
beforeMount | onBeforeMount | 组合式 API |
mounted | onMounted | 组合式 API |
beforeUpdate | onBeforeUpdate | 组合式 API |
updated | onUpdated | 组合式 API |
beforeDestroy | onBeforeUnmount | 重命名 |
destroyed | onUnmounted | 重命名 |
全局 API
// Vue 2(VuePress 1.x)
Vue.component('MyComponent', MyComponent)
Vue.use(MyPlugin)
Vue.prototype.$myProperty = value
// Vue 3(VitePress)
app.component('MyComponent', MyComponent)
app.use(MyPlugin)
app.config.globalProperties.$myProperty = valueFilters 移除
<!-- Vue 2(VuePress 1.x) -->
<p>{{ date | formatDate }}</p>
<!-- Vue 3(VitePress) -->
<p>{{ formatDate(date) }}</p>// 改为方法或计算属性
function formatDate(date: string): string {
return new Date(date).toLocaleDateString('zh-CN')
}v-model 变更
<!-- Vue 2(VuePress 1.x) -->
<MyComponent v-model="value" />
<!-- 子组件:props: ['value'], emit: 'input' -->
<!-- Vue 3(VitePress) -->
<MyComponent v-model="value" />
<!-- 子组件:props: ['modelValue'], emit: 'update:modelValue' -->事件监听
<!-- Vue 2(VuePress 1.x) -->
<template>
<button @click.native="handleClick">按钮</button>
</template>
<!-- Vue 3(VitePress) -->
<template>
<!-- .native 修饰符已移除,默认监听原生事件 -->
<button @click="handleClick">按钮</button>
</template>页面数据访问
VuePress 通过 $page 和 $site 访问:
<!-- VuePress 1.x -->
<template>
<div>
<h1>{{ $page.title }}</h1>
<p>{{ $page.frontmatter.date }}</p>
<p>{{ $site.title }}</p>
</div>
</template>VitePress 使用 useData() 组合式函数:
<!-- VitePress -->
<script setup lang="ts">
import { useData } from 'vitepress'
const { page, site, frontmatter, theme } = useData()
</script>
<template>
<div>
<h1>{{ page.value.title }}</h1>
<p>{{ frontmatter.value.date }}</p>
<p>{{ site.value.title }}</p>
</div>
</template>数据映射
| VuePress | VitePress | 说明 |
|---|---|---|
$page.title | page.value.title | 页面标题 |
$page.frontmatter | frontmatter.value | Frontmatter |
$page.path | page.value.path | 页面路径 |
$site.title | site.value.title | 站点标题 |
$site.description | site.value.description | 站点描述 |
$site.themeConfig | theme.value | 主题配置 |
$route | useRoute() | 路由信息 |
$router | useRouter() | 路由器 |
全局组件注册
VuePress 自动注册:
.vuepress/components/
├── MyButton.vue → 自动全局注册为 <MyButton>
└── CustomCard.vue → 自动全局注册为 <CustomCard>VitePress 需手动注册:
// .vitepress/theme/index.ts
import DefaultTheme from 'vitepress/theme'
import MyButton from './components/MyButton.vue'
import CustomCard from './components/CustomCard.vue'
export default {
extends: DefaultTheme,
enhanceApp({ app }) {
app.component('MyButton', MyButton)
app.component('CustomCard', CustomCard)
}
}批量注册
可以使用 import.meta.glob 批量注册组件,避免逐个手动添加。
// .vitepress/theme/index.ts
import DefaultTheme from 'vitepress/theme'
const components = import.meta.glob('./components/*.vue', { eager: true })
export default {
extends: DefaultTheme,
enhanceApp({ app }) {
for (const [path, definition] of Object.entries(components)) {
const componentName = path
.split('/')
.pop()
?.replace(/\.\w+$/, '')
if (componentName) {
app.component(componentName, (definition as any).default)
}
}
}
}第七步:Markdown 迁移
内置容器
VuePress 和 VitePress 的容器语法相同:
::: tip
提示内容
:::VitePress 额外支持 info、danger、details 类型:
::: info
信息内容
:::
::: danger
危险警告
:::
::: details 点击展开
折叠内容
:::代码块差异
VuePress 使用 Prism.js:
// VuePress 配置
markdown: {
lineNumbers: true
}VitePress 使用 Shiki:
// VitePress 配置
markdown: {
theme: { light: 'github-light', dark: 'github-dark' },
lineNumbers: true
}Shiki 的优势:
- 更准确的语法高亮
- 支持 VSCode 主题
- 支持行高亮
ts {1,3-5} - 支持代码组
Emoji 语法
VuePress 需安装插件:
plugins: ['@vuepress/plugin-emoji']VitePress 内置支持:
:tada: :rocket: :bulb:第八步:多语言迁移
VuePress 使用 locales 配置:
// VuePress
module.exports = {
locales: {
'/': { lang: 'zh-CN' },
'/en/': { lang: 'en-US' }
},
themeConfig: {
locales: {
'/': { selectText: '选择语言' },
'/en/': { selectText: 'Languages' }
}
}
}VitePress 配置结构相似:
// VitePress
export default defineConfig({
locales: {
root: { label: '简体中文', lang: 'zh-CN' },
en: { label: 'English', lang: 'en-US' }
},
themeConfig: {
locales: {
root: { outlineLabel: '大纲' },
en: { outlineLabel: 'On This Page' }
}
}
})主要差异
| VuePress | VitePress | 说明 |
|---|---|---|
locales['/'] | locales.root | 根路径表示方式 |
locales['/en/'] | locales.en | 子路径不需要尾斜杠 |
themeConfig.locales | themeConfig.locales | 相同结构 |
| 需要对应目录结构 | 自动映射目录 | VitePress 更灵活 |
第九步:构建和部署
构建命令
# VuePress
npx vuepress build docs
# VitePress
npx vitepress build docs输出目录
| 工具 | 默认输出 | 修改方式 |
|---|---|---|
| VuePress | docs/.vuepress/dist | dest 配置 |
| VitePress | docs/.vitepress/dist | outDir 配置 |
部署配置更新
GitHub Pages 示例:
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm ci
- run: npm run build # VitePress 构建命令
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: docs/.vitepress/dist # VitePress 输出目录自动化迁移脚本
#!/bin/bash
# migrate-vuepress-to-vitepress.sh
# 自动化迁移 VuePress 项目到 VitePress
set -e
DOCS_DIR="${1:-docs}"
echo "🔧 开始迁移 VuePress → VitePress..."
echo "📁 文档目录: $DOCS_DIR"
# 1. 重命名目录
if [ -d "$DOCS_DIR/.vuepress" ]; then
echo " → 重命名 .vuepress 为 .vitepress"
mv "$DOCS_DIR/.vuepress" "$DOCS_DIR/.vitepress"
fi
# 2. 重命名配置文件
if [ -f "$DOCS_DIR/.vitepress/config.js" ]; then
echo " → 重命名 config.js 为 config.mts"
mv "$DOCS_DIR/.vitepress/config.js" "$DOCS_DIR/.vitepress/config.mts"
elif [ -f "$DOCS_DIR/.vitepress/config.yml" ]; then
echo " → 重命名 config.yml 为 config.mts"
mv "$DOCS_DIR/.vitepress/config.yml" "$DOCS_DIR/.vitepress/config.mts"
fi
# 3. 重命名首页文件
find "$DOCS_DIR" -name "README.md" -not -path "*/node_modules/*" | while read file; do
dir=$(dirname "$file")
echo " → 重命名 $file 为 $dir/index.md"
mv "$file" "$dir/index.md"
done
# 4. 重命名主题入口
if [ -f "$DOCS_DIR/.vitepress/theme/index.js" ]; then
echo " → 重命名 theme/index.js 为 index.ts"
mv "$DOCS_DIR/.vitepress/theme/index.js" "$DOCS_DIR/.vitepress/theme/index.ts"
fi
# 5. 更新依赖
echo " → 更新 package.json 依赖"
npm uninstall vuepress @vuepress/core @vuepress/cli 2>/dev/null || true
npm install -D vitepress vue
echo ""
echo "✅ 基础迁移完成!"
echo ""
echo "⚠️ 还需要手动完成以下步骤:"
echo " 1. 更新 config.mts 配置语法(参考本文档第三步)"
echo " 2. 替换不兼容的插件(参考本文档第五步)"
echo " 3. 迁移 Vue 2 组件到 Vue 3(参考本文档第六步)"
echo " 4. 更新 CSS 样式变量(参考本文档第四步)"
echo " 5. 运行 npm run dev 测试"迁移检查清单
基础设施
- [ ] 重命名
.vuepress为.vitepress - [ ] 重命名
config.js为config.mts - [ ] 重命名所有
README.md为index.md - [ ] 更新
package.json依赖和脚本 - [ ] 删除
package-lock.json并重新npm install
配置
- [ ] 转换为
defineConfig()包裹 - [ ]
sidebar[].title→sidebar[].text - [ ]
sidebar[].collapsable→sidebar[].collapsed - [ ]
sidebar[].children→sidebar[].items - [ ]
sidebar[].children[]字符串 →{ text, link }对象 - [ ]
themeConfig.repo→themeConfig.socialLinks - [ ]
themeConfig.editLinks→themeConfig.editLink - [ ]
themeConfig.search→themeConfig.search.provider
主题和样式
- [ ] 主题入口
extend→extends - [ ] Stylus 变量 → CSS 变量
- [ ] 更新颜色变量名
- [ ] 移除 VuePress 特定样式类名
插件
- [ ] 列出所有 VuePress 插件
- [ ] 找到每个插件的替代方案
- [ ] 迁移插件配置
- [ ] 移除无用插件
组件
- [ ] Vue 2 选项式 API → Vue 3 组合式 API
- [ ]
filters→ 方法或计算属性 - [ ]
$page/$site→useData() - [ ]
$route/$router→useRoute()/useRouter() - [ ] 事件
.native修饰符移除 - [ ]
v-modelprop 名变更 - [ ] 手动注册全局组件
测试
- [ ] 开发服务器正常启动
- [ ] 所有页面可正常访问
- [ ] 导航和侧边栏正常
- [ ] 搜索功能正常
- [ ] 暗色模式切换正常
- [ ] 自定义组件正常渲染
- [ ] 构建成功
- [ ] 部署成功
常见问题
Q: 可以渐进式迁移吗?
可以。在同一个项目中同时安装 VuePress 和 VitePress,逐个模块迁移:
# 同时安装两个工具
npm install -D vuepress vitepress但建议创建新分支一次性迁移,避免长期维护两套配置。
Q: VuePress 2.x 迁移更简单吗?
是的。VuePress 2.x 已经基于 Vite 和 Vue 3,迁移到 VitePress 主要是配置结构变更,组件和插件差异较小。
Q: 自定义主题非常复杂怎么办?
如果 VuePress 自定义主题非常复杂(几百个组件),建议分阶段迁移:
- 先用 VitePress 默认主题 + 插槽,实现基础功能
- 逐步迁移自定义组件
- 最后替换为完全自定义布局
Q: 迁移后构建失败怎么排查?
# 1. 清除缓存
rm -rf node_modules/.vitepress
# 2. 调试模式构建
npx vitepress build docs --debug
# 3. 检查 TypeScript 错误
npx tsc --noEmit相关资源
- 迁移专题指南 — 从其他工具迁移
- VitePress 版本升级 — VitePress 内部升级
- 配置文件详解 — VitePress 完整配置
- 使用 Vue 组件 — 在 Markdown 中使用 Vue