Luigit
repositories / pi-ext

pi-ext

bugabingas pi extensions

owned by admin

scripts/build/bundle.ts

Raw
import { build } from "rolldown";
import { type ExtensionBuildSpec, isExternal } from "./spec.ts";

export interface BundleOptions {
	release?: boolean;
}

export interface BundleResult {
	/** Entry output files relative to the output directory. */
	entries: string[];
	/** Every emitted file relative to the output directory. */
	files: string[];
}

/**
 * Bundle one extension into `outDir`.
 * Chunks stay flat in the package root so `import.meta.url` relative resource
 * lookups resolve identically from the entry and from any chunk.
 */
export async function bundleExtension(
	spec: ExtensionBuildSpec,
	outDir: string,
	options: BundleOptions = {},
): Promise<BundleResult> {
	const result = await build({
		input: spec.entries,
		cwd: spec.dir,
		platform: "node",
		// Source imports sibling modules as `./x.js`; the file on disk is `x.ts`.
		resolve: { extensionAlias: { ".js": [".ts", ".js"] } },
		external: (id, _parent, isResolved) =>
			isResolved ? false : isExternal(id, spec.externals),
		logLevel: "warn",
		onLog(level, log, defaultHandler) {
			if (level === "warn" && /import\.meta|circular/iu.test(log.message))
				return;
			defaultHandler(level, log);
		},
		output: {
			dir: outDir,
			format: "esm",
			entryFileNames: "[name].js",
			chunkFileNames: "[name]-[hash].js",
			hashCharacters: "base36",
			sourcemap: !options.release,
			minify: Boolean(options.release),
		},
	});
	const files: string[] = [];
	const entries: string[] = [];
	for (const output of result.output) {
		files.push(output.fileName);
		if (output.type === "chunk" && output.isEntry)
			entries.push(output.fileName);
		if (output.type === "chunk" && output.sourcemapFileName)
			files.push(output.sourcemapFileName);
	}
	return { entries, files };
}