Files
gods-eye-view/scripts/check-main-chunk.mjs
T
German Khokhlov 7abf74518f Cut duplicated and dead code across the engines, the layers and the QA scripts
- src/geo drops the ported debug argument checks and the tests that
  bitExact already covers; package boundaries accept a directory entry,
  so src/geo/ is listed once per group.
- Cesium no longer carries movers and lines nobody draws with: they are
  optional engine capabilities. The fake engine and the Cesium camera use
  the shared cameraMath; unused contract tables, clock.ticked, the
  'finest' surface detail and Navara click statistics are gone.
- ALPR keeps one overlay core and one presentation model for both
  engines, bikeshare one station bookkeeping, the Navara ground effects
  one definition helper; image atlases, view centres, mover banks and
  colours are shared.
- The legacy switch route, the clock offset and rate controls and other
  unused exports are removed.
- The acceptance runs the Navara draw, geo import and scope checks;
  scenarios use the harness switch and page helpers; the main chunk
  check keeps the size budget only and runs once in CI.
2026-11-05 13:32:39 +04:00

98 lines
3.4 KiB
JavaScript

#!/usr/bin/env node
/**
* The size budget of the Cesium-mode main chunk (run after `npm run build`):
* gzip-9 of the entry chunk the built page loads (from the Vite manifest, or
* the module script dist/index.html loads) may exceed the baseline in
* scripts/main-chunk-baseline.json by at most its allowance. What the initial
* chunks may hold is the build's own check (build/initialChunkGuard.js).
*
* Prints the size. `--json` prints the whole result; `--dist=DIR` reads
* another build.
*
* npm run build && npm run check:main-chunk
*/
import fs from 'node:fs';
import path from 'node:path';
import { gzipSync } from 'node:zlib';
import { fileURLToPath, pathToFileURL } from 'node:url';
import { entryFromHtml, entryFromManifest } from '../src/tooling/mainChunk.js';
const ROOT = fileURLToPath(new URL('..', import.meta.url));
/** The verdict for a main-chunk size against the baseline. */
export function checkMainChunk(
gzipBytes,
{ gzipBytes: baseline, allowanceBytes },
) {
const limit = baseline + allowanceBytes;
const growth = gzipBytes - baseline;
return {
ok: gzipBytes <= limit,
message: `main chunk ${gzipBytes} bytes gzip-9 (${growth >= 0 ? '+' : ''}${growth} over the ${baseline} baseline; limit ${limit})`,
};
}
/**
* gzip-9 size of the main chunk, with its name: the entry the built page
* loads (`entry`, else found from the Vite manifest or dist/index.html).
*/
export function measureMainChunk(distDir, { entry = null } = {}) {
const file = entry ?? findEntry(distDir).entry;
const bytes = fs.readFileSync(path.join(distDir, file));
return {
name: path.basename(file),
gzipBytes: gzipSync(bytes, { level: 9 }).length,
};
}
/** The entry chunk (relative to dist) and how it was found. */
function findEntry(dist) {
const manifestPath = path.join(dist, '.vite', 'manifest.json');
if (fs.existsSync(manifestPath)) {
const entry = entryFromManifest(
JSON.parse(fs.readFileSync(manifestPath, 'utf8')),
);
if (entry) return { entry, via: 'manifest' };
}
const htmlPath = path.join(dist, 'index.html');
if (!fs.existsSync(htmlPath))
throw new Error(`No build at ${dist}: run npm run build first`);
const entry = entryFromHtml(fs.readFileSync(htmlPath, 'utf8'));
if (!entry) throw new Error(`${htmlPath} loads no module script`);
return { entry, via: 'index.html' };
}
function main() {
const option = (name) =>
process.argv.find((arg) => arg.startsWith(`--${name}=`))?.split('=')[1];
const dist = path.resolve(ROOT, option('dist') ?? 'dist');
const { entry, via } = findEntry(dist);
const baselinePath = path.join(ROOT, 'scripts/main-chunk-baseline.json');
let budget = null;
if (fs.existsSync(baselinePath)) {
const measured = measureMainChunk(dist, { entry });
budget = {
...measured,
...checkMainChunk(
measured.gzipBytes,
JSON.parse(fs.readFileSync(baselinePath, 'utf8')),
),
};
}
const ok = budget?.ok ?? true;
if (process.argv.includes('--json')) {
console.log(JSON.stringify({ entry, via, budget, ok }, null, 2));
} else {
console.log(`[check:main-chunk] entry ${entry} (via ${via})`);
console.log(
budget
? `[check:main-chunk] ${budget.name}: ${budget.message}`
: '[check:main-chunk] no scripts/main-chunk-baseline.json: size budget not checked',
);
}
if (!ok) process.exitCode = 1;
}
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href)
main();