-
Notifications
You must be signed in to change notification settings - Fork 27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Esbuild support #467
Comments
@bretambrose Any update on this? I was facing an issue with aws-iot-device-sdk and tried upgrading to v2 but I fail to figure out how I can make aws-crt avialble in the lambda. Both when bundle with esbuild but also when deploying it in a layer. |
Don't have an update. It's in the backlog, but hasn't been prioritized/scheduled. |
The problem is in the code for the aws-crt package. In the node_modules/aws-crt/dist/native/binding.js file, there is this:
As you can see, this is trying to load some binary modules. It is making the assumption that the code that is running is two directories down from the project root, and that there will be a binary in the dist/bin directory. That works fine when running on an EC2, but not when it’s packaged into a single file. When it runs, it yields this error:
Clearly, it’s not going to find the binaries in /bin ! In fact, as far as I can tell, the binaries haven’t been copied anywhere.
It’s possible to fix it by making a change to one line:
I have the below in my package.json file to make sure this happens:
I should point out that I have not gotten it to work with webpack, because webpack is more intrusive in what it does to the code. Instead of using require, it has something called Here’s a link talking about webpack_require which may be of interest: https://devtools.tech/blog/understanding-webpacks-require---rid---7VvMusDzMPVh17YyHdyL |
@bretambrose we encounter the same issue here, where we use TypeScipt+esbuild for lambda functions. Any change to increase priority? |
Having the same exact issue here, unable to load the binaries in lambda when using esbuild and compiling it all into one single file. This is a major blocker for supporting multi-region services behind a cloudfront distribution. CloudFront cannot guarantee that you will stay within the region that the client request originated from. It is possible that CF directs someone in Virginia to Salt Lake City which would fall into us-west buckets instead of us-east. This means someone would be signing a sigv4 request expecting us-east-1 and then hits us-west-2 (thanks cloudfront) and the signature is not valid. Thus, we need sigv4a to work in lambda to support this * region. |
Justin - I am pretty sure that eslint just doesn't include the binaries in the giant zip file it makes. If you follow the changes I outlined on Dec 12 you should be able to put it together. Note the "cp -r node_modules/aws-crt/dist/bin build/dist" in the postbuild step which adds the binaries to the zip.
|
So I included aws-crt as a layer instead so it would have the files necessary but it still doesn't seem to work even when referencing the files from the layer. I'm not sure why it won't work as a layer unless the compiled index.js references are still broken even when using them? |
Thank you @mitgol, for your assistance. I encountered the same issue with my Node.js Lambda (ARM64) when trying to use a package that use aws-crt. Fortunately, I managed to resolve it with following bash commands: # generate folder "build" with index.js inside
esbuild --bundle --platform=node --target=node16 --minify --loader:.html=text --outfile=build/index.js lambda/lambda.ts
# add binary "aws-crt-nodejs.node" to the folder "build", inside subfolder "build/bin/linux-arm64-glibc"
mkdir -p build/bin/linux-arm64-glibc && cp ./node_modules/aws-crt/dist/bin/linux-arm64/aws-crt-nodejs.node build/bin/linux-arm64-glibc/.
# fix the index.js output so it looks for the binary locally
node ./scripts/fix-aws-crt-not-found.js ./build/index.js
# zipping the build folder and uploading it to lambda
rm -f ./build.zip && zip -j ./build.zip ./build/index.js && cd ./build && zip -r ../build.zip ./bin
aws lambda update-function-code --function-name YOUR_LAMBDA_NAME --zip-file fileb://build.zip --region YOUR_REGION --profile YOUR_PROFILE with // scripts/fix-aws-crt-not-found.js
const fget = (filepath) => require("fs").readFileSync(filepath).toString()
const fput = (filepath, data) => require("fs").writeFileSync(filepath, data)
const filename = process.argv[2]
const out = fget(filename).replace(
/=\[(\w+)\.join(.*?)\+"\.node"\]/g,
'=["."+$1.join$2+".node"]'
)
fput(filename, out) Hope this helps a bit |
Same exact issue when using ESBuild to compile for Lambda@Edge. I tried the solution offered by @anisg (not minified, but same idea), and for some reason this gave me the The error was being thrown in the snippet below because, for reasons unknown to me, let CrtSignerV4 = null;
try {
CrtSignerV4 = signatureV4CrtContainer.CrtSignerV4;
if (typeof CrtSignerV4 !== "function")
throw new Error();
} catch (e) {
e.message = `${e.message}
Please check whether you have installed the "@aws-sdk/signature-v4-crt" package explicitly.
You must also register the package by calling [require("@aws-sdk/signature-v4-crt");] or an ESM equivalent such as [import "@aws-sdk/signature-v4-crt";].
For more information please go to https://github.com/aws/aws-sdk-js-v3#functionality-requiring-aws-common-runtime-crt`;
throw e;
} I did something very, very ugly to work around it. // initializing variable in the global scope
let GlobalCrtSignerV4;
// ----
// setting the global variable wherever the CrtSignerV4 is defined
__name(getHeadersUnsignable, "getHeadersUnsignable");
GlobalCrtSignerV4 = CrtSignerV4; // added this line
import_signature_v4_multi_region.signatureV4CrtContainer.CrtSignerV4 = CrtSignerV4;
import_util_user_agent_node.crtAvailability.isCrtAvailable = true;
// ----
// using the global variable in the try/catch
let CrtSignerV4 = null;
try {
CrtSignerV4 = GlobalCrtSignerV4; // modified this line
if (typeof CrtSignerV4 !== "function")
throw new Error();
} catch (e) {
// ...
} Hoping there's a better way to do all this real soon. |
@mitgol thank you so much, this saved me a lot of time and pain. Hopefully there will be a real solution soon. |
@grant-d This problem is sort-of fixed in the latest release of aws-crt (1.21.1). An environment variable was added that you can set to add a specific path for the binary. The environment variable needs to be set in the Lambda configuration. In CDK the lambda is deployed like this:
The new section is environment. You can also set the environment variable manually in the AWS Console under Configuration > Environment Variables.
Note that this time around the packaging does not include all the other architectures, since only one is specified anyway in the relative path env variable. |
I know there’s a workaround but this is still a nightmare to implement a change in our builds for 50+ services to support sigv4a in our auth service. I don’t want to have to bundle the binaries manually after I run esbuild. The workaround of including it as a layer as well is a pain as every single lambda has to update and have that there before we toggle sigv4a on in auth service |
I agree it's sort of clunky, and it's annoying to have to change the deployment of the Lambda to include the environment variable. The one comment I would make is that if you change the package.json as I listed in the comment on Apr 10, there is nothing to do manually. The postbuild step copies the binary into the lambda's zip file. |
Yeah unfortunately requires us to update a ton of services which is annoying. This sigv4a logic is abstracted within a sub package we use so our services have no direct knowledge of this code and putting that build logic into dozens of services seems bad. Honestly just shocked no support yet. Would be cool if this was natively bundled into the lambda runtime even so I could always count on it being present but I know that's not feasible. |
@mitgol Thanks for the pointers! I was able to get it to work with the CDK and NodeJsFunction like this: new NodejsFunction(
this,
"Function",
{
//<snip>
environment: {
AWS_CRT_NODEJS_BINARY_RELATIVE_PATH:
"bin/linux-arm64-glibc/aws-crt-nodejs.node",
},
bundling: {
//<snip>
commandHooks: {
beforeBundling(inputDir: string, outputDir: string): string[] {
return [
`mkdir -p ${outputDir}/bin/linux-arm64-glibc && cp node_modules/aws-crt/dist/bin/linux-arm64-glibc/aws-crt-nodejs.node ${outputDir}/bin/linux-arm64-glibc`,
];
},
afterBundling(inputDir: string, outputDir: string): string[] {
return [];
},
beforeInstall(inputDir: string, outputDir: string): string[] {
return [];
},
},
},
}
); I'm using |
Describe the feature
Using esbuild to build/package a JS project that uses the CRT is an exercise in frustration. We should smooth the sharp corners and provide README and/or sample-based guidance for people who wish to use esbuild.
Ideally we should provide solutions that
We may want to special case Lambda as well with a targeted sample.
We've also had a request for flexible NAPI module path lookup here: #214
I believe proper esbuild support would have to include flexible NAPI module resolution, and so I'm consolidating that request into this feature request as well.
Use Case
N/A
Proposed Solution
No response
Other Information
No response
Acknowledgements
The text was updated successfully, but these errors were encountered: