ReviewOS

also looking at this

stacks/lastsoulultra

LSU's own coaching surface, and what auditing the site turned up

#12
Merged glennmichael123 wants to merge claude/last-soul-ultra-web-6e0718 into main
86 files +3943 -1190

Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.

package.jsonmodified+2-1
Changes to package.json
@@ -27,7 +27,7 @@
2727 "upgrade": "./buddy upgrade",
2828 "dev": "./buddy dev",
2929 "development": "./buddy dev",
30 "build": "bun run build:assets && ./buddy build",
30 "build": "bun run build:assets && ./buddy build && bun run build:bundles",
3131 "prod": "./buddy build",
3232 "deploy": "./buddy deploy",
3333 "lint": "./buddy lint",
@@ -73,6 +73,7 @@
7373 "bud": "./buddy",
7474 "stx": "./buddy",
7575 "build:assets": "bun scripts/build-site-assets.ts",
76 "build:bundles": "bun scripts/externalize-page-bundles.ts",
7677 "audit:html": "bun scripts/audit-html.ts"
7778 },
7879 "dependencies": {
scripts/externalize-page-bundles.tsadded+87-0
Changes to scripts/externalize-page-bundles.ts
@@ -0,0 +1,87 @@
1/* eslint-disable no-console */
2/**
3 * Lift a page's own module bundle out of its HTML.
4 *
5 * The build externalises the blobs that repeat across pages - the signals
6 * runtime, the router, the generated stylesheet - and leaves a bundle that
7 * only one page uses inline. That is the wrong way round for the biggest one
8 * here: /world-series carries @ts-maps inline, 844 KB of minified JavaScript
9 * in the first 1% of the document, which the browser must download and parse
10 * before it paints anything below it, on every single visit, because an
11 * inline script cannot be cached.
12 *
13 * Moving it to a file named by its contents makes it cacheable, lets the
14 * document stream, and costs one request. `/_stx/modules.<hash>.js` is the
15 * shape stx's own SPA router already recognises as a module bundle, so a
16 * client-side navigation that fails to load it recovers the page rather than
17 * running a setup that can only throw.
18 *
19 * The tag keeps its attributes and gains no defer or async: an inline script
20 * runs at its position in document order, and so does an external one without
21 * those, so execution order is unchanged.
22 *
23 * bun run build # runs this after ./buddy build
24 */
25
26import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs'
27import { join, relative } from 'node:path'
28import process from 'node:process'
29
30const ROOT = 'dist'
31const ASSET_DIR = join(ROOT, '_stx')
32/** Below this, a request costs more than the bytes saved. */
33const MIN_BYTES = 16 * 1024
34
35if (!existsSync(ROOT)) {
36 console.error(`${ROOT}/ does not exist. Run the build first.`)
37 process.exit(1)
38}
39
40function pages(dir = ROOT): string[] {
41 return readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
42 const path = join(dir, entry.name)
43 if (entry.isDirectory()) return entry.name === '_stx' ? [] : pages(path)
44 return entry.name.endsWith('.html') ? [path] : []
45 })
46}
47
48/** The name stx's router matches as a module bundle: 16 hex characters. */
49function bundleName(code: string): string {
50 return `modules.${new Bun.CryptoHasher('sha256').update(code).digest('hex').slice(0, 16)}.js`
51}
52
53const written = new Map<string, number>()
54let movedBytes = 0
55let touchedPages = 0
56
57for (const file of pages()) {
58 const html = readFileSync(file, 'utf8')
59 let changed = false
60
61 const next = html.replace(
62 /<script([^>]*\bdata-stx-modules\b[^>]*)>([\s\S]*?)<\/script>/gi,
63 (whole, attrs: string, code: string) => {
64 // Already a reference, or small enough to leave where it is.
65 if (/\bsrc\s*=/i.test(attrs) || code.length < MIN_BYTES) return whole
66
67 const name = bundleName(code)
68 if (!written.has(name)) {
69 mkdirSync(ASSET_DIR, { recursive: true })
70 writeFileSync(join(ASSET_DIR, name), code)
71 written.set(name, code.length)
72 }
73 changed = true
74 movedBytes += code.length
75 return `<script${attrs} src="/_stx/${name}"></script>`
76 },
77 )
78
79 if (!changed) continue
80 writeFileSync(file, next)
81 touchedPages += 1
82 console.log(` ${relative(ROOT, file)} ${(html.length / 1024).toFixed(0)}KB -> ${(next.length / 1024).toFixed(0)}KB`)
83}
84
85console.log(written.size === 0
86 ? 'No page-local module bundle was large enough to externalize.'
87 : `Externalized ${written.size} page module bundle(s) from ${touchedPages} page(s) (${(movedBytes / 1024).toFixed(1)}KB removed from HTML)`)