Appearance
VitePress 课程计划
课程概述
本课程将带你从零开始构建一个完整的静态站点生成器,学习 VitePress 的核心原理和实现细节。课程分为 8 节课,每节课 20-40 分钟,总时长约 45-60 分钟。
课程目标
- 理解静态站点生成器的工作原理
- 掌握 Markdown 解析和 HTML 渲染
- 学习文件系统操作和构建流程
- 掌握测试驱动开发(TDD)
- 能够构建自己的文档站点
课程大纲
第 1 课:课程介绍与环境准备(5 分钟)
学习目标:
- 了解课程内容和目标
- 搭建开发环境
- 理解项目结构
内容:
- 课程介绍
- 环境准备(Node.js、npm)
- 项目初始化
- 运行第一个测试
实践:
bash
# 初始化项目
npm init -y
# 创建项目结构
mkdir -p src test content
# 运行测试
npm test预期输出:
✔ 所有测试通过第 2 课:Markdown 解析基础(10 分钟)
学习目标:
- 理解 Markdown 语法
- 实现标题解析
- 编写单元测试
内容:
- Markdown 语法简介
- 标题解析算法
- 正则表达式应用
- 单元测试编写
代码实现:
javascript
// 解析标题
function parseHeaders(line) {
const trimmedLine = line.trim()
const match = trimmedLine.match(/^(#{1,6})\s+(.+)$/)
if (!match) return null
const level = match[1].length
const text = match[2].trim()
return {
type: 'header',
level,
text,
id: text.toLowerCase().replace(/\s+/g, '-')
}
}测试:
bash
npm test预期输出:
✔ 应该解析标题
✔ 应该解析不同级别的标题第 3 课:代码块和列表解析(10 分钟)
学习目标:
- 实现代码块解析
- 实现列表解析
- 处理多行内容
内容:
- 代码块语法
- 列表语法
- 状态机设计
- 多行内容处理
代码实现:
javascript
// 解析代码块
function parseCodeBlock(line, language) {
return {
type: 'code',
language,
code: []
}
}
// 解析列表
function parseList(line) {
const match = line.match(/^(\s*)([-*+])\s+(.+)$/)
if (!match) return null
return {
type: 'list',
indent: match[1].length,
marker: match[2],
content: match[3]
}
}测试:
bash
npm test预期输出:
✔ 应该解析代码块
✔ 应该解析列表
✔ 应该处理嵌套列表第 4 课:HTML 渲染(10 分钟)
学习目标:
- 将 tokens 转换为 HTML
- 实现 HTML 转义
- 生成语义化 HTML
内容:
- HTML 标签生成
- 特殊字符转义
- 属性处理
- 语义化标记
代码实现:
javascript
// 转义 HTML 特殊字符
function escapeHtml(text) {
return text
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
}
// 渲染 Markdown tokens 为 HTML
export function renderHtml(tokens) {
let html = ''
for (const token of tokens) {
switch (token.type) {
case 'header':
const tag = `h${token.level}`
html += `<${tag} id="${token.id}">${escapeHtml(token.text)}</${tag}>\n`
break
// ... 其他类型
}
}
return html
}测试:
bash
npm test预期输出:
✔ 应该渲染标题
✔ 应该渲染代码块
✔ 应该渲染列表
✔ 应该转义 HTML 特殊字符第 5 课:Frontmatter 解析(10 分钟)
学习目标:
- 理解 Frontmatter 语法
- 实现 YAML 解析
- 提取元数据
内容:
- Frontmatter 语法
- YAML 格式
- 正则表达式匹配
- 元数据提取
代码实现:
javascript
// 解析 Frontmatter
function parseFrontmatter(content) {
const frontmatterRegex = /^---\n([\s\S]*?)\n---\n([\s\S]*)$/
const match = content.match(frontmatterRegex)
if (!match) {
return {
frontmatter: {},
content
}
}
const frontmatterLines = match[1].split('\n')
const frontmatter = {}
for (const line of frontmatterLines) {
const [key, ...valueParts] = line.split(':')
if (key && valueParts.length > 0) {
frontmatter[key.trim()] = valueParts.join(':').trim()
}
}
return {
frontmatter,
content: match[2]
}
}测试:
bash
npm test预期输出:
✔ 应该解析 Frontmatter
✔ 应该提取标题
✔ 应该处理无 Frontmatter 的情况第 6 课:文件系统操作(10 分钟)
学习目标:
- 读取和写入文件
- 递归扫描目录
- 处理文件路径
内容:
- Node.js 文件系统 API
- 递归算法
- 路径处理
- 异步操作
代码实现:
javascript
import { readFileSync, writeFileSync, readdirSync, statSync } from 'fs'
import { join, extname } from 'path'
// 读取文件内容
function readFile(filePath) {
return readFileSync(filePath, 'utf-8')
}
// 写入文件
function writeFile(filePath, content) {
writeFileSync(filePath, content, 'utf-8')
}
// 递归扫描目录
function scanDirectory(dir, files = []) {
const items = readdirSync(dir)
for (const item of items) {
const fullPath = join(dir, item)
const stat = statSync(fullPath)
if (stat.isDirectory()) {
scanDirectory(fullPath, files)
} else if (extname(item) === '.md') {
files.push(fullPath)
}
}
return files
}测试:
bash
npm test预期输出:
✔ 应该读取文件
✔ 应该写入文件
✔ 应该扫描目录
✔ 应该递归扫描子目录第 7 课:构建流程(10 分钟)
学习目标:
- 协调整个构建流程
- 生成 HTML 模板
- 优化构建性能
内容:
- 构建流程设计
- HTML 模板生成
- 并行处理
- 性能优化
代码实现:
javascript
// 生成 HTML 模板
function generateTemplate(title, content) {
return `<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>${title}</title>
<style>
/* CSS 样式 */
</style>
</head>
<body>
${content}
</body>
</html>`
}
// 构建单个页面
async function buildPage(inputPath, outputPath) {
const content = readFile(inputPath)
const { frontmatter, content: markdownContent } = parseFrontmatter(content)
const tokens = parseMarkdown(markdownContent)
const htmlContent = renderHtml(tokens)
const title = frontmatter.title || '文档'
const html = generateTemplate(title, htmlContent)
writeFile(outputPath, html)
}测试:
bash
npm test
npm run build预期输出:
✔ 应该构建页面
✔ 应该生成 HTML
✔ 构建完成!第 8 课:完整构建与部署(10 分钟)
学习目标:
- 完成完整构建流程
- 部署静态站点
- 性能优化
内容:
- 完整构建流程
- 静态站点部署
- 性能优化技巧
- 扩展功能建议
代码实现:
javascript
// 主构建函数
async function build() {
console.log('开始构建...')
const inputDir = join(process.cwd(), 'content')
const outputDir = join(process.cwd(), 'dist')
// 扫描所有 Markdown 文件
const markdownFiles = scanDirectory(inputDir)
console.log(`找到 ${markdownFiles.length} 个 Markdown 文件`)
// 构建每个页面
for (const inputFile of markdownFiles) {
const relativePath = inputFile.replace(inputDir, '')
const outputPath = join(outputDir, relativePath.replace('.md', '.html'))
// 确保输出目录存在
const outputDirPath = outputPath.split('/').slice(0, -1).join('/')
const { mkdirSync } = await import('fs')
mkdirSync(outputDirPath, { recursive: true })
await buildPage(inputFile, outputPath)
}
console.log('构建完成!')
}
// 运行构建
build().catch(console.error)测试:
bash
npm test
npm run build预期输出:
✔ 所有测试通过
开始构建...
找到 1 个 Markdown 文件
✓ 构建完成: content/index.md -> dist/index.html
构建完成!课程总结
学习成果
完成本课程后,你将能够:
- ✅ 理解静态站点生成器的工作原理
- ✅ 掌握 Markdown 解析和 HTML 渲染
- ✅ 熟练使用 Node.js 文件系统 API
- ✅ 编写高质量的单元测试
- ✅ 构建自己的文档站点
关键概念
- Markdown 解析:将 Markdown 转换为结构化数据
- HTML 渲染:将结构化数据转换为 HTML
- Frontmatter:页面元数据
- 静态站点生成:预生成静态 HTML 文件
- 测试驱动开发:先写测试,再写代码
扩展建议
添加更多 Markdown 语法
- 表格
- 引用
- 链接
- 图片
改进样式
- 暗色模式
- 自定义主题
- 响应式优化
添加功能
- 搜索功能
- 导航栏
- 侧边栏
- 代码高亮
性能优化
- 缓存机制
- 并行处理
- 增量构建
下一步
- 阅读 VitePress 官方文档
- 探索 VitePress 源代码
- 构建自己的文档站点
- 参与开源社区
参考资源
许可证
MIT License

扫描二维码关注"架构师AI杜"公众号,获取更多技术内容和最新动态
