website

#astro#js#html#css

git clone https://git.pyrossh.dev/website

木 Personal website of pyrossh. Built with astrojs, shiki, vite.


src/_data/repoFiles.js
import fs from "node:fs";
import path from "node:path";
import { readCache, writeCache } from "../_helpers/dataCache.js";
import {
  BINARY_EXTENSIONS,
  IMAGE_EXTENSIONS,
  LARGE_FILE_SIZE,
  discoverLocalRepos,
  getBlame,
  getFileHistory,
  getHeadSha,
  isDirty,
  toDataUri,
} from "../_helpers/gitRepos.js";
import { highlightCode } from "../_helpers/highlightCode.js";
import { mapPool } from "../_helpers/pool.js";

const CONCURRENCY = 8;

const renderFile = (repoDir, file) => {
  const full = path.join(repoDir, file.path);
  if (BINARY_EXTENSIONS.has(file.ext)) return { kind: "binary" };
  if (file.size > LARGE_FILE_SIZE) return { kind: "large" };
  if (IMAGE_EXTENSIONS.has(file.ext)) return { kind: "image", src: toDataUri(fs.readFileSync(full), file.ext) };
  const { html, lang } = highlightCode(fs.readFileSync(full, "utf8"), file.ext);
  return { kind: "text", html, lang };
};

export default async () => {
  const repos = discoverLocalRepos();
  const pages = [];
  for (const repo of repos) {
    const sha = getHeadSha(repo.dir);
    const cacheable = sha && !isDirty(repo.dir);
    const cacheKey = `files-${repo.id}`;

    let entries = cacheable ? readCache(cacheKey, sha) : null;
    if (!entries) {
      entries = await mapPool(repo.files, CONCURRENCY, async (file) => {
        const render = renderFile(repo.dir, file);
        const [history, blame] = await Promise.all([
          getFileHistory(repo.dir, file.path),
          render.kind === "text" ? getBlame(repo.dir, file.path) : [],
        ]);
        return { file, render, history, blame };
      });
      if (cacheable) writeCache(cacheKey, sha, entries);
    }

    // file.njk/file-history.njk/file-blame.njk only ever read `id`/`data`/
    // `tree`/`version` off `item.repo` — not `files`/`commits`/`readme`.
    // See the same note in repoCommits.js: Eleventy clones each page's data
    // slice, so keeping this slim avoids cloning the repo's full commit/
    // file lists on every single file page.
    const slimRepo = { id: repo.id, data: repo.data, tree: repo.tree, version: repo.version };
    for (const entry of entries) pages.push({ repoId: repo.id, repo: slimRepo, ...entry });
  }
  return pages;
};