A third instance of the pattern notebooks-export/ and the reading payloads already use: an artifact built somewhere with a toolchain this repo's node:24-slim container does not have, dropped into a gitignored directory, staged into public/ by a script, and picked up by auto-build.sh's signature on the next tick. Nothing here needs a JDK, Go, or an opinion about the game -- cannons_reloaded's deploy/export-cannons.sh hands over a directory that is already ready to serve. Three things are load-bearing and easy to get wrong later: The payload is at /cn/, not /cannons/. With build.format:'file' the page builds to cannons.html, and try_files would then have a file and a directory competing for the same URL. That is exactly why the notebook exports live at /nb/ and not under /notebooks/. nginx gets gzip_static for /cn/. nginx:alpine has `gzip on` commented out in its base config, so without it the page ships 9MB instead of 3.3MB and nothing anywhere reports that. It gets no-cache rather than an expiry, because classes.js and cannons.wasm are stable filenames whose contents change on every rebuild -- a long expiry would pair a stale client with a fresh server. The page loads on click, not `loading="lazy"`. Lazy only defers until the frame nears the viewport and this frame is above the fold, so a few MB would download for anyone who opened the page to read the paragraph. A missing export is a normal state throughout: copy-cannons.mjs stages nothing, the page says so, and the sidebar link does not appear. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S4wdbGSVzvUDHBWRjSVxfr
47 lines
1.9 KiB
JavaScript
47 lines
1.9 KiB
JavaScript
// Stage the ACannons browser build produced by cannons_reloaded's
|
|
// deploy/export-cannons.sh into public/, where Astro picks it up as static
|
|
// files.
|
|
//
|
|
// The export arrives ready to serve: only what the embedded page loads, res/
|
|
// already dereferenced down to en_US, and .gz siblings alongside the two big
|
|
// files for nginx's gzip_static. So this is a plain recursive copy and
|
|
// deliberately knows nothing about the game -- everything that needs a JDK, a
|
|
// Go toolchain or an opinion about the client lives in the other repo.
|
|
//
|
|
// No export (the workflow has never run, or this is a fresh clone) is a normal
|
|
// state, not an error: the page renders a note instead of a frame.
|
|
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const REPO = path.join(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
const SRC_DIR = path.join(REPO, 'cannons-export');
|
|
const OUT_DIR = path.join(REPO, 'public', 'cn');
|
|
|
|
fs.rmSync(OUT_DIR, { recursive: true, force: true });
|
|
|
|
if (!fs.existsSync(path.join(SRC_DIR, 'manifest.json'))) {
|
|
console.log('copy-cannons: no cannons-export/manifest.json — nothing to stage');
|
|
process.exit(0);
|
|
}
|
|
|
|
// The manifest is for the build, not the browser: it says which commit this
|
|
// is and what it weighs, and src/lib/cannons.mjs reads it from the export
|
|
// directly. Shipping it would just be a file nobody fetches.
|
|
let files = 0;
|
|
let bytes = 0;
|
|
for (const ent of fs.readdirSync(SRC_DIR, { withFileTypes: true, recursive: true })) {
|
|
if (ent.isDirectory()) continue;
|
|
const rel = path.relative(SRC_DIR, path.join(ent.parentPath, ent.name));
|
|
if (rel === 'manifest.json') continue;
|
|
const dest = path.join(OUT_DIR, rel);
|
|
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
fs.copyFileSync(path.join(SRC_DIR, rel), dest);
|
|
files++;
|
|
bytes += fs.statSync(dest).size;
|
|
}
|
|
|
|
console.log(
|
|
`copy-cannons: ${files} files, ${(bytes / 1048576).toFixed(1)}MB -> ${OUT_DIR}`,
|
|
);
|