Repository navigation
fix(build): bundle the Lambda handler as CommonJS - #281
Conversation
Load build/proxy.js with Node 20 from a directory containing only the files publish.yaml zips, so the repo-root package.json cannot mark it as an ES module, and with module syntax detection disabled. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
bun build emits build/proxy.js as ESM, but proxy-lambda.zip contains only build/ and node_modules/, so Lambda loads it as CommonJS and fails init with "Cannot use import statement outside a module". Write build/package.json with "type": "module" so it ships in the zip. Affects releases v2.3.0 through v2.4.3. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks for tracking this down, and for pushing the failing test and the fix as separate commits so CI shows both sides. I'd suggest fixing this in the bundler instead of shipping a generated "build": "bun build lambda/proxy.ts --outdir build/ --target node --format cjs"This emits
Some related suggestions: 1. Upgrade the runtime to Node 24. Node 20 is past end-of-life. # lambda.tf
runtime = "nodejs24.x"The AWS provider added # versions.tf
aws = {
source = "hashicorp/aws"
version = ">= 6.21.0"
}This requires consumers still on provider 5.x to upgrade, so the runtime change may be better released as a new major version, separate from the 2. Drop "package": "zip -r -qq proxy-lambda.zip build"# publish.yaml
- name: Zip Lambda
run: bun run package3. Smoke test the real artifact on the Lambda Node version. Unzipping the release zip, instead of copying - name: Setup Node
uses: actions/setup-node@v7
with:
# Keep in sync with the Lambda runtime in lambda.tf
node-version: 24
- name: Smoke Test Lambda Bundle
run: |
bun run package
unzip -q proxy-lambda.zip -d "$RUNNER_TEMP/lambda"
cd "$RUNNER_TEMP/lambda"
node --no-experimental-require-module -e "
if (typeof require('./build/proxy.js').handler !== 'function') throw new Error('build/proxy.js does not export handler');
" |
…monJS Packages through a shared package script (also used by publish.yaml), unzips it, and requires build/proxy.js on Node 20 with require(esm) and module syntax detection turned off. This tests the real artifact and requires the bundle itself to be CommonJS, so it fails against the current ESM bundle. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replaces the generated build/package.json with a CommonJS bundle, so build/proxy.js loads on Lambda without depending on a sidecar file. This matches the format v2.1.0 shipped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
danadajian
left a comment
There was a problem hiding this comment.
Approving. The CJS bundle, shared package script, and smoke test against the packaged zip all landed as suggested. Dropping node_modules from the zip and the Node 24 runtime upgrade (with the minimum AWS provider version) will be handled in a follow-up.
|
🎉 This PR is included in version 2.4.4 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
Problem
Since v2.3.0 (#191, switch to Bun),
bun buildemitsbuild/proxy.jsas an ES module (import …/export { handler }). The repo'spackage.jsonsets"type": "module", butpublish.yamlonly zipsbuildandnode_modules, so the releasedproxy-lambda.ziphas nopackage.json. Lambda's Node runtime therefore loadsbuild/proxy.jsas CommonJS and fails during init on every invocation:API Gateway returns
502 {"message": "Internal server error"}in well under a second for every webhook. Every release from v2.3.0 to v2.4.3 is affected for anyone deploying the published zip. We hit it in production after upgrading an internal deployment from v2.1.0 (still built withtscas CommonJS) to v2.4.3.Fix
bun build … --format cjsemitsbuild/proxy.jsas CommonJS, which is how Lambda loads it by default. That matches the format v2.1.0 shipped. It doesn't depend on a sidecarpackage.json, and the handler path (build/proxy.handler), runtime and Terraform don't change. (An earlier commit in this PR generatedbuild/package.jsonwith"type": "module". Review feedback suggested fixing this in the bundler instead, and the later commits replace it.)packagescript, used by bothpublish.yamland CI, so they zip the same contents.proxy-lambda.zipandrequiresbuild/proxy.json Node 20 (thelambda.tfruntime). It runs with--no-experimental-require-module --no-experimental-detect-module. Node 20.19+ canrequire()ESM by default, which would let a broken bundle pass, so the flags ensure only a real CommonJS bundle loads.Verification
Each step was pushed separately so CI shows both sides:
test(ci): smoke test loading the Lambda bundle as Lambda doesfix(build): mark Lambda bundle as an ES moduletest(ci): smoke test the packaged zip by requiring the handler as CommonJSERR_REQUIRE_ESMfix(build): bundle the Lambda handler as CommonJSOut of scope (follow-up)
nodejs24.xand setting a minimum AWS provider version, which needs a major release.node_modulesfrom the zip, since the bundle inlines its dependencies. Left out to avoid changing the artifact's contents in an outage-fix patch.Releasing as
fix:gives a v2.4.4 patch.🤖 Generated with Claude Code