××××

📋 Markdown-it 迁移报告及安装教程

📂纸鸢博客配置/文档类说明
💬

纸鸢博客从 marked 迁移到 markdown-it 的完整报告和手把手安装教程

📅发布于2026-04-06
⏱️阅读时间32 分钟
📝9311 字
📁分类开发文档
🏷️标签
markdown-itmarked迁移教程配置

📋 Markdown-it 迁移报告及安装教程

本文档详细记录了纸鸢博客从 marked 迁移到 markdown-it 的完整过程,包括迁移原因、技术方案、安装步骤和配置说明。


📌 目录

  1. 迁移概述
  2. 迁移原因
  3. 技术方案对比
  4. 安装步骤
  5. 配置详解
  6. 容器语法使用
  7. 样式定制
  8. 常见问题

迁移概述

迁移信息

项目 内容
迁移日期 2026-04-06
原解析器 marked (v17.0.5)
新解析器 markdown-it + 插件生态
代码高亮 highlight.js → Shiki
影响范围 文档渲染页面 ([...slug].astro)

迁移目标

  • ✅ 支持 VitePress 风格的自定义容器语法 (::: tip / ::: warning 等)
  • ✅ 提升代码高亮质量和语言支持
  • ✅ 获得更丰富的 Markdown 扩展能力
  • ✅ 保持现有功能的兼容性

迁移原因

1. 功能扩展需求

marked 的局限性:

  • 原生不支持自定义容器语法
  • 代码高亮需要额外配置
  • 插件生态相对有限

markdown-it 的优势:

  • 丰富的插件生态系统
  • 原生支持容器扩展
  • 更灵活的渲染控制

2. VitePress 兼容性

纸鸢博客希望支持类似 VitePress 的文档体验,特别是:

::: tip 提示
这是提示信息
:::

::: warning 警告
这是警告信息
:::

3. 代码高亮升级

highlight.js 迁移到 Shiki

  • 更准确的语法解析
  • 更好的主题支持
  • 与 VS Code 一致的着色体验

技术方案对比

方案对比表

特性 marked + highlight.js markdown-it + Shiki
容器语法 ❌ 不支持 ✅ 原生支持
代码高亮 highlight.js Shiki (VS Code 同款)
锚点生成 手动实现 markdown-it-anchor 插件
主题切换 手动配置 自动亮/暗主题
语言支持 有限 180+ 语言
插件生态 较少 丰富

最终技术栈

markdown-it (核心解析器)
├── markdown-it-container (自定义容器)
├── markdown-it-anchor (标题锚点)
├── @shikijs/markdown-it (代码高亮)
└── shiki (语法高亮引擎)

安装步骤

第一步:安装依赖包

在项目根目录执行以下命令:

npm install markdown-it markdown-it-container markdown-it-anchor @shikijs/markdown-it shiki

安装包说明:

包名 版本 用途
markdown-it latest Markdown 解析器核心
markdown-it-container latest 自定义容器插件
markdown-it-anchor latest 标题锚点生成
@shikijs/markdown-it latest Shiki 代码高亮集成
shiki latest 语法高亮引擎

第二步:更新导入语句

打开 src/pages/[...slug].astro,替换原有的导入:

原代码(marked):

/* 📝 Markdown 解析相关 */
import { Marked } from 'marked';
import { markedHighlight } from 'marked-highlight';
import hljs from 'highlight.js';

新代码(markdown-it):

/* 📝 Markdown 解析相关 */
import MarkdownIt from 'markdown-it';
import markdownItContainer from 'markdown-it-container';
import markdownItAnchor from 'markdown-it-anchor';
import { fromHighlighter } from '@shikijs/markdown-it';
import { createHighlighter } from 'shiki';

第三步:配置 markdown-it

[...slug].astro 文件中,找到 Markdown 解析部分,替换为以下配置:

/* 💕 创建 Shiki 高亮器 */
const highlighter = await createHighlighter({
  themes: ['github-light', 'github-dark'],
  langs: [
    'javascript', 'typescript', 'jsx', 'tsx', 'vue', 'html', 
    'css', 'scss', 'json', 'markdown', 'bash', 'powershell', 
    'python', 'java', 'rust', 'go', 'sql', 'yaml', 'toml', 
    'xml', 'dockerfile', 'nginx', 'php', 'ruby', 'c', 'cpp', 
    'csharp', 'kotlin', 'swift', 'dart', 'lua', 'perl', 'r', 
    'shellscript', 'vim', 'docker', 'apache', 'graphql', 
    'regex', 'astro'
  ],
});

/* 🔧 配置 markdown-it */
const md = new MarkdownIt({
  html: true,
  linkify: true,
  typographer: true,
});

/* 🎨 使用 Shiki 进行代码高亮 */
md.use(fromHighlighter(highlighter, {
  themes: {
    light: 'github-light',
    dark: 'github-dark',
  },
}));

/* 🔗 添加锚点支持 */
md.use(markdownItAnchor, {
  permalink: false,
  slugify: (s: string) => s.trim().toLowerCase().replace(/\s+/g, '-').replace(/[^\w\-]/g, ''),
});

/* 📦 添加容器支持 - tip */
md.use(markdownItContainer, 'tip', {
  render: (tokens: any[], idx: number) => {
    const token = tokens[idx];
    const title = token.info.trim().slice(3).trim() || '提示';
    if (token.nesting === 1) {
      return `<div class="custom-block tip"><p class="custom-block-title">${title}</p>\n`;
    } else {
      return '</div>\n';
    }
  },
});

/* 📦 添加容器支持 - warning */
md.use(markdownItContainer, 'warning', {
  render: (tokens: any[], idx: number) => {
    const token = tokens[idx];
    const title = token.info.trim().slice(7).trim() || '警告';
    if (token.nesting === 1) {
      return `<div class="custom-block warning"><p class="custom-block-title">${title}</p>\n`;
    } else {
      return '</div>\n';
    }
  },
});

/* 📦 添加容器支持 - danger */
md.use(markdownItContainer, 'danger', {
  render: (tokens: any[], idx: number) => {
    const token = tokens[idx];
    const title = token.info.trim().slice(6).trim() || '危险';
    if (token.nesting === 1) {
      return `<div class="custom-block danger"><p class="custom-block-title">${title}</p>\n`;
    } else {
      return '</div>\n';
    }
  },
});

/* 📦 添加容器支持 - info */
md.use(markdownItContainer, 'info', {
  render: (tokens: any[], idx: number) => {
    const token = tokens[idx];
    const title = token.info.trim().slice(4).trim() || '信息';
    if (token.nesting === 1) {
      return `<div class="custom-block info"><p class="custom-block-title">${title}</p>\n`;
    } else {
      return '</div>\n';
    }
  },
});

/* 📦 添加容器支持 - details */
md.use(markdownItContainer, 'details', {
  render: (tokens: any[], idx: number) => {
    const token = tokens[idx];
    const title = token.info.trim().slice(7).trim() || '详情';
    if (token.nesting === 1) {
      return `<details class="custom-block details"><summary>${title}</summary>\n`;
    } else {
      return '</details>\n';
    }
  },
});

// 🔽使用 markdown-it 解析 Markdown 为 HTML
const rawHtml = md.render(rawContent);

第四步:添加样式

src/components/doczy/_index.scss 中添加颜色变量:

/* ========================================
   🎴 自定义容器颜色变量 - VitePress 风格
   ======================================== */

/* ☀️ Info 信息容器 - 蓝色系 */
$container-info-border: #0ea5e9;
$container-info-title: #0284c7;
$container-info-bg-start: rgba(14, 165, 233, 0.08);
$container-info-bg-end: rgba(56, 189, 248, 0.05);
$container-info-dark-title: #38bdf8;
$container-info-dark-bg-start: rgba(14, 165, 233, 0.15);
$container-info-dark-bg-end: rgba(56, 189, 248, 0.08);

/* 💡 Tip 提示容器 - 绿色系 */
$container-tip-border: #10b981;
$container-tip-title: #059669;
$container-tip-bg-start: rgba(16, 185, 129, 0.08);
$container-tip-bg-end: rgba(52, 211, 153, 0.05);
$container-tip-dark-title: #34d399;
$container-tip-dark-bg-start: rgba(16, 185, 129, 0.15);
$container-tip-dark-bg-end: rgba(52, 211, 153, 0.08);

/* ⚠️ Warning 警告容器 - 橙色系 */
$container-warning-border: #f59e0b;
$container-warning-title: #d97706;
$container-warning-bg-start: rgba(245, 158, 11, 0.08);
$container-warning-bg-end: rgba(251, 191, 36, 0.05);
$container-warning-dark-title: #fbbf24;
$container-warning-dark-bg-start: rgba(245, 158, 11, 0.15);
$container-warning-dark-bg-end: rgba(251, 191, 36, 0.08);

/* 🚨 Danger 危险容器 - 红色系 */
$container-danger-border: #ef4444;
$container-danger-title: #dc2626;
$container-danger-bg-start: rgba(239, 68, 68, 0.08);
$container-danger-bg-end: rgba(248, 113, 113, 0.05);
$container-danger-dark-title: #f87171;
$container-danger-dark-bg-start: rgba(239, 68, 68, 0.15);
$container-danger-dark-bg-end: rgba(248, 113, 113, 0.08);

/* 📋 Details 详情容器 */
$container-details-bg-start: rgba(248, 249, 250, 0.8);
$container-details-bg-end: rgba(255, 255, 255, 0.6);
$container-details-hover-bg: rgba(0, 0, 0, 0.02);
$container-details-dark-bg-start: rgba(30, 30, 46, 0.8);
$container-details-dark-bg-end: rgba(40, 40, 70, 0.6);
$container-details-dark-hover-bg: rgba(255, 255, 255, 0.05);

/* 🎴 自定义容器基础样式 */
$container-bg: rgba(255, 255, 255, 0.7);
$container-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);
$container-shadow-hover: 0 6px 20px rgba(0, 0, 0, 0.1);
$container-dark-bg: rgba(30, 30, 46, 0.6);
$container-dark-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
$container-dark-shadow-hover: 0 6px 20px rgba(0, 0, 0, 0.3);

src/components/doczy/docindex.scss 中添加容器样式(使用上述变量)。

第五步:构建测试

执行构建命令验证配置:

npm run build

如果构建成功,说明迁移完成!


配置详解

markdown-it 基础配置

const md = new MarkdownIt({
  html: true,        // 允许 HTML 标签
  linkify: true,     // 自动转换 URL 为链接
  typographer: true, // 启用排版增强
});

Shiki 代码高亮配置

const highlighter = await createHighlighter({
  themes: ['github-light', 'github-dark'],  // 主题
  langs: ['javascript', 'typescript', ...], // 语言列表
});

md.use(fromHighlighter(highlighter, {
  themes: {
    light: 'github-light',
    dark: 'github-dark',
  },
}));

容器插件配置

容器插件的 render 函数接收两个参数:

  • tokens: Token 数组
  • idx: 当前 token 索引
md.use(markdownItContainer, 'tip', {
  render: (tokens, idx) => {
    const token = tokens[idx];
    const title = token.info.trim().slice(3).trim() || '提示';
    
    if (token.nesting === 1) {
      // 容器开始标签
      return `<div class="custom-block tip"><p class="custom-block-title">${title}</p>\n`;
    } else {
      // 容器结束标签
      return '</div>\n';
    }
  },
});

容器语法使用

基础语法

::: type 标题
内容
:::

支持的类型

类型 语法示例 用途
info ::: info 信息 一般性信息
tip ::: tip 提示 技巧建议
warning ::: warning 警告 潜在问题
danger ::: danger 危险 严重后果
details ::: details 详情 可折叠内容

使用示例

::: tip 💡 最佳实践
这是提示内容,支持 **Markdown** 语法。
:::

::: warning ⚠️ 注意事项
这是警告内容。
:::

::: details 点击展开
这是可折叠的详情内容。
- 列表项 1
- 列表项 2
:::

样式定制

修改颜色变量

编辑 src/components/doczy/_index.scss

/* 修改 info 容器的边框颜色 */
$container-info-border: #3b82f6;  // 改为蓝色

/* 修改 tip 容器的标题颜色 */
$container-tip-title: #10b981;    // 改为绿色

修改容器样式

编辑 src/components/doczy/docindex.scss

.custom-block {
  // 修改圆角
  border-radius: 12px;
  
  // 修改内边距
  padding: 20px 24px;
}

.custom-block.info {
  // 自定义 info 容器样式
  border-left-width: 6px;
}

常见问题

Q1: 构建时报错 “Language xxx not found”

原因: Shiki 未加载该语言

解决:createHighlighterlangs 数组中添加该语言

const highlighter = await createHighlighter({
  themes: ['github-light', 'github-dark'],
  langs: [
    // 添加缺失的语言
    'jsx', 'tsx', 'astro', ...
  ],
});

Q2: 容器语法不生效

原因: 容器插件未正确注册

解决: 检查 [...slug].astro 中是否正确注册了容器类型

// 确保每种类型都注册了
md.use(markdownItContainer, 'tip', { ... });
md.use(markdownItContainer, 'warning', { ... });
md.use(markdownItContainer, 'danger', { ... });
md.use(markdownItContainer, 'info', { ... });
md.use(markdownItContainer, 'details', { ... });

Q3: 代码高亮样式异常

原因: Shiki 主题配置不正确

解决: 确保主题名称正确

md.use(fromHighlighter(highlighter, {
  themes: {
    light: 'github-light',  // 确保主题存在
    dark: 'github-dark',
  },
}));

Q4: 如何添加新的容器类型?

解决: 复制现有容器配置,修改类型名称

md.use(markdownItContainer, 'note', {
  render: (tokens, idx) => {
    const token = tokens[idx];
    const title = token.info.trim().slice(4).trim() || '笔记';
    if (token.nesting === 1) {
      return `<div class="custom-block note"><p class="custom-block-title">${title}</p>\n`;
    } else {
      return '</div>\n';
    }
  },
});

然后在样式文件中添加 .custom-block.note 的样式。


迁移总结

完成的工作

  1. ✅ 成功替换 marked 为 markdown-it
  2. ✅ 集成 Shiki 代码高亮
  3. ✅ 实现 5 种自定义容器类型
  4. ✅ 添加完整的样式支持
  5. ✅ 适配亮/暗色模式

文件变更

文件 变更类型 说明
package.json 修改 添加新依赖
[...slug].astro 修改 替换 Markdown 解析逻辑
_index.scss 修改 添加容器颜色变量
docindex.scss 修改 添加容器样式

🕊️ 白木 原创开发 🔗 gl.baimu.live