惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
LangChain Blog
有赞技术团队
有赞技术团队
博客园_首页
IT之家
IT之家
爱范儿
爱范儿
量子位
小众软件
小众软件
Jina AI
Jina AI
WordPress大学
WordPress大学
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 聂微东
The Cloudflare Blog
博客园 - 司徒正美
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
V2EX
大猫的无限游戏
大猫的无限游戏
月光博客
月光博客
雷峰网
雷峰网
V
Visual Studio Blog
博客园 - Franky
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
美团技术团队
Last Week in AI
Last Week in AI
S
SegmentFault 最新的问题

V2EX

我用 AI 写代码,但终端管理反而成了累赘——于是我做了 codux [调研] 各位在公司都用什么 ide 和 agent 写代码? 老运维 share 一个运维平台 看到有公司考核 token 指标,很好奇大家上个月的 AI 账单是多少 GLM-Coding 调用持续报错: z.ai 的 Lite 套餐几乎无法使用,官方 Pro/Max 是否稳定? 现在还有什么渠道可以稳定安全地使用 Claude 吗? 上海漕河泾内推,本组有 2 个 hc,一个后端,一个前端,预算都是 20k 左右,不打卡,氛围好 如果 V2EX 上有一组不永久保存聊天记录(比如只保存 7 天或者 24 小时)的聊天室,那么会开启哪些有用或者有趣的可能? gemini cli 貌似挂了,一直返回 403 第一次在自媒体上赚到钱 收集了最近在使用的低价 GPT, Gemini,邮箱等 AI 会员的小店合集 讨论个大实话:现在企业还在说 AI 编程提效 20%, 30%的,真的太落后,没用懂 AI。因为包括很多前沿公司,已经狂奔到提效 200%-500%的情况 [招聘][远程][币安] 前端/后端/QA/iOS/Android 至少 3 年以上经验 目前有大量 HC 欢迎投递 Chatgpt Pro 用量用不完的可以开这些设置 面试的时候好像遇到钓鱼了,给各位避个坑 cursor 年续费 22 号到期, 自动续费是否还是老的计次套餐呢 被两件破事毁掉的一下午,琐碎的内耗消磨人的精力 使用 Planet 存储 Codex 的会话或者重要信息 如果业务部门领导不要你开发功能,而是要求你教会它用 claude code 开发功能,你会怎么做? 分享一个 MacOS 接绿联 CM818 USB 转 DP 转接器使用感受 我的 HR 朋友 10 年老 Java ,非全大专,大家帮忙看看简历 开源了一个 AI 口语练习工具,音素级发音评分,完全免费可自部署 V2EX 上有哪些你觉得很有趣、印象深刻的妹纸? 字节为啥不出个国内版 Vercel? 有在大马的朋友吗? 问个运营商问题 你们在有领导的公司大群发过的最大胆的消息是什么 公司裁员,目前没有工作。想试试摆摊,做一个移动鲜啤打酒车 我的硬盘 Memblaze Pblaze 5 Linux 下不识别,给 Linux 内核提交了补丁, AI 说有望被合并 只有我一个人觉得 codex 不好用?
Vibe Coding 了一个博客框架
yuanyuan11 · 2026-06-20 · via V2EX

title: date: 2026-04-24

从 2022 年自己搭建博客至今,中间折腾了不少东西,框架换来换去,记录在这里 博客再改版 但是没有一个让我自己最满意的。而为了写个博客去学习它的模板语法、配置方式,感觉很麻烦,一直都想自己写一个,直到最近才抽空用 copilot 写了一个基于 python 的框架,核心代码就几百行,不依赖任何外部库,自己控制所有逻辑,想咋样就咋样,出问题也知道去哪修。

这个博客框架有以下几个我比较喜欢的特性:

短链

_slug_hash 函数根据每个文章的文件夹名称,使用 CRC24 哈希并通过 base36 输出 5 位全小写短链,直接映射到主域名下面,比如 https://jiaoyuan.org/5xbok/,既干净又便于分享,也不会产生冲突。

BASE62 = "0123456789abcdefghijklmnopqrstuvwxyz"
RESERVED_SLUGS = frozenset({"assets", "logs", "readme", "page", "atom", "posts"})

def _crc24(data: bytes) -> int:
    crc = 0xB704CE
    for b in data:
        crc ^= b << 16
        for _ in range(8):
            crc <<= 1
            if crc & 0x1000000:
                crc ^= 0x1864CFB
    return crc & 0xFFFFFF

def _slug_hash(name: str) -> str:
    val = _crc24(name.encode())
    result = []
    while val > 0:
        result.append(BASE62[val % len(BASE62)])
        val //= len(BASE62)
    return "".join(reversed(result)).rjust(5, "0")

load_posts 读取文章时自动计算短链,并且通过 used 集合做唯一性检查,撞了自动加后缀:

def load_posts(cfg, engine):
    used = set()
    for folder in sorted(posts_dir.iterdir()):
        slug = _slug_hash(folder.name)
        if slug in used or slug in RESERVED_SLUGS:
            i = 1
            while f"{slug}-{i}" in used:
                i += 1
            slug = f"{slug}-{i}"
        used.add(slug)

渲染优化

现在很多博客框架我觉得都太复杂,为了适应大多数人的要求,加入了很多冗余的功能,我这里想办法减少了前端渲染和 js 的加载。Markdown 的渲染是自己写的,没有用任何现有的解析器。支持的语法包括标题、段落、列表、引用、表格、代码块、行内样式这些常用功能,日常写文章完全够用。

代码块这里支持 bash 、python 、c 、r 、html 、css 、c# 这些语言的语法高亮,由 _highlight_source 方法在构建时即直接渲染为带 token 类名的 HTML 标签,不加载任何 JS ,速度快了很多,并且适配暗色和亮色模式。

def _highlight_source(self, code: str, lang: str) -> str:
    kw = {"python": {"def", "class", "if", "else", "for", ...}, ...}
    token_re = re.compile(
        r"(?P<comment>#..."
        r")|(?P<string>\"...\")"
        r"|(?P<keyword>\b...\b)"
        r"|(?P<number>\b\d+\.?\d+\b)"
    )
    for m in token_re.finditer(code):
        if m.lastgroup == "keyword":
            out.append(f'<span class="tok-k">{text}</span>')
        elif m.lastgroup == "string":
            out.append(f'<span class="tok-s">{text}</span>')

CSS 变量根据主题切换,无需额外 JS 处理高亮颜色:

:root {
  --tok-k: #0550ae; /* keyword */
  --tok-s: #0a3069; /* string */
  --tok-c: #6e7781; /* comment */
}
[data-theme="dark"] {
  --tok-k: #79c0ff;
  --tok-s: #a5d6ff;
  --tok-c: #8b949e;
}

页面生成后直接写静态 HTML 文件,Nginx 直出,不需要任何后端处理或数据库查询:

def _write(public_dir: Path, rel_out_dir: str, html_text: str) -> None:
    out = public_dir / rel_out_dir
    out.mkdir(parents=True, exist_ok=True)
    (out / "index.html").write_text(html_text, encoding="utf-8")

数学公式渲染用的 KaTeX ,通过正则检测文中是否包含 $...$$$...$$ 或者 front matter 是否声明 math: true,只有在需要的时候才加载 KaTeX 的 CSS 和 JS:

MATH_RE = re.compile(r"\$\$.*?\$\$|\$[^$\n]+\$", re.DOTALL)

def _load_markdown_file(path, rel_url, out_dir, is_log, engine):
    body = ...
    has_math = bool(MATH_RE.search(body)) or bool(meta.get("math"))
    return ContentItem(has_math=has_math, ...)

评论系统

评论基于 GitHub Issues 。每篇文章底部有一个按钮,默认链接到新建 issue 页面,标题已经预填好。同时页面加载后会通过 GitHub API 搜索匹配该标题的现有 issue ,如果找到就直接把按钮链接跳转过去,不需要建一堆重复的讨论。

# config 里配置评论仓库
cf = {"comment_repo": "imjiaoyuan/imjiaoyuan.github.io"}

# 渲染评论区域
btn = f'<a href="https://github.com/{repo}/issues/new?title={title}">...</a>'

# 加载后自动匹配已有 issue
fetch("https://api.github.com/search/issues?q=" + q)
  .then(r => r.json())
  .then(data => {
    if (data.total_count > 0) btn.href = data.items[0].html_url
  })

不用额外注册任何第三方评论服务,仓库的 Issues 就是数据库。


整个博客就一个 GitHub 仓库,内容、源码、生成的静态文件都在里面。提交后 GitHub Actions 会自动执行构建,生成 HTML 然后部署到 Pages 。整个过程全自动,不用手动敲命令,也不用登录什么后台。本地构建的时候可以使用 run.py,其包含三个命令:

python run.py -d            # 构建静态站点到 public/
python run.py -s            # 构建并启动开发服务器(热重载)
python run.py -n post-name  # 创建新文章

写博客对我来说就是一种记录,把脑子里的东西倒出来整理一下。很多东西不记下来很快就忘了,写下来还能回头看看当时的自己是怎么想的,也挺有意思。