VitePress 自动化部署笔记方案
本文详细介绍如何将私有仓库中的 Markdown 笔记使用 VitePress 自动部署到 GitHub Pages (github.io)。
📋 目录
方案概述
🎯 部署架构
私有仓库 (ww1820/Note)
├── Markdown 源文件
├── .vitepress/config.mts
├── .github/workflows/deploy.yml
└── package.json
↓ (GitHub Actions 自动构建)
↓
构建产物 (.vitepress/dist/)
↓ (推送到公开仓库)
↓
公开仓库 (ww1820/ww1820.github.io)
├── index.html
├── assets/
└── 笔记页面
↓ (GitHub Pages 自动发布)
↓
访问地址: https://ww1820.github.io/ 核心特性
- ✅ 私有仓库:源文件保密,只公开构建结果
- ✅ 自动部署:推送代码即自动构建和发布
- ✅ 选择性发布:可排除特定文件夹(如私密笔记)
- ✅ 全文搜索:内置本地搜索功能
- ✅ 响应式设计:支持多端访问
- ✅ 自动侧边栏:自动生成导航结构
环境准备
系统要求
- Node.js: >= 18.0.0 (推荐 20.x LTS)
- npm: >= 9.0.0
- Git: >= 2.0
检查当前环境
bash
# 检查 Node.js 版本
node -v
# 检查 npm 版本
npm -v
# 检查 Git 版本
git -v Node.js 多版本管理
为什么需要版本管理?
- VitePress 1.x 需要 Node.js >= 18
- 不同项目可能需要不同的 Node.js 版本
- 方便在多个版本间切换
方案 1:使用 nvm (推荐)
nvm (Node Version Manager) 是最流行的 Node.js 版本管理工具。
安装 nvm
Linux / macOS:
bash
# 方法 1:使用 curl
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
# 方法 2:使用 wget
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
# 加载 nvm
source ~/.bashrc
# 或者
source ~/.zshrc Windows:
使用 nvm-windows:
- 下载
nvm-setup.exe - 运行安装程序
- 以管理员身份打开 PowerShell 或 CMD
验证安装
bash
nvm --version
# 输出: 0.39.7 常用命令
bash
# 列出所有可用的 Node.js 版本
nvm list-remote
# Windows 使用
nvm list available
# 安装最新的 LTS 版本
nvm install --lts
# 安装特定版本
nvm install 20
nvm install 18.19.0
# 列出已安装的版本
nvm list
nvm ls
# 使用特定版本
nvm use 20
nvm use 18
# 设置默认版本
nvm alias default 20
# 查看当前使用的版本
nvm current
# 在当前 shell 中使用指定版本运行命令
nvm exec 20 node --version
# 卸载特定版本
nvm uninstall 16 项目级版本管理
在项目根目录创建 .nvmrc 文件:
text
20 使用时:
bash
# 进入项目目录
cd /path/to/Note
# 自动使用 .nvmrc 指定的版本
nvm use
# 或者
nvm install 方案 2:使用 n
n 是一个简单的 Node.js 版本管理器。
安装 n
bash
# 方法 1:通过 npm 全局安装(需要已有 Node.js)
sudo npm install -g n
# 方法 2:通过脚本安装
curl -L https://bit.ly/n-install | bash 常用命令
bash
# 安装最新的 LTS 版本
sudo n lts
# 安装最新版本
sudo n latest
# 安装特定版本
sudo n 20
sudo n 18.19.0
# 列出所有已安装的版本
n list
n ls
# 交互式选择版本
sudo n
# 删除特定版本
sudo n rm 16.0.0
# 删除除当前版本外的所有版本
sudo n prune
# 查看已安装的版本
n --version 方案 3:使用 Volta
Volta 是一个快速、可靠的 JavaScript 工具链管理器。
安装 Volta
bash
# Linux / macOS
curl https://get.volta.sh | bash
# Windows (PowerShell)
# 下载并运行安装程序
# https://docs.volta.sh/guide/getting-started 常用命令
bash
# 安装 Node.js
volta install node@20
volta install node@lts
# 固定项目使用的 Node.js 版本
volta pin node@20
# 安装并固定 npm 版本
volta install npm@10
volta pin npm@10
# 列出已安装的工具
volta list
# 查看当前版本
node -v
npm -v 优势:
- 自动为每个项目使用正确的 Node.js 版本
- 速度快,无需手动切换版本
- 支持固定 npm、yarn 等工具版本
方案对比
| 特性 | nvm | n | Volta |
|---|---|---|---|
| 安装简易度 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| 切换速度 | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 跨平台支持 | Linux/macOS/Windows | Linux/macOS | Linux/macOS/Windows |
| 自动切换 | 需 shell 集成 | ❌ | ✅ |
| 社区支持 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ |
| 推荐指数 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
推荐:
- 日常使用: nvm(功能完善,社区成熟)
- 快速切换: Volta(自动切换,速度快)
- 简单需求: n(命令简单,易上手)
项目配置
目录结构
Note/ # 项目根目录
├── .github/
│ └── workflows/
│ └── deploy.yml # GitHub Actions 部署配置
├── .vitepress/
│ ├── config.mts # VitePress 主配置
│ ├── utils/
│ │ └── sidebar.ts # 自动侧边栏生成工具
│ ├── theme/
│ │ └── index.ts # 自��义主题(可选)
│ ├── dist/ # 构建输出目录(自动生成)
│ └── cache/ # 缓存目录(自动生成)
├── 0 收集箱/ # 私密文件夹(不发布)
├── 1 笔记/
│ ├── index.md # 目录索引页
│ └── [笔记文件.md]
├── 2 计算机/
│ ├── index.md
│ ├── 编程语言/
│ │ ├── index.md
│ │ └── [笔记文件.md]
│ └── 数据结构与算法/
│ └── [笔记文件.md]
├── 3 问题记录/
│ ├── index.md
│ └── [问题记录.md]
├── 4 工作/ # 私密文件夹(不发布)
├── 5 工具/
│ ├── index.md
│ └── [工具笔记.md]
├── pic/ # 图片资源目录
├── index.md # 网站首页
├── package.json # 项目依赖配置
├── .gitignore # Git 忽略配置
├── .nvmrc # Node.js 版本锁定(可选)
└── README.md # 项目说明 配置文件详解
1. package.json
json
{
"name": "note",
"version": "1.0.0",
"description": "记录工作学习笔记",
"type": "module",
"scripts": {
"docs:dev": "vitepress dev",
"docs:build": "vitepress build",
"docs:preview": "vitepress preview"
},
"devDependencies": {
"vitepress": "^1.0.0"
},
"keywords": ["notes", "vitepress"],
"author": "ww1820",
"license": "MIT",
"engines": {
"node": ">=18.0.0",
"npm": ">=9.0.0"
}
} 关键字段说明:
type: "module": 启用 ES 模块支持scripts: 定义常用命令engines: 指定 Node.js 和 npm 版本要求
2. .vitepress/config.mts
VitePress 的核心配置文件:
typescript
import { defineConfig } from 'vitepress'
import { fileURLToPath, URL } from 'node:url'
import { generateSidebar } from './utils/sidebar'
// 获取当前文件的目录路径
const __dirname = fileURLToPath(new URL('.', import.meta.url))
export default defineConfig({
// 站点元信息
title: '个人笔记',
description: '记录工作学习笔记',
// 部署基础路径
// 部署到 https://username.github.io/ 使用 '/'
// 部署到 https://username.github.io/repo/ 使用 '/repo/'
base: '/',
// 语言设置
lang: 'zh-CN',
// 忽略死链检查(推荐开启)
ignoreDeadLinks: true,
// 启用最后更新时间
lastUpdated: true,
// 主题配置
themeConfig: {
// 顶部导航栏
nav: [
{ text: '首页', link: '/' },
{ text: '笔记', link: '/1 笔记/' },
{ text: '计算机', link: '/2 计算机/' },
{ text: '问题记录', link: '/3 问题记录/' },
{ text: '工具', link: '/5 工具/' }
],
// 侧边栏(自动生成)
sidebar: {
'/1 笔记/': [
{
text: '📝 笔记',
items: generateSidebar('1 笔记', __dirname)
}
],
'/2 计算机/': [
{
text: '💻 计算机',
items: generateSidebar('2 计算机', __dirname)
}
],
'/3 问题记录/': [
{
text: '🔧 问题记录',
items: generateSidebar('3 问题记录', __dirname)
}
],
'/5 工具/': [
{
text: '🛠️ 工具',
items: generateSidebar('5 工具', __dirname)
}
]
},
// 社交链接
socialLinks: [
{ icon: 'github', link: 'https://github.com/ww1820' }
],
// 本地搜索
search: {
provider: 'local',
options: {
locales: {
root: {
translations: {
button: {
buttonText: '搜索笔记',
buttonAriaLabel: '搜索笔记'
},
modal: {
noResultsText: '无法找到相关结果',
resetButtonTitle: '清除查询条件',
footer: {
selectText: '选择',
navigateText: '切换'
}
}
}
}
}
}
},
// 编辑链接
editLink: {
pattern: 'https://github.com/ww1820/Note/edit/master/:path',
text: '在 GitHub 上编辑此页'
},
// 页脚
footer: {
message: '基于 VitePress 构建',
copyright: 'Copyright © 2026 ww1820'
},
// 最后更新时间文本
lastUpdated: {
text: '最后更新于',
formatOptions: {
dateStyle: 'short',
timeStyle: 'short'
}
},
// 文档页脚导航
docFooter: {
prev: '上一页',
next: '下一页'
},
// 页面大纲配置
outline: {
label: '页面导航',
level: [2, 3] // 显示 h2 和 h3 标题
},
// 其他中文化配置
returnToTopLabel: '返回顶部',
sidebarMenuLabel: '菜单',
darkModeSwitchLabel: '外观'
},
// Markdown 配置
markdown: {
lineNumbers: true, // 显示行号
image: {
lazyLoading: true // 图片懒加载
}
},
// Vue 配置
vue: {
template: {
compilerOptions: {
whitespace: 'preserve',
isCustomElement: (tag) => tag.startsWith('v-')
}
}
}
}) 3. .vitepress/utils/sidebar.ts
自动生成侧边栏的工具函数:
typescript
import { readdirSync, statSync } from 'fs'
import { join } from 'path'
export interface SidebarItem {
text: string
link?: string
items?: SidebarItem[]
collapsed?: boolean
}
/**
* 生成侧边栏配置
* @param dir 相对于项目根目录的路径
* @param rootDir VitePress 配置文件所在目录
*/
export function generateSidebar(dir: string, rootDir: string): SidebarItem[] {
const items: SidebarItem[] = []
const fullPath = join(rootDir, '..', dir)
try {
const files = readdirSync(fullPath)
// 排序:目录在前,文件在后
files.sort((a, b) => {
const aPath = join(fullPath, a)
const bPath = join(fullPath, b)
const aIsDir = statSync(aPath).isDirectory()
const bIsDir = statSync(bPath).isDirectory()
if (aIsDir && !bIsDir) return -1
if (!aIsDir && bIsDir) return 1
return a.localeCompare(b, 'zh-CN')
})
for (const file of files) {
// 跳过隐藏文件和特殊文件
if (file.startsWith('.') || file.startsWith('_')) {
continue
}
const filePath = join(fullPath, file)
const stat = statSync(filePath)
if (stat.isDirectory()) {
// 处理子目录
const subItems = generateSidebarForDirectory(dir, file, rootDir)
if (subItems.length > 0) {
items.push({
text: file,
collapsed: true, // 默认折叠
items: subItems
})
}
} else if (file.endsWith('.md') && file !== 'index.md') {
// 处理 Markdown 文件
items.push({
text: file.replace('.md', ''),
link: `/${dir}/${file}`
})
}
}
} catch (error) {
console.warn(`⚠️ 无法读取目录: ${dir}`, error)
}
return items
}
/**
* 生成子目录的侧边栏
*/
function generateSidebarForDirectory(
parentDir: string,
subDir: string,
rootDir: string
): SidebarItem[] {
const items: SidebarItem[] = []
const fullPath = join(rootDir, '..', parentDir, subDir)
try {
const files = readdirSync(fullPath)
files.sort((a, b) => a.localeCompare(b, 'zh-CN'))
for (const file of files) {
if (file.startsWith('.') || file.startsWith('_')) {
continue
}
const filePath = join(fullPath, file)
const stat = statSync(filePath)
if (stat.isDirectory()) {
// 递归处理更深层的子目录
const deepItems = generateSidebarForDeepDirectory(
parentDir,
subDir,
file,
rootDir
)
if (deepItems.length > 0) {
items.push({
text: file,
collapsed: true,
items: deepItems
})
}
} else if (file.endsWith('.md') && file !== 'index.md') {
items.push({
text: file.replace('.md', ''),
link: `/${parentDir}/${subDir}/${file}`
})
}
}
} catch (error) {
console.warn(`⚠️ 无法读取子目录: ${parentDir}/${subDir}`)
}
return items
}
/**
* 处理更深层的目录
*/
function generateSidebarForDeepDirectory(
parentDir: string,
subDir: string,
deepDir: string,
rootDir: string
): SidebarItem[] {
const items: SidebarItem[] = []
const fullPath = join(rootDir, '..', parentDir, subDir, deepDir)
try {
const files = readdirSync(fullPath)
files.sort((a, b) => a.localeCompare(b, 'zh-CN'))
for (const file of files) {
if (file.startsWith('.') || file.startsWith('_')) {
continue
}
if (file.endsWith('.md') && file !== 'index.md') {
items.push({
text: file.replace('.md', ''),
link: `/${parentDir}/${subDir}/${deepDir}/${file}`
})
}
}
} catch (error) {
console.warn(`⚠️ 无法读取深层目录: ${parentDir}/${subDir}/${deepDir}`)
}
return items
} 4. index.md (网站首页)
markdown
---
layout: home
hero:
name: "个人笔记"
text: "记录工作学习的点点滴滴"
tagline: 持续学习,不断进步 💡
actions:
- theme: brand
text: 开始阅读
link: /1 笔记/
- theme: alt
text: 在 GitHub 上查看
link: https://github.com/ww1820/Note
features:
- icon: 📝
title: 学习笔记
details: 记录日常学习心得和知识总结
link: /1 笔记/
- icon: 💻
title: 计算机技术
details: 编程、开发、技术栈相关笔记
link: /2 计算机/
- icon: 🔧
title: 问题记录
details: 开发过程中遇到的问题和解决方案
link: /3 问题记录/
- icon: 🛠️
title: 工具分享
details: 提高效率的工具和技巧
link: /5 工具/
---
## 📚 关于本站
这是我的个人学习笔记站点,使用 VitePress 构建,记录工作和学习过程中的心得体会。
### 特色功能
- 🔍 **全文搜索**:快速定位内容
- 📱 **响应式设计**:完美适配各种设备
- 🌙 **深色模式**:保护您的眼睛
- 🚀 **快速加载**:优化的性能体验
欢迎浏览和交流! 5. 目录索引文件示例
每个笔记目录需要一个 index.md 文件:
markdown
---
title: 笔记
---
# 📝 笔记
这里是我的学习笔记汇总。
::: tip 💡 提示
使用左侧导航栏浏览所有笔记,侧边栏会自动显示目录结构。
:::
## 📚 内容组织
笔记按主题和时间组织,使用搜索功能可以快速定位内容。
## 🔖 最近更新
查看侧边栏中的笔记列表,按时间倒序排列。 6. .gitignore
text
# 依赖
node_modules/
package-lock.json
# VitePress
.vitepress/dist/
.vitepress/cache/
.temp/
# 日志
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# 操作系统
.DS_Store
Thumbs.db
# IDE
.vscode/
.idea/
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# 环境变量
.env
.env.local
.env.*.local 自动化部署
GitHub Actions 配置
1. 创建 Personal Access Token
- 访问 GitHub Settings → Developer settings → Personal access tokens → Tokens (classic)
- 点击 Generate new token (classic)
- 设置:
- Note:
Deploy to GitHub Pages - Expiration: 自定义(建议 1 年)
- Scopes: 勾选
repo完整权限
- Note:
- 点击 Generate token
- 立即复制 token(只显示一次)
2. 添加 Secret 到私有仓库
- 进入私有仓库 Settings → Secrets and variables → Actions
- 点击 New repository secret
- 设置:
- Name:
PERSONAL_ACCESS_TOKEN - Secret: 粘贴刚才的 token
- Name:
- 点击 Add secret
3. 创建 GitHub Actions 工作流
yaml
name: Deploy to GitHub Pages
# 触发条件
on:
push:
branches: [master] # 推送到 master 分支时触发
workflow_dispatch: # 支持手动触发
# 权限设置
permissions:
contents: read
# 任务定义
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
# 1. 检出代码
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0 # 获取完整历史(用于显示最后更新时间)
# 2. 设置 Node.js 环境
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
# 3. 安装依赖
- name: Install dependencies
run: npm ci
# 4. 构建 VitePress
- name: Build with VitePress
run: npm run docs:build
env:
NODE_ENV: production
# 5. 部署到公开仓库
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
personal_token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
external_repository: ww1820/ww1820.github.io # 目标仓库
publish_branch: main # 目标分支
publish_dir: .vitepress/dist # 构建输出目录
user_name: 'github-actions[bot]'
user_email: 'github-actions[bot]@users.noreply.github.com'
force_orphan: true # 清空旧提交历史(可选) 部署流程
1. 本地修改笔记
↓
2. 提交到 Git
$ git add .
$ git commit -m "更新笔记"
$ git push origin master
↓
3. GitHub Actions 自动触发
├─ 检出代码
├─ 安装依赖
├─ 构建 VitePress
└─ 推送到公开仓库
↓
4. GitHub Pages 自动发布
↓
5. 访问网站
https://ww1820.github.io/ 配置 GitHub Pages
- 进入公开仓库 (ww1820.github.io) 的 Settings → Pages
- 设置:
- Source: Deploy from a branch
- Branch: main
- Folder: / (root)
- 点击 Save
- 等待 1-2 分钟,页面会显示访问地址
本地开发
初始化项目
bash
# 1. 克隆仓库
git clone https://github.com/ww1820/Note.git
cd Note
# 2. 使用正确的 Node.js 版本
nvm use 20
# 或者(如果有 .nvmrc)
nvm use
# 3. 安装依赖
npm install
# 4. 启动开发服务器
npm run docs:dev 常用命令
bash
# 开发模式(热重载)
npm run docs:dev
# 构建生产版本
npm run docs:build
# 预览构建结果
npm run docs:preview
# 清理缓存
rm -rf .vitepress/cache .vitepress/dist 常见问题
1. Node.js 版本错误
错误信息:
Error: Not supported 解决方案:
bash
# 检查版本
node -v
# 升级到 Node.js 20
nvm install 20
nvm use 20 2. 构建失败:Duplicate attribute
错误信息:
[vite:vue] 某某.md (7:28): Duplicate attribute. 原因: Markdown Front Matter 格式错误(开头有空行)
解决方案:
yaml
# ❌ 错误
---
title: 标题
---
# ✅ 正确
---
title: 标题
--- 批量修复:
bash
# 查找问题文件
grep -r "^---$" --include="*.md" -A 2 . | grep "^$"
# 手动编辑或使用脚本修复 3. 目录访问 404
问题: 访问 /1 笔记/ 显示 404
原因: 缺少 index.md 文件
解决方案:
bash
# 创建索引文件
echo "# 笔记\n\n使用左侧导航栏浏览。" > "1 笔记/index.md" 4. 图片无法显示
问题: 图片路径错误或图片未提交
解决方案:
markdown
<!-- ✅ 使用相对路径 -->

<!-- ✅ 使用绝对路径 -->

<!-- ❌ 避免使用外部链接(可能失效) --> 确保图片已提交:
bash
git add pic/
git commit -m "添加图片" 5. 部署失败:Permission denied
错误信息:
Error: The process '/usr/bin/git' failed with exit code 128 原因: Personal Access Token 无效或权限不足
解决方案:
- 检查 token 是否过期
- 确认 token 有
repo完整权限 - 重新生成 token 并更新 Secret
6. 搜索功能不工作
问题: 本地搜索无结果
原因: 搜索索引未生成或配置错误
解决方案:
typescript
// .vitepress/config.mts
export default defineConfig({
themeConfig: {
search: {
provider: 'local', // 确保设置为 'local'
options: {
// ... 配置选项
}
}
}
}) 重新构建:
bash
rm -rf .vitepress/cache
npm run docs:build 7. 语法高亮警告
警告信息:
The language 'plantuml' is not loaded, falling back to 'txt' 解决方案:
bash
# 替换为支持的语言
find . -name "*.md" -exec sed -i 's/```plantuml/```text/g' {} \;
find . -name "*.md" -exec sed -i 's/```mysql/```sql/g' {} \; 性能优化
1. 图片优化
bash
# 压缩图片(使用 ImageMagick)
find pic/ -name "*.jpg" -exec convert {} -quality 85 {} \;
find pic/ -name "*.png" -exec convert {} -quality 85 {} \; 2. 构建优化
typescript
export default defineConfig({
// ...
build: {
chunkSizeWarningLimit: 1000, // 提高警告阈值
}
}) 3. 启用缓存
yaml
- name: Cache dependencies
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node- 4. 忽略不需要构建的文件夹
typescript
export default defineConfig({
// ...
// 🎯 排除不需要构建的文件和目录
srcExclude: [
'**/0 收集箱/**', // 排除 "0 收集箱" 目录
'**/4 工作/**', // 排除 "4 工作" 目录
'**/node_modules/**', // 排除 node_modules
'**/.vitepress/**', // 排除 .vitepress
'**/README.md' // 排除 README(如果不需要)
]
// ...
}) 进阶技巧
1. 自定义域名
如果您有自己的域名:
text
notes.yourdomain.com 在 DNS 设置中添加 CNAME 记录:
notes.yourdomain.com → ww1820.github.io 更新 base 配置:
typescript
export default defineConfig({
base: '/', // 使用自定义域名时设置为 '/'
}) 2. 添加评论系统
使用 Giscus(基于 GitHub Discussions):
bash
npm install -D @giscus/vue typescript
import DefaultTheme from 'vitepress/theme'
import Giscus from '@giscus/vue'
export default {
extends: DefaultTheme,
enhanceApp({ app }) {
app.component('Giscus', Giscus)
}
} 3. Google Analytics
typescript
export default defineConfig({
head: [
[
'script',
{ async: '', src: 'https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX' }
],
[
'script',
{},
`window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-XXXXXXXXXX');`
]
]
}) 总结
通过本方案,您可以:
- ✅ 使用私有仓库保护源文件
- ✅ 自动构建和部署到 GitHub Pages
- ✅ 灵活管理 Node.js 版本
- ✅ 自动生成侧边栏导航
- ✅ 获得出色的阅读体验
推荐工作流:
- 本地使用 nvm 管理 Node.js 版本
- 使用 VitePress 开发模式实时预览
- 提交代码到私有仓库
- GitHub Actions 自动部署
- 访问 GitHub Pages 查看效果
参考资源
最后更新: 2026-02-13
作者: ww1820
许可: MIT License