https://jaceho.github.io 的源码与生成器。站点分两层:
| 层 | 内容 | 怎么来 |
|---|---|---|
| 博客 | 个人首页、2011–2016 的 61 篇旧文、/posts/、/about/ |
仓库根目录的 Jekyll 源(HPSTR 主题),GitHub Pages 直接构建 |
/me/ |
首页 / 文章 / 经历与作品 / 合作,4 页 | build.py 生成到 dist/,作为静态文件直接发布 |
/me/ 是作品站,不是审计报告:它是给人看的履历与合作入口。所有数字仍由脚本重算,改内容只需重跑 python3 build.py。
build.py # dist/{index,writing,work,contact}.html + style.css,自带结构断言
publish_via_api.py # 把 dist/ 发到 master(Git Data API)
verify_pages.sh # 本地跑一遍 GitHub Pages 的那次 Jekyll 构建
/ 是给人看的个人首页:一句话定位、六篇精选、按年索引、现在的方向、合作入口。
文章全量在 /posts/,按年分组。所以 _config.yml 里没有 paginate ——
/page2/…/page13/ 随分页一起消失了。
permalink 是 /:title/(不是旧版的 /:category/:title/),否则会出现
/%E7%AE%97%E6%B3%95/p37/ 这种带百分号编码中文的链接。改 permalink 等于改掉全部
62 条旧地址,Pages 上没有重定向机制 —— 这是有意接受的代价。
python3 build.py # → dist/(会先清空 dist/,不留幽灵页)数据源在 ~/tmp/profile-audit/*.json。build.py 结尾有三条结构断言,改内容时替你拦退化:
每页恰好 1 个 <h1>、没有空 <td>、没有漏出来的 #### 原始 Markdown。
本机 git 到 github 的通道是死的(代理 CONNECT tunnel failed, response 502 / HTTP2 framing layer),
但 gh api 走 HTTPS 是通的。所以发布走 Git Data API,一次提交多个文件:
python3 build.py
python3 publish_via_api.py # blobs → tree(base_tree) → commit(parents=[head]) → PATCH refs/heads/masterpublish_via_api.py 顶部的 FILES / DELETE 决定这次发哪些路径。
tree API 里放 {"path": ..., "sha": null} 就是删除该路径。
三层,越往下越接近真实:
-
build.py的结构断言 —— 挡住形状退化,看不见渲染。 -
./verify_pages.sh—— 抓 master tarball,用本地 Jekyll 3.9.5 复制 GitHub Pages 的构建。--with-dist会把本地dist/叠到me/上一并验证。 -
线上实测 —— 状态码 + 内容抽查:
for u in / /me/ /me/contact.html /me/evidence.html /posts/ /page2/; do printf '%-24s %s\n' "$u" "$(curl -sS -o /dev/null -w '%{http_code}' "https://jaceho.github.io$u")" done # /me/evidence.html、/page2/、/readability-post/ 都应当 404
样式改动还要过截图(ego-browser,桌面 + 390px + 暗色),因为断言看不见布局。
macOS 自带 Ruby 2.6,能跑 jekyll 3.9.5 —— 但 gem 解析器默认挑最新传递依赖,
而 ffi / i18n / public_suffix / json 的最新版都要求 Ruby ≥ 3.0,报错信息看起来像"jekyll 要 Ruby 3"。
实际只要把这些钉到还支持 2.6 的版本:
export GEM_HOME=$HOME/.gem/ruby/2.6.0 GEM_PATH=$HOME/.gem/ruby/2.6.0
export PATH=$GEM_HOME/bin:$PATH
gem install --user-install ffi:1.15.5 i18n:1.8.11 public_suffix:4.0.7 json:2.6.3 \
kramdown:1.17.0 addressable:2.8.7 colorator:1.1.0 em-websocket:0.5.3 \
mercenary:0.3.6 pathutil:0.16.2 safe_yaml:1.0.5 --no-document
gem install --user-install jekyll:3.9.5 jekyll-paginate:1.1.0 \
jekyll-sitemap:1.4.0 jekyll-feed:0.15.1 --no-document
export JEKYLL_NO_BUNDLER_REQUIRE=true # 否则 jekyll 会去 Bundler 找 jekyll-gist/jekyll-import两个关键点:kramdown 必须是 1.17.x(jekyll 3.9 的约束),JEKYLL_NO_BUNDLER_REQUIRE 必须设,
否则仓库里的 Gemfile 会把 jekyll 拽进 Bundler 然后因为缺 jekyll-gist 直接崩。
全站只有两个动效文件:assets/css/modern.css 末尾的 motion 段,和 assets/js/site.js(1.5 KB,唯一 JS)。
规则是「渐进增强 + 只用 opacity/transform」:
site.js先看prefers-reduced-motion,命中就直接return,连motion类都不加;CSS 里所有隐藏 都写成.motion ...,所以脚本没跑、被拦、或读者要求减少动效时,页面是完整静态的 —— 不可能出现白屏。- 只有一件事需要 JS:
IntersectionObserver让#main > section依次浮现,另有 1.6 s 兜底setTimeout, 防止观察器不触发时正文永远不可见。 - 其余全是纯 CSS
:hover/:focus-within:- 标题 hover → 墨绿方块光标出现并闪烁(
@keyframes caret-blink,steps(1,end)); - 精选行 hover → 左缘 2 px 竖线
scaleY(0→1),整行translateX(4px),标题转 accent 色; - hero 次级链接 hover → 下划线
scaleX(0→1)从左生长(主按钮.hero-cta除外)。
- 标题 hover → 墨绿方块光标出现并闪烁(
一个曾经的教训:不要加「跟随鼠标的光晕」。在米色底上 radial-gradient + color-mix 会渲染成一块带硬边的
绿渍,看起来是脏,不是光。已删除,.hero::before 不再存在。
这个环境里 renderer 不持续出帧,CSS 动画/过渡的 timeline 会被冻住:getComputedStyle 读到的永远是起始值
(caret 恒 1、下划线恒 scaleX(0)),看起来像动效没生效。真相是没有帧就没有时间推进。
可靠的测法有两种:先 page.screenshot()(强制出一帧)再读,或者直接对截图做像素采样 —— 比如取 caret 中心点,
亮相位是 (39,85,80)≈accent,暗相位是 (237,239,236)(6 % 残影),8 帧里两种都出现才算闪。
站上除了博客还有一层:公众号「智谈局」2023–2026 的 32 篇正文,纯文本,URL 形如 /mp/<微信文章 id>/。
- 生成器
gen_mp.py,源数据~/tmp/profile-audit/mp-bodies.json(38 条抓取)+mp-publish.json(46 条发布记录)。 - 32 = 38 − 6。那 6 条抓到的正文只有 84–143 字符,是「阅读详情」预览而不是文章,丢掉;另有 6 条已被平台删除、1 条不可查看,正文哪都没有,只剩标题。
- 抓下来的是 innerText:一整行,段落全被压成空格。按
(?<=[。!?;]) +切开还原段落(最长那篇 19k 字符 → 116 段,中位 145 字),不改一个字。 - Jekyll collection
mp(_config.yml里output: true),布局_layouts/archive.html,每篇自带permalink。 - 验收口径:逐篇抓线上 HTML,剥标签后去空白与源文本逐字比对,32/32 相同。
CSDN 那 5 篇独占的(置换群 / MathJax / Real Android 逆向 / 框架对比 / jenkins iOS)没有抓。
试过:裸 curl 一律 521(边缘封 UA),带浏览器 UA + Referer 有时 200,但同一 URL 两次响应不同,
一次给正文一次只给壳子;解析出来的第一版是 <h3>3</h3> 这种编号碎片。宁可在目录里留外链,也不堆半截文本。
Page build failed.+duration: 0不一定是内容问题。2026-11-04 的两个提交都这么报, 本地同版本 Jekyll 构建全绿;手动重触发同一个 commit 就built(42s)。所以顺序是: 先./verify_pages.sh排除内容,再gh api -X POST repos/JaceHo/jaceho.github.io/pages/builds重建。/me/用 4 个静态 HTML + 一个style.css,没有 front matter —— Jekyll 会原样拷贝,不经过 Liquid。 所以这些文件里放{{ }}是安全的,但也意味着不能写 Liquid 逻辑。/about/不能用:上游已有about/index.md,Jekyll 渲染成/about/index.html,静态页会撞 URL。sample-page/是 WordPress 时代的残留,已改成layout: null+noindex+ 跳首页。_posts/2012-05-22-readability-post.md是主题自带的 lorem ipsum 演示文,不是本人写作。 文件留在仓库里,但published: false,所以博客和/me/的计数都是 61 篇。