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.
31 lines
1.5 KiB
JavaScript
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(),
|
|
};
|
|
};
|