Folio/tests/helpers/bundle.mjs

55 lines
1.8 KiB
JavaScript

// Shared test-harness bundler.
//
// Every run-*-test.mjs used to hand-roll the same esbuild boilerplate:
// write temp entry (optional) -> esbuild.build(bundle/node/esm/silent)
// -> dynamic import of the artifact -> rmSync cleanup.
// This module is that sequence, parameterized. Harnesses call it once (or
// more, like the chapters harness's three bundles) and get back the loaded
// module plus a scoped cleanup function.
import esbuild from "esbuild";
import fs from "fs";
import os from "os";
import path from "path";
import url from "url";
export async function bundleForTest({
// Unique-ish name; also names the temp artifacts (and the generated entry
// file when entrySource is used).
name,
// Module paths to bundle directly (relative to the project root or absolute).
entryPoints,
// Alternative to entryPoints: inline TS re-export text, written to a temp
// entry file next to the project root (deleted right after the build).
entrySource,
format = "esm",
external = [],
} = {}) {
const ext = format === "cjs" ? "cjs" : "mjs";
const out = path.join(os.tmpdir(), `${name}-${process.pid}.${ext}`);
let tempEntry = null;
let eps = entryPoints ?? [];
if (entrySource !== undefined) {
tempEntry = path.resolve(`.${name}-entry.ts`);
fs.writeFileSync(tempEntry, entrySource);
eps = [tempEntry];
}
await esbuild.build({
entryPoints: eps.map((p) => path.resolve(p)),
bundle: true,
platform: "node",
format,
outfile: out,
external,
write: true,
logLevel: "silent",
});
if (tempEntry) fs.rmSync(tempEntry, { force: true });
const mod = await import(url.pathToFileURL(out).href);
return {
mod,
// Removes only this call's bundled artifact.
cleanupBundle() {
fs.rmSync(out, { force: true });
},
};
}