Using ES modules in AWS Lambda created by Amplify CLI - node.js

According to the AWS blog, use of ES modules in Lambda is supported as of the Nodejs14 runtime.
Announcement - https://aws.amazon.com/about-aws/whats-new/2022/01/aws-lambda-es-modules-top-level-await-node-js-14/
Example - https://aws.amazon.com/blogs/compute/using-node-js-es-modules-and-top-level-await-in-aws-lambda/
I have checked that the Lambda function runtime is Node14 (and tried switching to Node18 without any difference) - I checked via the Lambda console once I'd pushed the code, and checked that the version changes to 18 when the setting in the Amplify config is changed.
I won't go into the detail of how I got here, other than I need to use an npm package that is written to ESM syntax.
As a sanity check and as a minimum reproducable example, I generated a new simple hello world function with the Amplify CLI, and then ran it with amplify mock function test --event src/event.json and confirmed it runs ok. But when I change the package.json to "type":"module" I get:
stack: 'Error: Could not load lambda handler function due to Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /[redacted]/amplify/backend/function/test/src/index.js\n' +
'require() of ES modules is not supported.\n' +
'require() of /[redacted]/amplify/backend/function/test/src/index.js from /snapshot/repo/build/node_modules/amplify-nodejs-function-runtime-provider/lib/utils/execute.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.\n'
I get this same error whether I exercise the function from the amplify mock function CLI, the Lambda console, or by accessing the API gateway that links to the Lambda function.
Beyond the link blog posts above, I can't find any other mention or examples of using ES Modules with Lambda.
If you want to do this yourself:
Install amplify cli
amplify init
amplify add function and name it test, choose Nodejs, Hello World template
amplify mock function test --event src/event.json and it will work
Change amplify/backend/function/test/src/package.jsonto include"type":"module"`
amplify mock function test --event src/event.json and it will fail
Optionally you can push the application to AWS and test the lambda through the lambda console, you should get the same results.
Related issues:
https://github.com/aws-amplify/amplify-cli/issues/10437: Same issue in that the module being imported is ESM, and resolve in that a version update to the module provided CJS support
https://github.com/aws-amplify/amplify-cli/issues/5691: This relates to the root project being ESM (type: module in package.json) and monkey patching the package.json via amplify hooks, but doesn't address the issue of importing an ESM package. There is a comment at the bottom that claims its fixed in amplify CLI 10.2.3, but might have only addresses the root package issue, and not the lambda sub-project where I've encountering it.
https://github.com/aws-amplify/amplify-cli/issues/10432: Relates to use of 'mock function', but the problem relates to mocked or deployed functions. The steps outlined are about continuing to generate CJS output from typescript, converting the TS codes ESM style import/export. Because the code that amplify runs is CJS, if you try to import an ESM package it'll fail.

Related

How to import from a bundle created in webpack?

I'm working on a project that's based on a given sample project that uses a package named Seeso.
The sample project uses the 'cross-env' and 'parcel-bundler' packages which are both deprecated, and I would like to replace them with pure node.
I managed to create a backend that statically serves requested files and thus handles imports,
but the Seeso package seems to dynamically resolve its imports using a webpack bundle (I have little to no knowledge of webpack but not even a configuration file is present; just the bundle), and I get the following error after I changed the import path of Seeso in the easy-seeso.js file to its actual path:
Uncaught SyntaxError: The requested module '/external_modules/seeso/dist/seeso.js' does not provide an export named 'CalibrationAccuracyCriteria' (at easy-seeso.js:2:34)
because of
import Seeso, {InitializationErrorType, CalibrationAccuracyCriteria} from '/external_modules/seeso/dist/seeso.js';
How can I import the needed Seeso files from the webpack bundle with minimum work and understanding of webpack as possible? (Preferably without running webpack commands before running - would like to run 'node server.js' and that's it)
Here is the sample project:
https://github.com/visualcamp/seeso-sample-web

function used across several lambda functions in aws

I am new to nodeJS, npm, and aws lambda. Suppose I have a custom sort algorithm that I want to use in several lambda functions. This should be something very simple, but the only way I have found is to create a layer with a node module published as an npm package. I do not want any of the code be uploaded to an npm.
I tried to download the layer I am currently using, create a folder in node_modules along with other packages that are published in npm with
npm init
fill all the info for the package.json
created a function code in a index.js
'use strict'
exports.myfunc= myfunc;
function myfunc() {
console.log("This is a message from the demo package");
}
zip all the layer again and upload it in a version 2 of the layer
pick the new version in a lambda function and call it as i would do with any other node_module form a third party, like this:
const mypack= require('mypack');
mypack.myfunc();
but it tells me:
"errorMessage": "Error: Cannot find module ... \nRequire stack:\n- /var/task/index.js\n- /var/runtime/UserFunction.js\n- /var/runtime/index.js",
I think it maybe because in the layer in the nodejs folder, there is package-lock.json and my module is not there. I tried to put it there without the "resolved" and "integrity" that the packages published on npm have but did not work.
Is there a way to simply upload the code I want in a nodejs layer having nothing to do with npm?
I would like to try something such as this in the accepted answer,
var moduleName = require("path/to/example.js")
How to install a node.js module without using npm?
but I don't know where is the path of the modules of a layer, the path of lambda that shows __dirname is /var/task, but it looks like any lambda has same path. I am lost...
I was able to import js in a folder in the following manner:
download the zip of the layer uncompress it, put in node_modules any additional folder with your custom js and upload it as a new version of the layer.
In the lambda function, reference it with
moduleName = require("path/to/example.js")
You can find that path, which is the trick here, using a known library you already have in your layer and is working, in my case I used base64-js, then I returned the path of that library like this:
require.resolve('base64-js')
That returned
'/opt/nodejs/node_modules/base64-js/index.js'
So I used
moduleName = require("/opt/nodejs/node_modules/MYCUSTOMFOLDER/index.js")
and that was it...

I get bcrypt error after deployed my nodejs/expressjs app to AWS lambda

I am trying to make my express.js app works on AWS Lambda. The deployment (using serverless framework completes successfully, however the app returns a 500 internal error when I test my requests. My logs shows me this error :
/var/task/node_modules/bcrypt/lib/binding/napi-v3/bcrypt_lib.node: invalid ELF header.
I've tried to replace bcrypt with bcryptjs but the problem persists.
Also, in my serverless.yml, I've added the following line to force lambda to install bcrypt by itself, but apparently it didn't make the trick :
package:
exclude:
- node_modules/**
Any suggestion ?
First, please include node modules. AWS won't install anything into the lambda node env besides the aws-sdk.
Secondly, you're seeing this error because your likely developing on a mac OS machine, so the bycrypt binary from your machine is ending up getting uploaded to lambda.
Please double check that when you tried bcryptjs, you fully removed bcrypt from your project dependencies.

Camaro : Module not found: Can't resolve xxxx

using Camaro npm package to transform XML in Server-less framework lambda project and getting error when running sls offline command -
Module not found for asm2wasm, env, global
WebAssembly module is included in initial chunk.
This is not allowed, because WebAssembly download and compilation must happen asynchronous.
Add an async splitpoint (i. e. import()) somewhere between your entrypoint and the WebAssembly module:

Loosing jest variable when using esm package

I followed this answer to make jest work with esm packages
node - using jest with esm package
But I get an error when I try to do jest.SpyOn because it said that jest is undefined.
I did some digging and notice that jest is present on my app.test.js file but not in the asserts.js
So I was wondering how can I get the jest variable on the assert file or can I import jest directly without relaying on injecting it like the default config

Resources