Skip to content

Commit 0d08c01

Browse files
committed
Auto-generate shared bundle
1 parent 14085a6 commit 0d08c01

4 files changed

Lines changed: 73 additions & 77 deletions

File tree

build.mjs

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { copyFile, readFile, rm, writeFile } from "node:fs/promises";
2-
import { dirname, join } from "node:path";
2+
import { basename, dirname, join } from "node:path";
33
import { fileURLToPath } from "node:url";
44

55
import * as esbuild from "esbuild";
@@ -62,15 +62,22 @@ const onEndPlugin = {
6262
},
6363
};
6464

65+
/** The name of the virtual `entry-points` module. */
66+
const SHARED_ENTRYPOINT = "entry-points";
67+
6568
/**
66-
* Emit a tiny stub file for each Action entrypoint. Each stub imports the shared bundle
69+
* This plugin finds all source files that contain action entry points.
70+
* It then generates the virtual `entry-points` module which imports all identifies files,
71+
* and re-exports their `runWrapper` functions with suitable aliases.
72+
* A tiny stub file is emitted for each Action entrypoint. Each stub imports the shared bundle
6773
* and calls the respective entry point.
6874
*
6975
* @type {esbuild.Plugin}
7076
*/
7177
const entryPointsPlugin = {
7278
name: "entry-points",
7379
setup(build) {
80+
const namespace = "actions";
7481
const actions = [];
7582

7683
const toPascal = (s) =>
@@ -93,6 +100,44 @@ const entryPointsPlugin = {
93100
}
94101
});
95102

103+
// Resolve the virtual `entry-points` file and set the corresponding namespace.
104+
// Ideally, we'd `RegExp.escape` the entrypoint here, but that API isn't supported in Node 20.
105+
// Since we're dealing with a hardcoded string, this isn't too much of a problem.
106+
build.onResolve({ filter: new RegExp(`^${SHARED_ENTRYPOINT}$`) }, () => {
107+
return { path: SHARED_ENTRYPOINT, namespace };
108+
});
109+
110+
// Generate the virtual `entry-points` file based on the actions we discovered.
111+
// Restrict using the namespace. The path filter does not need to discriminate any further.
112+
build.onLoad({ filter: /.*/, namespace }, async () => {
113+
const wrapperTemplatePath = "entry-wrapper.js.tpl";
114+
const wrapperTemplate = await readFile(
115+
join(SRC_DIR, wrapperTemplatePath),
116+
"utf-8",
117+
);
118+
119+
const actionsSorted = actions.sort((a, b) =>
120+
a.name.localeCompare(b.name),
121+
);
122+
const imports = actionsSorted
123+
.map(
124+
(action) =>
125+
`import * as ${action.pascalCaseName} from "./src/${basename(action.path)}"`,
126+
)
127+
.join("\n");
128+
const wrappers = actionsSorted
129+
.map((action) =>
130+
wrapperTemplate.replaceAll("__ACTION__", action.pascalCaseName),
131+
)
132+
.join("\n\n");
133+
134+
return {
135+
contents: `"use strict";\n${imports}\n\n${wrappers}\n`,
136+
resolveDir: ".",
137+
loader: "ts",
138+
};
139+
});
140+
96141
// Emit entry point stubs for each action using the entry template.
97142
build.onEnd(async (result) => {
98143
// Read the entry point template.
@@ -119,7 +164,10 @@ const entryPointsPlugin = {
119164

120165
const context = await esbuild.context({
121166
// Include upload-lib.ts as an entry point for use in testing environments.
122-
entryPoints: globSync(["src/entry-points.ts", "src/upload-lib.ts"]),
167+
entryPoints: [
168+
{ in: SHARED_ENTRYPOINT, out: SHARED_ENTRYPOINT },
169+
join(SRC_DIR, "upload-lib.ts"),
170+
],
123171
bundle: true,
124172
format: "cjs",
125173
outdir: OUT_DIR,

lib/entry-points.js

Lines changed: 19 additions & 19 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/entry-points.ts

Lines changed: 0 additions & 55 deletions
This file was deleted.

src/entry-wrapper.js.tpl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export async function run__ACTION__() {
2+
return await __ACTION__.runWrapper();
3+
}

0 commit comments

Comments
 (0)