← back to build-pages
perf: cache commit bundle per-repo, keyed on HEAD SHA — page hit 80ms→17ms warm
b4e3a28956851e4c15b27975bb619632c1ba9808 · 2026-05-13 12:57:56 -0700 · SteveStudio2
Files touched
Diff
commit b4e3a28956851e4c15b27975bb619632c1ba9808
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date: Wed May 13 12:57:56 2026 -0700
perf: cache commit bundle per-repo, keyed on HEAD SHA — page hit 80ms→17ms warm
---
server.js | 21 ++++++++++++++++++---
1 file changed, 18 insertions(+), 3 deletions(-)
diff --git a/server.js b/server.js
index 055e57f..10cb2fe 100644
--- a/server.js
+++ b/server.js
@@ -67,6 +67,23 @@ async function gitRun(repo, args) {
return stdout;
}
+// Per-repo cache keyed on HEAD SHA. Probing HEAD is ~5ms; rebuilding the full
+// commits+files+facets bundle is 50-80ms. A page hit on an unchanged repo
+// drops from ~80ms to ~10ms once warm. The HEAD probe still runs every hit
+// so a `git commit` in the source repo shows up on the next refresh.
+const _projectCache = new Map();
+async function getProjectBundle(slug, p) {
+ const head = (await gitRun(p.repo, ['rev-parse', 'HEAD'])).trim();
+ const cached = _projectCache.get(slug);
+ if (cached && cached.head === head) return cached;
+ const commits = await listCommits(p.repo);
+ const facets = extractFacets(commits);
+ const files = await listFiles(p.repo);
+ const bundle = { head, commits, facets, files, at: Date.now() };
+ _projectCache.set(slug, bundle);
+ return bundle;
+}
+
async function listCommits(repo) {
const fmt = '%H%x01%h%x01%ai%x01%an%x01%s%x01%b%x02';
const raw = await gitRun(repo, ['log', '--no-merges', `--pretty=format:${fmt}`]);
@@ -251,9 +268,7 @@ app.get('/p/:slug', async (req, res, next) => {
const p = PROJECTS[req.params.slug];
if (!p) return res.status(404).send(shell('Not found', '<h1>404</h1><p>No such project.</p>'));
try {
- const commits = await listCommits(p.repo);
- const facets = extractFacets(commits);
- const files = await listFiles(p.repo);
+ const { commits, facets, files } = await getProjectBundle(req.params.slug, p);
const idxData = JSON.stringify(commits.map(c => ({
h: c.shortHash, d: c.dateISO.slice(0, 10), s: c.subject, b: c.body.slice(0, 4000),
})));
← f8e102d smoke: assert /p/:slug?q= hydrates search input on server-re
·
back to build-pages
·
smoke: warm /p/butlr render <250ms perf budget (cache regres 91732aa →