开源项目

开源 Markdown Wiki:把 /md/ 目录变成一个可以直接阅读的站点

写文档这件事,最大的成本从来不是写,而是「写完之后放哪、怎么被看到」。市面上的知识库方案要么要跑一个带数据库的服务,要么把内容锁进特定平台的私有格式。所以我做了 Markdown Wiki 并完整开源:把 /md/ 目录变成一个可以直接阅读的 Wiki 站点——纯静态、零后端,Markdown 文件本身就是数据源。

md.oneyer.cc 就是它的线上实例,本站上一篇 Agent 接管与代码审查 SOP 也是从这个 Wiki 里取的。项目地址:GitHub · yexli/md,MIT 协议,运行时依赖只有三个。

特性一览

特性 说明
文件即数据源 往 md/ 目录丢一个 .md 文件、刷新页面,它就出现在左侧菜单里——不改代码、不重新构建
纯静态 部署后是一堆静态文件,Nginx、对象存储、GitHub Pages 都能直接跑,服务器上不需要 Node
完整 Markdown 标题、列表、表格、引用、代码块、图片、删除线;代码语法高亮覆盖常见语言
全文搜索 标题与正文一起搜,标题命中排在前面,正文命中带一段上下文
本文大纲 屏幕够宽时右侧出现四级嵌套目录,滚动自动高亮当前章节,点击平滑跳转
复制与下载 顶栏「复制全文」复制纯文本、「下载」导出 Markdown 原文件;每个代码块右上角可单独复制
响应式 桌面三栏、平板收窄、手机抽屉式菜单,表格与长代码横向滚动
安全渲染 所有 HTML 走 DOMPurify 白名单,script、onerror=、javascript: 一律剔除

快速开始

Shell
# 本地开发
npm install
npm run dev        # http://localhost:5173

# 构建与预览
npm run build      # 构建到 dist/
npm run preview    # 本地预览构建产物

把 .md 文件放进 md/ 目录,刷新页面即可。

使用方式

添加文档

TEXT
md/
├── 项目介绍.md
├── 开发指南/
│   ├── 架构设计.md
│   └── 前端实现.md
└── images/
    └── architecture.svg

支持 .md 和 .markdown,子目录会原样变成可折叠的菜单分组,不需要修改任何代码。程序启动时先尝试读取服务器的 /md/ 目录列表,读到什么就显示什么;如果服务器没有开启目录列表(比如对象存储),则回退到构建时打包进 JS 的那份文档快照。

菜单标题

优先取正文里第一个一级标题,没有则回退到文件名:

MARKDOWN
# 这是我想要的菜单标题

正文内容……

路径规则

Markdown 里的相对路径,以当前文件所在目录为基准:

MARKDOWN
<!-- 文件位置:md/开发指南/架构设计.md -->
![图](./images/a.png)      <!-- → /md/开发指南/images/a.png -->
![图](../images/b.png)     <!-- → /md/images/b.png -->
![图](/images/c.png)       <!-- 以 / 开头时以 /md/ 为基准 → /md/images/c.png -->
[架构](../开发指南/架构设计.md)   <!-- 站内链接,点击后无刷新切换 -->

外链会在新标签页打开。图片放在 md/ 目录里的任何位置都可以。

三种部署姿势

构建产物是纯静态文件,npm run build 之后把 dist/ 里的内容发布出去即可,服务器上不需要 Node。

托管平台

Cloudflare Pages、Vercel、Netlify、腾讯云 EdgeOne Pages 都可以,连上仓库后 push 自动部署,构建配置统一填:

配置项 值
构建命令 npm run build
输出目录 dist
Node 版本 由 .nvmrc 决定(22)

自己的服务器(Nginx / 宝塔)

服务器上的 md/ 是你自己的文档,更新界面时不该去动它,所以要分两步打包:

pack.shShell
# file: pack.sh
npm run build
python deploy/pack.py      # 生成不含 md/ 的部署包

产物是 wiki-dist.zip 和 wiki-dist.tar.gz,里面只有 index.html 和 assets/,解压到站点根目录即完成更新,服务器上已有的 md/ 原封不动。需要连本地文档一起打包时加 --with-md。

想让往服务器 md/ 目录里丢文件就即时生效,给 Nginx 加两行:

wiki.confNginx
# file: wiki.conf
location /md/ {
    autoindex on;
    autoindex_format json;
}

# 图片缓存:正则只匹配到文件结尾,不要写成 ^/md/images/,那样会把目录请求也截走
location ~* ^/md/.*\.(png|jpe?g|gif|svg|webp|ico)$ {
    expires 7d;
}

autoindex_format json 需要 Nginx 1.7.9 以上(宝塔、各大面板自带的版本都满足)。没配也能正常跑,只是新增文档后需要重新构建上传。

对象存储与 GitHub Pages

腾讯云 COS、阿里云 OSS 这类没有目录列表能力的托管,传 dist/ 内容即可(记得开启静态网站模式、把 index.html 设为默认首页),新增文档后重新构建上传。

GitHub Pages 则在仓库 Settings → Pages → Source 选择 GitHub Actions,之后推送到 main 即自动部署,工作流会自动解析仓库路径,子路径下的 base 不需要手工配置。

与 GitHub 保持同步

md/ 目录是运行时读取的,所以日常只需要同步它,不用构建、不用重启任何服务:

sync-wiki.shShell
# file: sync-wiki.sh
cd /www/wwwroot
git clone https://github.com/yexli/md.git md
cp md/deploy/sync-wiki.sh /www/wwwroot/sync-wiki.sh
chmod +x /www/wwwroot/sync-wiki.sh
/www/wwwroot/sync-wiki.sh

然后在宝塔计划任务里加一个 Shell 脚本任务定时执行它(比如每 5 分钟)。之后本地写完文档 git push,服务器到点自动跟上。

!
GitHub 是文档的唯一来源:同步脚本用 rsync –delete 做镜像同步,也就是说不要在服务器上直接改 md/ 里的文件——任何手工改动都会在下一轮同步时被覆盖。

技术选型:运行时只有三个依赖

依赖 用途
markdown-it Markdown 解析
highlight.js 代码语法高亮
DOMPurify HTML 白名单过滤

构建工具是 Vite,只在开发和构建时使用。目录树、搜索、复制、大纲、URL 状态全部手写,没有引入路由库、状态管理库或 UI 组件库——这个体量的项目,引入框架的收益撑不起它的成本。

边界与取舍

  • 服务器模式下启动时会把 /md/ 里所有文档读进内存(菜单标题和全文搜索都需要),几十到几百篇都很轻;上千篇再考虑改成按需加载。
  • 回退模式下文档内容会打包进 JS,产物约 320 KB(gzip 约 125 KB)。
  • 大纲收录到四级标题为止,更深的层级不显示,避免目录过碎。
  • 不提供编辑、评论、协作、权限。Markdown 文件在编辑器里改,版本交给 Git。
  • 本地改完样式后如果页面没更新,重启一次 npm run dev(偶发的样式模块缓存不失效)。

写在最后

这个项目的出发点很简单:知识库的维护成本应该趋近于零。写一个 .md 文件、git push,剩下的——渲染、目录、搜索、部署——都不该是作者要操心的事。如果你也在找一个不锁格式、不跑服务、Git 即版本的文档方案,欢迎拿去用:GitHub · yexli/md,Issue 和 PR 都欢迎。

评论

留言无需注册,填个昵称就能说上两句。

发表评论

✓ 无需注册,提交即显示 · 首次留言会进入审核队列