Files
James Russo 2b1109db4c test(lambda): behavioral guard for handler CJS banner shims (#1977)
Miguel's fix (f999b40d) added the require/__filename/__dirname shims to the
Lambda handler bundle after #1932 crashed every render at import with
"__dirname is not defined in ES module scope" (wawoff2's emscripten build
reads __dirname at module scope; it's inlined via producer -> fontCompression).

The accompanying test only grepped build-zip.ts for the banner literals, so it
passes even if the shim is renamed, reordered into a broken form, or if a new
inlined CJS dep needs a global the banner doesn't provide.

Replace it with a behavioral test: extract the banner to _handlerBanner.ts
(build-zip.ts self-executes on import, so it can't be imported directly),
bundle a fixture that touches __dirname/__filename/require with the real
banner, and import the output under real Node -- not the bun test runtime,
which defines __dirname in ESM and would mask a missing shim. The import
faithfully reproduces Lambda's Node ESM environment and fails with the exact
#1932 error when any shim is dropped.

Handler bundle output is unchanged (identical banner string).

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 21:51:08 -07:00

31 lines
1.5 KiB
TypeScript

/**
* CJS-interop banner prepended to the ESM handler bundle.
*
* Lambda's Node 22 runtime treats `.mjs` as ESM, which has no `require`,
* `__filename`, or `__dirname`. The handler bundle inlines CJS deps that
* assume all three exist at module scope:
* - postcss et al. call top-level `require(...)`
* - wawoff2's emscripten build (pulled in unconditionally via
* producer → fontCompression) reads `__dirname` at module scope
* Without the shims the handler throws "Dynamic require of <X> is not
* supported" / "__dirname is not defined in ES module scope" at import time,
* before it can run — which is exactly how a freshly deployed stack crashed
* on every render (#1932).
*
* This mirrors the producer's own CJS banner (packages/producer/build.mjs);
* the handler bundle inlines producer source, so it needs the same shim.
*
* Kept in its own module (not inline in build-zip.ts, which self-executes on
* import) so build-zip.test.ts can import the exact banner, bundle a fixture
* with it, and assert the globals actually resolve.
*/
export const HANDLER_BANNER = [
"// hyperframes-aws-lambda handler bundle",
'import { createRequire as __hf_createRequire } from "module";',
'import { fileURLToPath as __hf_fileURLToPath } from "url";',
'import { dirname as __hf_dirname } from "path";',
"const require = __hf_createRequire(import.meta.url);",
"const __filename = __hf_fileURLToPath(import.meta.url);",
"const __dirname = __hf_dirname(__filename);",
].join("\n");