[object Object]

← 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 →