concept-collection / fastandaccurate
Fetch results from the results repo's Pages site; serve local results in dev
Jeremy Magland <jmagland@flatironinstitute.org> committed commit 71709818101b parent e58e208 Browse files
3 changed files+50−11
scripts/check-app.mjsmodified+6−3View file
@@ -48,9 +48,12 @@ try {
4848 if (msg.type() === "error") {
4949 const text = msg.text();
5050 const url = msg.location()?.url ?? "";
51- // The committed-results fetch may 404 before the results repo has
52- // content; the app reports that in the UI by design.
53- if (url.includes("raw.githubusercontent.com")) return;
51+ // The committed-results fetch may fail offline, or while the
52+ // results site is unavailable; the app reports that in the UI by
53+ // design. CORS complaints name the URL in the message text rather
54+ // than in the location, so both are checked.
55+ const RESULTS_HOST = "github.io/fastandaccurate-results";
56+ if (url.includes(RESULTS_HOST) || text.includes(RESULTS_HOST)) return;
5457 // numbl logs its linear-algebra bridge choice at error level.
5558 if (text.includes("using bridge:")) return;
5659 errors.push(`${text} (${url})`);
src/app/results.tsmodified+11−4View file
@@ -9,8 +9,15 @@ import {
99
1010 export const RESULTS_REPO_URL =
1111 "https://github.com/concept-collection/fastandaccurate-results";
12-const RESULTS_RAW =
13- "https://raw.githubusercontent.com/concept-collection/fastandaccurate-results/main";
12+// The results repo is served by its own GitHub Pages (branch-based, main
13+// at /), which is CDN-backed and CORS-open. raw.githubusercontent.com
14+// would also work but rate-limits hard enough to break page loads.
15+// In dev the vite server serves the sibling checkout instead (see
16+// localResultsPlugin in vite.config.ts), so local work sees local
17+// results and makes no network requests for them.
18+const RESULTS_BASE = import.meta.env.DEV
19+ ? "/local-results"
20+ : "https://concept-collection.github.io/fastandaccurate-results";
1421
1522 export function isResultFile(x: unknown): x is ResultFile {
1623 const r = x as ResultFile;
@@ -26,13 +33,13 @@ export function isResultFile(x: unknown): x is ResultFile {
2633 }
2734
2835 export async function fetchCommittedResults(): Promise<ResultFile[]> {
29- const idxResp = await fetch(`${RESULTS_RAW}/index.json`, { cache: "no-cache" });
36+ const idxResp = await fetch(`${RESULTS_BASE}/index.json`, { cache: "no-cache" });
3037 if (!idxResp.ok) throw new Error(`index.json: HTTP ${idxResp.status}`);
3138 const idx = (await idxResp.json()) as { files?: string[] };
3239 const files = idx.files ?? [];
3340 const results = await Promise.all(
3441 files.map(async (f) => {
35- const resp = await fetch(`${RESULTS_RAW}/${f}`, { cache: "no-cache" });
42+ const resp = await fetch(`${RESULTS_BASE}/${f}`, { cache: "no-cache" });
3643 if (!resp.ok) return null;
3744 const data: unknown = await resp.json();
3845 return isResultFile(data) ? data : null;
vite.config.tsmodified+33−4View file
@@ -1,8 +1,8 @@
1-import { defineConfig } from "vite";
1+import { defineConfig, type Plugin } from "vite";
22 import react from "@vitejs/plugin-react";
3-import { readFileSync } from "fs";
3+import { existsSync, readFileSync } from "fs";
44 import { fileURLToPath } from "url";
5-import { dirname, join } from "path";
5+import { dirname, join, normalize } from "path";
66
77 const root = dirname(fileURLToPath(import.meta.url));
88 const numblVersion = (
@@ -11,9 +11,38 @@ const numblVersion = (
1111 ) as { version: string }
1212 ).version;
1313
14+/**
15+ * In dev, serve the sibling fastandaccurate-results checkout under
16+ * /local-results/ so the page shows the results repo as it stands on
17+ * disk, uncommitted and unpushed included, and never touches the network
18+ * for them. Production builds fetch the deployed results site instead.
19+ */
20+function localResultsPlugin(): Plugin {
21+ const resultsRoot = join(root, "..", "fastandaccurate-results");
22+ return {
23+ name: "fastandaccurate-local-results",
24+ apply: "serve",
25+ configureServer(server) {
26+ server.middlewares.use((req, res, next) => {
27+ const url = (req.url ?? "").split("?")[0];
28+ if (!url.startsWith("/local-results/")) return next();
29+ const rel = decodeURIComponent(url.slice("/local-results/".length));
30+ const file = normalize(join(resultsRoot, rel));
31+ if (!file.startsWith(normalize(resultsRoot)) || !existsSync(file)) {
32+ res.statusCode = 404;
33+ res.end("not found");
34+ return;
35+ }
36+ res.setHeader("content-type", "application/json");
37+ res.end(readFileSync(file));
38+ });
39+ },
40+ };
41+}
42+
1443 export default defineConfig({
1544 base: "./",
16- plugins: [react()],
45+ plugins: [react(), localResultsPlugin()],
1746 define: {
1847 __NUMBL_VERSION__: JSON.stringify(numblVersion),
1948 __BUILD_ID__: JSON.stringify(