website
git clone https://git.pyrossh.dev/website
木 Personal website of pyrossh. Built with astrojs, shiki, vite.
src/_data/repoCommits.js
import { html as renderDiffHtml, parse as parseDiff } from "diff2html";
import { readCache, writeCache } from "../_helpers/dataCache.js";
import { discoverLocalRepos, getCommitDiff, getHeadSha } from "../_helpers/gitRepos.js";
import { mapPool } from "../_helpers/pool.js";
const CONCURRENCY = 8;
// Some repos have vendored/generated/binary-as-text blobs committed at some
// point in their history (a minified bundle, a compiled binary git doesn't
// detect as binary, ...) — `git show -p` dumps the whole file as a diff on
// every commit that touches it, and diff2html's per-line markup multiplies
// that further. Left unguarded, that's easily 100s of MB of HTML per repo,
// held for every commit at once across every repo — well past Node's default
// heap. Cap it the way GitHub's own diff viewer does: skip rendering past a
// size threshold rather than trying to syntax-highlight a multi-MB blob.
const MAX_DIFF_SIZE = 300 * 1024;
const DIFF_TOO_LARGE_HTML = '<p class="diff-too-large">This diff is too large to display.</p>';
const toDiffHtml = (diffText) => {
const idx = diffText.indexOf("diff --git");
const patch = idx >= 0 ? diffText.slice(idx) : "";
if (!patch.trim()) return "";
if (patch.length > MAX_DIFF_SIZE) return DIFF_TOO_LARGE_HTML;
try {
const json = parseDiff(patch);
return renderDiffHtml(json, { drawFileList: true, matching: "lines" });
} catch {
return "";
}
};
export default async () => {
const repos = discoverLocalRepos();
const pages = [];
for (const repo of repos) {
// Unlike repoFiles.js, none of this reads the working tree — `git
// show` only ever sees committed history — so it's safe to cache on
// HEAD sha alone, with no working-tree-clean requirement. That
// matters because this repo (website) is usually dirty while it's
// being actively worked on, and its commit history is the most
// expensive part of the build.
const sha = getHeadSha(repo.dir);
const cacheKey = `commits-${repo.id}`;
let entries = sha ? readCache(cacheKey, sha) : null;
if (!entries) {
entries = await mapPool(repo.commits, CONCURRENCY, async (commit) => {
const diffText = await getCommitDiff(repo.dir, commit.hash);
return { commit, diffHtml: toDiffHtml(diffText) };
});
if (sha) writeCache(cacheKey, sha, entries);
}
// Only `id`/`data`/`version` ever get read off `item.repo` in
// commit.njk — not the full `repo` object's `files`/`tree`/`commits`/
// `readme`. Eleventy's paginator deep-clones each page's data slice for
// isolation, so embedding the whole repo (every commit's metadata,
// every file, the tree, the README) here means that whole structure
// gets cloned once per commit page — the actual multiplier behind the
// OOM, not just the diff HTML size.
const slimRepo = { id: repo.id, data: repo.data, version: repo.version };
for (const entry of entries) pages.push({ repoId: repo.id, repo: slimRepo, ...entry });
}
return pages;
};