Files
mdg-filius/packages/server/src/precompress.ts
T
julian.kiedaischandClaude Opus 5.5 087721cba3 feat: F5.6b server F as an image: the editor from F itself, one stack per environment
F hands out the editor's page and bundle (editor/ beside main.mjs, or
FILIUS_EDITOR_DIR): GET and HEAD only, one wall against leaving the folder,
F's own routes first, assets/ cached a year, the rest asked for again; the
build lays .br and .gz beside the files and F sends the better one the
browser takes (bundle 695 KB to 212 KB).

deploy/Dockerfile: two stages, Node 24, no node_modules, not root.
deploy/docker-compose.yml with an env file per environment: the file sets
the stack's name, volume, image tag and port (test 8081, production 8080).
Measured with both stacks side by side behind nginx and Chromium.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 17:43:51 +00:00

38 lines
1.6 KiB
TypeScript

// Lays a .br and a .gz beside every compressible file of the editor's
// bundle, once, when the image is built (precompressMain.ts); F sends them
// instead of the file (editorFiles.ts). At the strongest level (brotli's is
// its default), because it costs only the build: the editor's bundle shrinks to about a third, and a
// tablet on the school's network feels that at every opening. A packed file
// that is not smaller is not laid.
import { readdir, readFile, writeFile } from 'node:fs/promises';
import { extname, join } from 'node:path';
import { promisify } from 'node:util';
import { brotliCompress, constants, gzip } from 'node:zlib';
export const COMPRESSIBLE = new Set(['.html', '.js', '.mjs', '.css', '.json', '.svg', '.txt']);
const packers = [
{ suffix: '.br', pack: (bytes: Buffer) => promisify(brotliCompress)(bytes) },
{ suffix: '.gz', pack: (bytes: Buffer) => promisify(gzip)(bytes, { level: constants.Z_BEST_COMPRESSION }) },
];
/** Packs the compressible files under `folder`; returns how many packed files it laid. */
export async function precompress(folder: string): Promise<number> {
let laid = 0;
for (const entry of await readdir(folder, { withFileTypes: true })) {
const path = join(folder, entry.name);
if (entry.isDirectory()) laid += await precompress(path);
else if (entry.isFile() && COMPRESSIBLE.has(extname(entry.name))) {
const bytes = await readFile(path);
for (const { suffix, pack } of packers) {
const packed = await pack(bytes);
if (packed.length >= bytes.length) continue;
await writeFile(path + suffix, packed);
laid += 1;
}
}
}
return laid;
}