把 Aemeath 的站点统计页搬进我的博客
之前博客的数据一直在 Umami 后台看,自己够用,但总想着有个能放出去的门面。后来刷到年华把 Aemeath 的站点统计页移植到 Firefly移植统计页面的文章,版式挺喜欢的,就去原作者的页面看了一下怎么搬。作者把整套开源在 Jarvis0227/Aemeath,MIT 协议。看了下也是 Astro 写的,跟 Firefly 同源,改起来的成本不大,于是动了手。
数据是怎么拿到的
Umami 后台可以给某个站点生成一条「公开分享」链接,拿到链接末尾那串 slug 之后,前端就能自己去读数据:
GET /api/share/<slug>换回websiteId和一个 share token- 带着
x-umami-share-token去/api/websites/<id>/stats、/metrics取数
整个流程只读,不需要管理员 token,也不用自己写个中间层转发。分享链接随时能在后台撤掉,所以 slug 被看到也没什么风险。
我把 slug 和实例地址放进了配置文件,另外留了一个「历史累计」的口子——要是以后换统计服务,可以把之前的数字并进展示,而不会去写 Umami。
按自己情况改的三个地方
搬别人写好的代码,费劲的不是抄,是搞清楚哪些地方作者是按他自己仓库的情况写死的以及适配。这次碰到三处。
别挂在全局 Layout 上
原版把统计组件挂在全局 Layout,因为它的侧栏要显示访问快照。我只在 /analytics/ 这一页用它,所以把组件挂在了页面内部。
地图要换成合规的
原版的国内访客地图用的是维基系那套边界数据,缺南海诸岛,也没有九段线。本站是国内备案网站,需要考虑合规性,所以原样搬过来不合适,需要自己改一改地图。
数据源换成高德 DataV 的行政边界,用 Albers 等积圆锥投影(双标准纬线 25° 和 47°、中央经线 105°)自己生成 SVG。写脚本时碰到两个具体问题:
- 九段线的数据是零宽轮廓,没有面积,用
fill画出来什么都看不到,必须走stroke。 - 南海插图里那堆岛礁点特别小,主图缩放之后直接消失,得给它们加
vector-effect="non-scaling-stroke"。
另外还有个样式上的坑:底图那张 <img> 我一开始设了透明度,结果把叠在上面的插图也压没了。插图是挂在 overlay 层的,得单独处理。
脚本同时会回写页面里的三段几何数据,所以以后换底图、改投影,都必须重跑脚本,不能只换文件。
推送节奏:原作者是按他自己仓库算的
这块踩得最多。
第一个问题很低级:原版有个 src/pages/api/github-pushes.json.ts,我移植时只搬了页面,忘了这个接口文件,卡片一直在请求一个 404 地址,什么都不显示。这类页面依赖的 API 文件比较分散,搬的时候得对着原仓库的文件树逐个核对。
第二个问题是口径。原版算推送次数时有一行:
Math.max(0, 当天提交数 - defaultActionRunsPerDay)defaultActionRunsPerDay 是 2,注释写着「扣除每日 2 次固定 Actions」。这是原作者按他仓库的情况定的,他那边每天有两次定时任务提交,不扣掉的话统计出来的就不是「人推的」。
我仓库里没有这种固定提交。唯一的定时任务是同步友链的 workflow,每天跑一次,而且是检测到变化才提交。照抄那个 2 的后果是,某天我明明推了 1 次,1 - 2 被 Math.max(0, ...) 吃成 0。把本地的 24 次提交算了一遍,页面显示 6 次。
改成 0 之后数字对了,但很快发现第三个问题:数字对了,可它不是我想看的。
这个仓库是从 Firefly 上游 fork 的,master 历史里大部分提交是原作者和上游其他贡献者写的。53 周范围内 1446 条提交,真正属于我的只有 121 条。所以还得按提交者过滤,用邮箱和 GitHub 登录名做白名单,把别人的提交筛掉。
第四个问题出在构建环境。本地统计一切正常,部署上去数字少得离谱。原因是托管平台的构建环境里 .git 是浅克隆,git log --since="53 weeks ago" 只能看到最近二十来个提交。所以在回退到读本地 git 之前,得先补一次历史:
git fetch --deepen=2000补深之后线上才拿到完整的提交量。
一个纯前端的坑:属性名撞车
数据源改完,卡片里「次数」那一格还是空的,其它指标都正常。
翻代码,取元素是这么写的:
const count = panel.querySelector("[data-push-count]");看起来很对。但用浏览器数了一下选择器命中了几个元素:
[data-push-count] → 309热力图的每个格子都写了 data-push-count(存当天提交数),而它们在 DOM 里排在底部那个 <strong> 前面。querySelector 只认第一个匹配,于是每次写入的数字都落进了一个空的热力图格子,底部那格永远是初始值。
改法是把底部那个换成唯一的名字,同时改掉对应的选择器。这类问题的症状是某个数字永远是空的,光读代码很难发现,得实际去数一下选择器命中几个。
怎么确认数字是对的
统计页最麻烦的地方在于「数字不对」有很多种可能:数据源少、口径错、映射错、还是渲染错。所以我基本是把每个数字都跟数据源直接算出来的值对一遍。
热力图点亮了多少格,就跟 git log 数出来的、44 周内有提交的天数比(201 对 202);「平均间隔约 6 小时」就跟「1446 条提交除以 361 天」对。对不上再往回一层层找。这比盯着页面猜快得多。
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!











