书接上回
上回发布的文章提到我把日常用的AI提示词整理成了开源模板库,后面也在GitHub上收获了一些星星(hhh虽然只有2颗)很感激大家愿意点开我的仓库!! 但说实话,那个项目一直有个让我不太满意的地方------它只是一个文件夹里堆满Markdown文件的仓库。
用户想找一个提示词,得先打开仓库,再点进目录,再找到对应的.md文件,打开才能看到内容。这个流程让我想起在Hugging Face上学习时的体验:他们不仅有清晰的左侧导航,还能一键切换文档的不同版本,整个浏览体验非常流畅。
"我的用户不该只在GitHub的代码视图里看文档",我想。 他们应该有一个像样的、可以舒服阅读和查找的文档站。
灵感来源与目标设定
促使我动手的直接原因有两点:
- 在Hugging Face学习时,我发现他们构建的文档站体验极好------左侧导航、全文搜索、明暗主题,阅读起来非常顺畅
- 我意识到 ,如果别人打开我的仓库看到一堆文件夹,可能直接就劝退了。我需要一个能清晰展示所有提示词 ,并且方便用户快速找到想要内容的站点
目标其实很明确:做一个像Datawhale和Hugging Face那样,有漂亮页面、有导航栏、能一键切换文档的站点。
技术选型------为什么是VitePress?
要建文档站,市面上有好几个选择,做一个对比:
| 方案 | 优点 | 缺点 |
|---|---|---|
| Docsify | 轻量,无需构建 | 运行时动态加载,SEO较差 |
| GitBook CLI | 风格经典,导航清晰 | 官方已停止维护 |
| VitePress | Vue生态,性能优秀,支持组件扩展 | 相比 Docsify,需要构建步骤,不能即时预览 |
我最终选择了VitePress。原因很现实:
- Vue组件支持------我预感到后面可能需要一些"骚操作"(比如嵌入交互组件),VitePress对Vue的支持最好
- 构建性能------它基于Vite,热更新和构建速度都很快
- 未来兼容性------我后面还打算做CLI工具,VitePress的生态更契合我未来的方向
- GitHub Pages亲和------VitePress构建出的静态文件,和GitHub Pages配合得天衣无缝
其实中间还考虑过Docusaurus,但它是React生态,我对Vue更熟悉。选技术栈嘛,适合自己的才是最好的。
迭代之路------从"能用"到"好用"
第一回合:把项目变成"真正的网站"
最开始的改动是把所有.md文件从根目录迁移到docs/文件夹,按VitePress的约定组织好目录。同时配置了自动侧边栏------不需要我手动维护,新增一个文件,侧边栏会自动出现。
第二回合:让用户能搜到东西
VitePress默认的本地搜索对中文支持很差------搜"密码重置"可能什么都搜不到,但搜"password"却可以。我要的是用户用中文也能搜到内容。
解决方案是集成vitepress-plugin-pagefind插件。这个插件基于Pagefind实现,对中文分词有优化。
卡点:插件报错
No fs option provided安装后VitePress无法启动,报错提示缺少文件系统访问权限。折腾了半天,排查出是插件版本和VitePress版本有兼容问题,换了个版本后成功集成。虽然花了不少时间,但看到搜索框能正常响应中文关键词时,感觉值了。
第三回合:提供"源码切换"功能(最折腾的一关)
这是整个过程中最复杂、最折腾的一环。用户既要能舒服地阅读渲染好的文档,也要能一键查看和复制原始的Markdown源码,毕竟提示词模板是需要复制去AI对话里用的。
我最初尝试了组件包裹方案------创建一个SourceCodeToggle.vue组件,在每个页面用<template #rendered>包裹内容。但很快撞上了问题:---(YAML frontmatter分隔符)在Vue模板里被当成了HTML标签 ,导致构建报错Element is missing end tag。
csharp
[plugin:vite:vue] docs/05-git/commit-message.md: Element is missing end tag.
这让我花了很长时间来排查。我试过:
- 删除
---前后的换行 - 用
<template v-pre>包裹内容 - 用HTML实体编码
{{替代{{}} - 用
<!-- frontmatter separator -->替换--- - 用
<div v-pre>包裹所有内容
全都没有用。 Vue解析器在编译阶段就会检查模板结构,---一旦出现就会被当作不完整的HTML标签。无论怎么转义或包裹,都绕不开编译器的静态分析。
卡点:组件方案全部失败
折腾了五六个小时,尝试了所有能想到的办法,依然报错。我意识到这条路走不通------在Vue模板里放
---,本质上就是错误的。
最终我换了思路:放弃组件包裹,改用内联Vue方式。
核心思想很简单:把Vue模板代码直接嵌入.md文件,用v-else块包裹原始内容。因为 Vue 在编译 v-else 块时,不会去检查它内部的模板语法是否合法 ,只会原样保留。所以放在里面的 --- 不会被当成 HTML 标签去解析。
vue
<script setup>
import { ref } from 'vue'
import source from './xxx.md?raw'
const showSource = ref(false)
</script>
<button @click="showSource = !showSource">
{{ showSource ? '返回阅读' : '查看源码' }}
</button>
<div v-if="showSource">
<pre><code>{{ source }}</code></pre>
</div>
<div v-else>
<!-- 原始Markdown内容 -->
</div>
这个方案终于跑通了!虽然每个文件都需要嵌入这段代码,但可以写一个自动化脚本来批量处理。
第四回合:全自动化脚本
如果每次新增文件都要手动嵌入Vue代码,那也太不"程序员"了。我让ai帮我写了一个add-toggle.js脚本,做以下事情:
- 递归扫描
docs/下的所有.md文件 - 检测是否已被处理(避免重复操作)
- 提取原始内容,清理残留标签
- 自动计算组件导入路径(处理不同目录深度)
- 用新格式包裹内容并写回文件
集成到package.json后,每次docs:dev或docs:build都会自动触发,新增文件完全不用额外操作。
成果:一个真正可用、可维护的文档站
⭐欢迎大家体验prompt-arsenal文档站!!!你可以看到:
- 左侧自动生成的导航栏
- 右上角中文搜索框
- 每个页面右上角的源码/阅读切换按钮
- 完整的亮色/暗色主题
用户既可以在线阅读,也可以一键切换到源码模式,直接复制提示词去用。
一次有"思维链"的升级
回顾整个过程,我最大的收获是学会了在技术困境中切换思路 。遇到---报错时,我一直试图"绕过"它------转义、包裹、注释掉,全都失败了。直到我意识到,问题不在---本身,而在于我试图让Vue去解析它 。一旦改变了思路,改用v-else块,一切就通了。
这也印证了:当你在一个方向上反复碰壁时,也许应该后退一步,重新审视问题的本质。
如果你也正在尝试把零散的文档整合成一个可用的站点,希望我的这条踩坑路径能给你一些启发。毕竟自己走通的路,踩过的坑,才是最好的经验。
大家也没有类似这种分隔符误编译的经历和好的解决办法?欢迎在评论区留言!