Skip to content

Commit 5e165f7

Browse files
committed
Fix esm bundling using esbuild
1 parent d26433e commit 5e165f7

File tree

3 files changed

+60
-4
lines changed

3 files changed

+60
-4
lines changed

library/bundler/internal/shim.mjs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { createRequire } from "node:module";
2+
import path from "node:path";
3+
import url from "node:url";
4+
5+
globalThis.require = createRequire(import.meta.url);
6+
globalThis.__filename = url.fileURLToPath(import.meta.url);
7+
globalThis.__dirname = path.dirname(__filename);

library/bundler/internal/unplugin.ts

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,14 @@ type UserOptions = {
1111
};
1212

1313
let outputFormat: "cjs" | "esm" | undefined = undefined;
14+
let importFound = false;
1415

1516
export const basePlugin: UnpluginInstance<UserOptions | undefined, false> =
1617
createUnplugin(() => {
1718
return {
1819
name: "zen-js-bundler-plugin",
1920

20-
buildStart(options) {
21+
buildStart: () => {
2122
protectDuringBundling();
2223
},
2324

@@ -26,6 +27,19 @@ export const basePlugin: UnpluginInstance<UserOptions | undefined, false> =
2627
id: /\.(js|ts|cjs|mjs|jsx|tsx)$/,
2728
},
2829
handler(code, id) {
30+
// Check whether the instrumentation import is present in the user's code
31+
// The import is required in CJS builds but forbidden in ESM builds
32+
if (
33+
!importFound &&
34+
!id.includes("node_modules") &&
35+
// We need to ignore imports of instrument/internals from within the library itself
36+
// As the lib is not inside the node_modules folder during unit and e2e tests
37+
(code.includes("@aikidosec/firewall/instrument'") ||
38+
code.includes('@aikidosec/firewall/instrument"'))
39+
) {
40+
importFound = true;
41+
}
42+
2943
const result = patchPackage(id, {
3044
source: code,
3145
format: "unambiguous",
@@ -39,13 +53,26 @@ export const basePlugin: UnpluginInstance<UserOptions | undefined, false> =
3953
? result.source
4054
: new TextDecoder("utf-8").decode(result.source);
4155

42-
// Todo rewrite Zen imports in ESM mode but after code is processed by bundler?
43-
4456
return {
4557
code: modifiedCode,
4658
};
4759
},
4860
},
61+
62+
buildEnd: () => {
63+
if (outputFormat === "esm" && importFound === true) {
64+
throw new Error(
65+
"Aikido: Detected import of '@aikidosec/firewall/instrument' in your code while building an ESM bundle. Please remove this import and preload the library by running Node.js with the --require option instead. See our ESM documentation for more information."
66+
);
67+
}
68+
69+
if (outputFormat === "cjs" && importFound === false) {
70+
throw new Error(
71+
"Aikido: Missing import of '@aikidosec/firewall/instrument' in your code while building a CJS bundle. Please add this as the first line of your application's entry point file to ensure proper instrumentation."
72+
);
73+
}
74+
},
75+
4976
esbuild: {
5077
config: (options) => {
5178
if (!options.format) {
@@ -74,6 +101,20 @@ export const basePlugin: UnpluginInstance<UserOptions | undefined, false> =
74101
} else {
75102
throw new Error("esbuild external option is not an array");
76103
}
104+
105+
const injectPath = join(
106+
findZenLibPath(),
107+
"bundler",
108+
"internal",
109+
"shim.mjs"
110+
);
111+
if (!options.inject) {
112+
options.inject = [injectPath];
113+
} else if (Array.isArray(options.inject)) {
114+
options.inject.push(injectPath);
115+
} else {
116+
throw new Error("esbuild inject option is not an array");
117+
}
77118
}
78119

79120
if (!options.outdir) {
@@ -107,7 +148,9 @@ function copyFiles(outDir: string, format: "cjs" | "esm") {
107148
copyFileSync(join(zenLibDir, file), join(outDir, file));
108149
}
109150
} else if (format === "esm") {
110-
cpSync(zenLibDir, join(outDir, "zen"), { recursive: true });
151+
cpSync(zenLibDir, join(outDir, "node_modules", "@aikidosec", "firewall"), {
152+
recursive: true,
153+
});
111154
}
112155
}
113156

library/tsdown.config.mts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,10 @@ export default defineConfig({
2121
tsconfig: "./tsconfig.build.json",
2222
fixedExtension: false,
2323
unbundle: process.env.BUILD_KEEP_STRUCTURE === "true",
24+
copy: [
25+
{
26+
from: "./bundler/internal/shim.mjs",
27+
to: "../build/bundler/internal/shim.mjs",
28+
},
29+
],
2430
});

0 commit comments

Comments
 (0)