mirror of
https://github.com/github/codeql-action.git
synced 2026-05-23 14:28:45 +00:00
436aa0401d
Bundles each entry point as ESM with esbuild's splitting:true so
shared transitive dependencies (Azure storage, undici, octokit, ...)
live in shared chunk files under lib/chunks/ instead of being
duplicated into every entry bundle.
A small banner is injected so bundled CommonJS deps that call
require(), __filename or __dirname at runtime still work. A
lib/package.json with { "type": "module" } is written by the build
so the bundles can keep the .js extension while being loaded as ESM
by Node; this scope avoids touching the tsc output in build/ and the
action.yml entrypoints stay unchanged.
On a measured tar.gz of the working tree this takes the repo from
~9.5 MB to ~2.6 MB compressed (lib/ alone: 8.0 MB -> 0.7 MB).
136 lines
3.8 KiB
JavaScript
136 lines
3.8 KiB
JavaScript
import { copyFile, rm, writeFile } from "node:fs/promises";
|
|
import { dirname, join } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
import * as esbuild from "esbuild";
|
|
import { globSync } from "glob";
|
|
|
|
import pkg from "./package.json" with { type: "json" };
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = dirname(__filename);
|
|
|
|
const SRC_DIR = join(__dirname, "src");
|
|
const OUT_DIR = join(__dirname, "lib");
|
|
|
|
/**
|
|
* Clean the output directory before building.
|
|
*
|
|
* @type {esbuild.Plugin}
|
|
*/
|
|
const cleanPlugin = {
|
|
name: "clean",
|
|
setup(build) {
|
|
build.onStart(async () => {
|
|
await rm(OUT_DIR, { recursive: true, force: true });
|
|
});
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Copy defaults.json to the output directory since other projects depend on it.
|
|
*
|
|
* @type {esbuild.Plugin}
|
|
*/
|
|
const copyDefaultsPlugin = {
|
|
name: "copy-defaults",
|
|
setup(build) {
|
|
build.onEnd(async () => {
|
|
await rm(join(OUT_DIR, "defaults.json"), {
|
|
force: true,
|
|
});
|
|
await copyFile(
|
|
join(SRC_DIR, "defaults.json"),
|
|
join(OUT_DIR, "defaults.json"),
|
|
);
|
|
});
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Mark `lib/` as an ESM scope by writing `lib/package.json` with
|
|
* `{ "type": "module" }`. This lets the bundles use the regular `.js`
|
|
* extension while still being loaded as ESM by Node, without affecting
|
|
* the rest of the repo (the root package.json stays CJS so the tsc
|
|
* output in `build/` and any other consumers are unchanged).
|
|
*
|
|
* @type {esbuild.Plugin}
|
|
*/
|
|
const writeLibPackageJsonPlugin = {
|
|
name: "write-lib-package-json",
|
|
setup(build) {
|
|
build.onEnd(async () => {
|
|
await writeFile(
|
|
join(OUT_DIR, "package.json"),
|
|
JSON.stringify({ type: "module" }) + "\n",
|
|
);
|
|
});
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Log when the build ends.
|
|
*
|
|
* @type {esbuild.Plugin}
|
|
*/
|
|
const onEndPlugin = {
|
|
name: "on-end",
|
|
setup(build) {
|
|
build.onEnd((result) => {
|
|
// eslint-disable-next-line no-console
|
|
console.log(`Build ended with ${result.errors.length} errors`);
|
|
});
|
|
},
|
|
};
|
|
|
|
// Banner injected into every emitted ESM file so that bundled CommonJS
|
|
// dependencies which call `require(...)` at runtime (e.g. parts of the
|
|
// Azure SDK + undici stack pulled in transitively by `@actions/cache` and
|
|
// `@actions/artifact`), or read `__filename` / `__dirname`, keep working.
|
|
const esmCompatBanner = [
|
|
`import { createRequire as __codeqlCreateRequire } from "module";`,
|
|
`import { fileURLToPath as __codeqlFileURLToPath } from "url";`,
|
|
`import { dirname as __codeqlDirname } from "path";`,
|
|
`var require = __codeqlCreateRequire(import.meta.url);`,
|
|
`var __filename = __codeqlFileURLToPath(import.meta.url);`,
|
|
`var __dirname = __codeqlDirname(__filename);`,
|
|
].join("");
|
|
|
|
const context = await esbuild.context({
|
|
// Include upload-lib.ts as an entry point for use in testing environments.
|
|
entryPoints: globSync([
|
|
`${SRC_DIR}/*-action.ts`,
|
|
`${SRC_DIR}/*-action-post.ts`,
|
|
"src/upload-lib.ts",
|
|
]),
|
|
bundle: true,
|
|
// Use ESM with code splitting so shared modules (Azure storage, undici,
|
|
// octokit, ...) live in shared chunk files instead of being duplicated
|
|
// into every entry bundle. Node treats these `.js` files as ESM because
|
|
// `writeLibPackageJsonPlugin` writes `lib/package.json` with
|
|
// `"type": "module"`.
|
|
format: "esm",
|
|
splitting: true,
|
|
minify: true,
|
|
chunkNames: "chunks/chunk-[hash]",
|
|
banner: { js: esmCompatBanner },
|
|
outdir: OUT_DIR,
|
|
platform: "node",
|
|
plugins: [
|
|
cleanPlugin,
|
|
copyDefaultsPlugin,
|
|
writeLibPackageJsonPlugin,
|
|
onEndPlugin,
|
|
],
|
|
target: ["node20"],
|
|
define: {
|
|
__CODEQL_ACTION_VERSION__: JSON.stringify(pkg.version),
|
|
},
|
|
metafile: true,
|
|
});
|
|
|
|
const result = await context.rebuild();
|
|
await writeFile(join(__dirname, "meta.json"), JSON.stringify(result.metafile));
|
|
|
|
await context.dispose();
|