Skip to content

VitePress 课程计划

课程概述

本课程将带你从零开始构建一个完整的静态站点生成器,学习 VitePress 的核心原理和实现细节。课程分为 8 节课,每节课 20-40 分钟,总时长约 45-60 分钟。

课程目标

  • 理解静态站点生成器的工作原理
  • 掌握 Markdown 解析和 HTML 渲染
  • 学习文件系统操作和构建流程
  • 掌握测试驱动开发(TDD)
  • 能够构建自己的文档站点

课程大纲

第 1 课:课程介绍与环境准备(5 分钟)

学习目标:

  • 了解课程内容和目标
  • 搭建开发环境
  • 理解项目结构

内容:

  1. 课程介绍
  2. 环境准备(Node.js、npm)
  3. 项目初始化
  4. 运行第一个测试

实践:

bash
# 初始化项目
npm init -y

# 创建项目结构
mkdir -p src test content

# 运行测试
npm test

预期输出:

✔ 所有测试通过

第 2 课:Markdown 解析基础(10 分钟)

学习目标:

  • 理解 Markdown 语法
  • 实现标题解析
  • 编写单元测试

内容:

  1. Markdown 语法简介
  2. 标题解析算法
  3. 正则表达式应用
  4. 单元测试编写

代码实现:

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 分钟)

学习目标:

  • 实现代码块解析
  • 实现列表解析
  • 处理多行内容

内容:

  1. 代码块语法
  2. 列表语法
  3. 状态机设计
  4. 多行内容处理

代码实现:

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

内容:

  1. HTML 标签生成
  2. 特殊字符转义
  3. 属性处理
  4. 语义化标记

代码实现:

javascript
// 转义 HTML 特殊字符
function escapeHtml(text) {
  return text
    .replace(/&/g, '&')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
}

// 渲染 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 解析
  • 提取元数据

内容:

  1. Frontmatter 语法
  2. YAML 格式
  3. 正则表达式匹配
  4. 元数据提取

代码实现:

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 分钟)

学习目标:

  • 读取和写入文件
  • 递归扫描目录
  • 处理文件路径

内容:

  1. Node.js 文件系统 API
  2. 递归算法
  3. 路径处理
  4. 异步操作

代码实现:

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 模板
  • 优化构建性能

内容:

  1. 构建流程设计
  2. HTML 模板生成
  3. 并行处理
  4. 性能优化

代码实现:

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 分钟)

学习目标:

  • 完成完整构建流程
  • 部署静态站点
  • 性能优化

内容:

  1. 完整构建流程
  2. 静态站点部署
  3. 性能优化技巧
  4. 扩展功能建议

代码实现:

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
构建完成!

课程总结

学习成果

完成本课程后,你将能够:

  1. ✅ 理解静态站点生成器的工作原理
  2. ✅ 掌握 Markdown 解析和 HTML 渲染
  3. ✅ 熟练使用 Node.js 文件系统 API
  4. ✅ 编写高质量的单元测试
  5. ✅ 构建自己的文档站点

关键概念

  • Markdown 解析:将 Markdown 转换为结构化数据
  • HTML 渲染:将结构化数据转换为 HTML
  • Frontmatter:页面元数据
  • 静态站点生成:预生成静态 HTML 文件
  • 测试驱动开发:先写测试,再写代码

扩展建议

  1. 添加更多 Markdown 语法

    • 表格
    • 引用
    • 链接
    • 图片
  2. 改进样式

    • 暗色模式
    • 自定义主题
    • 响应式优化
  3. 添加功能

    • 搜索功能
    • 导航栏
    • 侧边栏
    • 代码高亮
  4. 性能优化

    • 缓存机制
    • 并行处理
    • 增量构建

下一步

  1. 阅读 VitePress 官方文档
  2. 探索 VitePress 源代码
  3. 构建自己的文档站点
  4. 参与开源社区

参考资源

许可证

MIT License

架构师AI杜公众号二维码

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