/**
 * Report the minified size of each browser runtime, as JSON on stdout.
 *
 * Run under Bun because minifying is what the production build does, and this
 * has to measure the same thing. The security audit runs under Node and shells
 * out to this.
 *
 * Measuring the raw source instead would count comments, which the production
 * minifier strips -- so they cost a visitor nothing while still consuming the
 * budget. That made the old metric reward deleting explanatory comments over
 * writing smaller code.
 */
import {
  getReactiveRuntime,
  getComponentControllerRuntime,
  getNavRuntime,
  getRealtimeRuntime,
} from "../../packages/csr/src/index.ts";

const runtimes: Record<string, string> = {
  "reactive-runtime.ts": getReactiveRuntime(),
  "component-controllers.ts": getComponentControllerRuntime(),
  "nav-runtime.ts": getNavRuntime(),
  "realtime-runtime.ts": getRealtimeRuntime(),
};

const sizes: Record<string, number> = {};

for (const [name, source] of Object.entries(runtimes)) {
  const built = await Bun.build({
    // A blob entrypoint keeps this off the filesystem, so a failed run cannot
    // leave scratch files behind in the repository.
    entrypoints: ["runtime.js"],
    target: "browser",
    format: "esm",
    minify: true,
    plugins: [
      {
        name: "inline-runtime",
        setup(build) {
          build.onResolve({ filter: /^runtime\.js$/ }, () => ({
            path: "runtime.js",
            namespace: "inline",
          }));
          build.onLoad({ filter: /.*/, namespace: "inline" }, () => ({
            contents: source,
            loader: "js",
          }));
        },
      },
    ],
  });
  if (!built.success || !built.outputs.length) {
    throw new Error(`Failed to minify ${name}:\n${built.logs.map(String).join("\n")}`);
  }
  sizes[name] = (await built.outputs[0]!.text()).length;
}

process.stdout.write(JSON.stringify(sizes));
