Files
edgeever/scripts/web-startup-graph.mjs
tianma-if 5eecc8df13 perf: reduce bundled fonts and defer startup dependencies
Keep shared offline defaults and download optional fonts into a validated cache with reliable export fallbacks. Prune stale Android DOM assets and refresh the smaller iOS editor bundles.

Preserve lazy startup boundaries through direct shared exports and dependency-aware splitting. Add ESM graph and Chrome startup checks to prevent eager editor and font loading.
2026-10-19 11:10:25 +08:00

31 lines
1.5 KiB
JavaScript

import { readFileSync, statSync } from "node:fs";
import { dirname, resolve, relative } from "node:path";
import ts from "typescript";
/** Follow actual ESM dependencies; removing preload hints cannot conceal eager code. */
export const readWebStartupGraph = (distDirectory) => {
const root = resolve(distDirectory);
const html = readFileSync(resolve(root, "index.html"), "utf8");
const entries = [...html.matchAll(/<script\b[^>]*type="module"[^>]*src="([^"]+)"[^>]*>/g)].map(match => match[1]);
const visited = new Set();
const visit = (file) => {
if (visited.has(file)) return;
const name = relative(root, file);
if (name.startsWith("..")) throw new Error(`Startup module escapes build directory: ${name}`);
visited.add(file);
const source = ts.createSourceFile(file, readFileSync(file, "utf8"), ts.ScriptTarget.Latest, false, ts.ScriptKind.JS);
for (const statement of source.statements) {
if (!ts.isImportDeclaration(statement) && !ts.isExportDeclaration(statement)) continue;
const specifier = statement.moduleSpecifier;
if (!specifier || !ts.isStringLiteral(specifier) || !specifier.text.startsWith(".")) continue;
const target = resolve(dirname(file), specifier.text);
if (/\.(?:m?js)$/.test(target)) visit(target);
}
};
for (const entry of entries) visit(resolve(root, entry.replace(/^\.?\//, "")));
return {
initialJavaScriptBytes: [...visited].reduce((total, file) => total + statSync(file).size, 0),
initialJavaScriptFiles: [...visited].map(file => relative(root, file)).sort(),
};
};