Cannot use import statement outside a module in Lambda function - node.js

I have created a lambda function to get the list of items stored in dynamodb. Then i executed npm run build command after which i got .js files. I zipped the dist contents along with node modules, webpack.config.js and package.json and uploaded it. When i try to test it, am getting the following error. But there is no error in the code as far as i checked.
{
"errorType": "Runtime.UserCodeSyntaxError",
"errorMessage": "SyntaxError: Cannot use import statement outside a module",
"trace": [
"Runtime.UserCodeSyntaxError: SyntaxError: Cannot use import statement outside a module",
" at _loadUserApp (/var/runtime/UserFunction.js:98:13)",
" at Object.module.exports.load (/var/runtime/UserFunction.js:140:17)",
" at Object.<anonymous> (/var/runtime/index.js:43:30)",
" at Module._compile (internal/modules/cjs/loader.js:956:30)",
" at Object.Module._extensions..js (internal/modules/cjs/loader.js:973:10)",
" at Module.load (internal/modules/cjs/loader.js:812:32)",
" at Function.Module._load (internal/modules/cjs/loader.js:724:14)",
" at Function.Module.runMain (internal/modules/cjs/loader.js:1025:10)",
" at internal/main/run_main_module.js:17:11"
]
}

I had the same error with node uuid module. Importing and using it as below fixed my issue:
'use strict';
const uuid = require('uuid'); // <-- how to import
exports.hello = async (event) => {
// ...
uniqueId = uuid.v4(); // <-- how to use it
// ...
};

I was ok with using require() for the longest time BUT certain packages like netlify cannot be loaded in lambda via require().
But AWS improved this ES vs commonJS import statement support early 2022... See here. Sadly not well described.
The following steps are maybe not perfect but worked for me:
Switch to NodeJs v14 on your AWS function if you didn't already
Pack the packages that you want to use once more and don't just have a nodejs folder but also a node14 folder. The node14 folder is mentioned here and I think essential. In case you forgot how to create lambda packages follow the docs here.
Create a lib.mjs file and load the package via import from /opt/nodejs/node14/node_modules/[my-package]/[maybe-some-subfolder]/index.js.
You can export what you need as object from lib.mjs and load it from index.js
lib.mjs:
// lib.mjs
import { NetlifyAPI } from "/opt/nodejs/node14/node_modules/netlify/src/index.js";
import { Route53Client } from "/opt/nodejs/node14/node_modules/#aws-sdk/client-route-53/dist-cjs/index.js";
export function loadPackages() {
return { NetlifyAPI, Route53Client };
}
Index.js:
//index.js:
import { loadPackages } from './lib.mjs';
export async function handler(event) {
const { NetlifyAPI, Route53Client } = loadPackages();
//TODO: business logic
}
This took me a long time to research and my approach is likely not perfect. I was forced to find a solution to load netflify and it only worked via import statement. I'm happy to get feedback in the comments and I am willing to adjust my tutorial accordingly.
Currently I'd generally still recommend to stick with require() if you can. If not I hope I could help.
PS: webpack is not needed in this approach.

This might be pretty late but i fixed mine by using require instead of import when importing modules

You have a problem with your import. Review your code (imports parts) and see if your IDE detects any errors. For my case, it was :
import Jimp from 'jimp/es'
I changed it to
import Jimp from 'jimp'
And now everything works.

Related

Transforming UMD modules to ES modules in RollupJS ("The requested module X does not provide an export named 'default'")

I am currently having a TypeScript project that includes Ethers.js, which in turn includes bn.js.
The problem is
SyntaxError: The requested module './../../../bn.js/lib/bn.js' does not provide an export named 'default'
It appears to me this is because BN is in UMD format (see at https://github.com/indutny/bn.js/blob/master/lib/bn.js#L1)
(function (module, exports) {
'use strict';
// Utils
function assert (val, msg) {
if (!val) throw new Error(msg || 'Assertion failed');
}
and the correponding .ts declaration is
"use strict";
/**
* BigNumber
*
* A wrapper around the BN.js object. We use the BN.js library
* because it is used by elliptic, so it is required regardless.
*
*/
import _BN from "bn.js";
import BN = _BN.BN;
import { Bytes, Hexable, hexlify, isBytes, isHexString } from "#ethersproject/bytes";
import { Logger } from "#ethersproject/logger";
import { version } from "./_version";
const logger = new Logger(version);
It may be there's something that could be done at importing (source) or in Rollup. Difficult to tell!
Here is a screenshot of the build errors (one variation, depending on if building or running directly)
Question: Is there a way to transform this format to an ESM format in application Rollup pipeline?
I have tried using #rollup/plugin-commonjs and #rollup/plugin-node-resolve as in
resolve({ browser: true, preferBuiltins: false }), commonjs()]
(or see the project as whole at https://github.com/veikkoeeva/erc1155sample/blob/main/web/rollup.config.js, the error shows with npm run test or npm run start (in console log)).
Thus far I've had no luck cracking this, though. Hence coming here wondering if there's a dumb issue I don't see or if this is a genuinely tougher issue.
Edit: indeed, following https://rollupjs.org/guide/en/#error-name-is-not-exported-by-module and maybe named exports is the key here...

Cypress: Cannot use cy.task() to load dataset to Mongo before tests

I'm trying to use cy.taks() to load certain datasets to mongo before a test is run. But I'm getting errors. I've got a module where I export 2 functions, one from dropping a collection, and the other to load an object to a collection. Here is my cypress/plugins/index.js:
module.exports = (on, config) => {
on("task", {
"defaults:db": () => {
const {dropCollection, createUser } = require("../../lib/connectDB");
dropCollection("users");
createUser(userData)
},
});
};
Here is my /lib/connecDB.js:
export function dropCollection(collection) {
return mongoose.connection.dropCollection(collection);
}
export async function createUserInDB(userData) {
await User.create(userData);
}
So when I run the test, I'm getting:
cy.task('defaults:db') failed with the following error:
Unexpected token 'export'
Tried as well importing these function outside the index.js export, but getting same result.
I'd say it is something about export/import. The functions are exported as ES6, and imported as ES5.
I've tried to import the function the ES6 like:
import { dropCollection, createUser } from '../lib/connectDB'
And then export the plugin function also as ES6, but then I get:
Error: The plugins file is missing or invalid.
Your `pluginsFile` is set to `C:\Users\someRoute\cypress\plugins\index.js`, but either the file is missing, it contains a syntax error, or threw an error when required. The `pluginsFile` must be a `.js`, `.ts`, or `.coffee` file.
I've also tried to import required modules outside the function like:
const globalDbUtils = require('../lib/connectDB')
And then use the functions as
globalDbUtils.dropCollection("collectionName")
globalDbUtils.createUser(userData)
But I'm getting last error. I've tried pretty much everything, I tried to import Mongoose models straight, mongo client etc...Also I tried to import just one function and return it (just copy/pasting official doc...) but cannot make it work. I researched for a couple of days getting nothing, I found there is a npm package that helps u doing this, but since cypress allows you to do this by using no more plugins, I'd like to do it with no more tools than cypress itself.
Anyone knows what I am doing wrong?
Thanks in advance!
You need to use require instead of import at the top of your file and when exporting at the bottom use
module.exports = { createUserInDB }
Instead of exporting as you are currently doing.

NodeJS - using require works import does not work

I'm trying to understand why require works while import does not for an npm package. The package is r7insight_node and allows us to send our logs to their product, Rapid7. When we use require as per their instructions things work fine, but don't when I use import.
Their library has an src/index.js file that looks like:
// Use codependency for dynamically loading winston
const requirePeer = codependency.register(module);
// Import winston
const winston = requirePeer('winston', {optional: true});
const Transport = requirePeer('winston-transport', {optional: true});
// If we have successfully loaded winston (user has it)
// we initialize our InsightTransport
if (winston) {
provisionWinston(winston, Transport);
}
// Logger is default export
module.exports = Logger;
// Export as `bunyanStream` to not break existing integration
module.exports.bunyanStream = buildBunyanStream;
module.exports.provisionWinston = provisionWinston;
My understanding is that require is synchronous and is "computed" whereas import is asynchronous and is NOT "computed" as written here. Is this the reason for why require works while import does not?
Does "computed" mean in that the index.js file is executed and hence the if (winston) block is checked and executed in a require but not in an import? Is there a way to achieve the same using import statements?
Thanks in advance
for the package to work with the ES6 import way, it has to be written to it, it has to be exported as eg:export default Logger and not module.exports = Logger, hope my answer helped you

Why do I get a UserCodeSyntaxError when I have no syntax error in my code?

I'm currently creating a Dialogflow chatbot in nodejs and upon deploying my code I get an error message. I've attempted to uncomment most things out to just be left with the base functioning code and I am still unable to get it working. I'm not exactly sure what the issue is here
'use strict';
import {getAPIresponse} from "./api/index.js";
// const http = require('https');
// const respond = fulfillmentText => {
// return {
// statusCode: 200,
// body: JSON.stringify({
// fulfillmentText
// }),
// headers: {
// "Content-Type": "application/json"
// }
// }
//
// };
module.exports.dining = async (event,context) => {
const incoming= JSON.parse(event.body).queryResult;
console.log(`INCOMING: ${incoming.parameters.hall}`);
const {
displayName
} = incoming.intent;
console.log(displayName);
//const menu = getAPIresponse('https://esb.prod.uds.harvard.edu/api/dining/2.0/','events?locationId=36');
//console.log(menu);
// if(displayName === 'dining'){
// if(incoming.parameters.meal === 'breakfast'){
// //get's dining hall code to include in API request
// const hall = getCode(incoming.parameters.hall);
// //generate response from API based off of parameters passed by user
// const menu = getAPIresponse("https://esb.prod.uds.harvard.edu/api/dining/2.0/","events?locationId=${hall}", hall);
// console.log(menu);
// }
// if(incoming.parameters.meal === 'lunch'){
// //get's dining hall code to include in API request
// const hall = getCode(incoming.parameters.hall);
// //generate response from API based off of parameters passed by user
// const menu = getAPIresponse("https://esb.prod.uds.harvard.edu/api/dining/2.0","/events", hall);
// }
// if(incoming.parameters.meal === 'dinner'){
// //get's dining hall code to include in API request
// const hall = getCode(incoming.parameters.hall);
// //generate response from API based off of parameters passed by user
// const menu = getAPIresponse("https://esb.prod.uds.harvard.edu/api/dining/2.0","/events", hall);
// }
// }
};
Almost everything is commented out and I still get the error message that reads
2019-07-02 16:31:33.351 (-04:00) undefined ERROR Uncaught Exception {
"errorType":"Runtime.UserCodeSyntaxError","errorMessage":"SyntaxError: Unexpected tok
en {","stack":["Runtime.UserCodeSyntaxError: SyntaxError: Unexpected token {"," at
_loadUserApp (/var/runtime/UserFunction.js:98:13)"," at Object.module.exports.loa
d (/var/runtime/UserFunction.js:140:17)"," at Object.<anonymous> (/var/runtime/ind
ex.js:36:30)"," at Module._compile (internal/modules/cjs/loader.js:701:30)"," a
t Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)"," at Modu
le.load (internal/modules/cjs/loader.js:600:32)"," at tryModuleLoad (internal/modu
les/cjs/loader.js:539:12)"," at Function.Module._load (internal/modules/cjs/loader
.js:531:3)"," at Function.Module.runMain (internal/modules/cjs/loader.js:754:12)",
" at startup (internal/bootstrap/node.js:283:19)"]}
Worked for me: Updating Node.js version of lambda
I got this error because lambda was defined to execute with Node.js 12.x, when I changed it to Node.js 14.x (as on my local machine) it worked
If it works - and you're generally using the serverless package to automate the deployment of your lambda - don't forget to update your serverless.yml file accordingly
AWS Lambda does not support the ES6 import specifier as you've written here
import {getAPIresponse} from "./api/index.js";
because the ES6 import syntax isn't yet supported by default in Node.js (note: my lambda runtime was set to Node.js 10.x).
Illustration:
I was having this issue as well when importing a library at the top of my lambda distribution's index.js file.
The stacktrace Uncaught Exception { "errorType":"Runtime.UserCodeSyntaxError", ... unexpected token import found ... blabla... } ... was thrown in my lambda function when I used the import syntax:
import awsServerlessExpress from 'aws-serverless-express';
exports.handler = (event, context) => {
console.log('hello world!')
};
But not in this version below when I just used the standard module require syntax.
const awsServerlessExpress = require('aws-serverless-express');
exports.handler = (event, context) => {
console.log('hello world!')
};
For me, it was the import syntax that was causing the SyntaxError exceptions, but do take note that, for you, any JavaScript syntax not supported by your current Node.js runtime will throw this exception.
A couple of solutions:
Change all import statements to standard module require statements and keep using whatever default JavaScript flavour is supported by your configured Node.js runtime.
Use a transpiler like Babel w/ Webpack to transpile your ES6 JavaScript before deploying to the cloud.
Use the quick solution nicely described by Yitzchak below :) Just bump the NodeJS version on your Lambda Dashboard.
In my case, I pasted code from another lambda which had node version 14.
But my current lambda node version was 12.
The code I pasted was using optional chaining(?.) in one line. Removed it, deployed code and it worked fine.
If you are using TypeScript and encounter this error make sure the target you set in tsconfig.json matches your targeted nodejs version. For a list of recommended settings visit Node Target Mapping
For example I was targeting node.js 12 and using ES2020. Changing this to ES2019 fixed my issue.
Sometimes in lambda, when we click on Deploy all the changes are not deployed. Refresh the page and check for syntax errors.
or at least that's what was the problem in my case.
In my case I changed the tsconfig.json module setting:
"module": "es2015"
to
"module": "CommonJS",
ref: https://www.typescriptlang.org/tsconfig#module

Unable to create a Pool instance with constructor in jest test

When I run a jest test, creating a Pool instance when I require the pool, it returns a _pg.Pool is not a constructor error.
I have tried looking at the StackOverflow: pg.Pool is not a constructor
And this still does not work.
However, I am able to create a pool instance when I run the code, the error only shows up in Jest.
Node code:
import { Pool } from 'pg'
const pool = new Pool({configs})
export default pool
Error log:
● Test suite failed to run
TypeError: _pg.Pool is not a constructor
> 6 | const pool = new Pool({
|
at Object.<anonymous> (src/resources/connection.js:6:14)
at Object.require (src/routes/api.js:2:20)
at Object.<anonymous> (src/__tests__/integration/user.test.js:8:1)
sidenote: the code is a copy of the documentation in https://node-postgres.com/api/pool
I don't expect an error to occur, since pg.Pool is a class with a constructor.
In case anyone comes across the same problem, I solved it by installing pg-pool, which has been merged into main pg package, and then importing pg-pool's Pool instead of pg's.
Reference: https://github.com/brianc/node-postgres/tree/master/packages/pg-pool
I wanted to add an alternate answer because for me the issue was very subtle and simple to fix.
I have a wrapper module that leverages pg and which historically has imported it via:
import * as postgresql from 'pg';
I've always used this.pool = new postgresql.Pool( { ...bits } );
This of course led to the following error today when updating my module to be pure ESM:
TypeError: postgresql.Pool is not a constructor
at new PostgreSQLDriver (file:///home/rik/workspaces/kwaeri/node-kit/postgresql-database-driver/dist/src/postgresql-database-driver.mjs:35:278)
at file:///home/rik/workspaces/kwaeri/node-kit/postgresql-database-driver/dist/test/postgresql-database-driver.mjs:23:559
at ModuleJob.run (node:internal/modules/esm/module_job:193:25)
at async Promise.all (index 0)
at async ESMLoader.import (node:internal/modules/esm/loader:528:24)
at async importModuleDynamicallyWrapper (node:internal/vm/module:438:15)
at async formattedImport (/home/rik/workspaces/kwaeri/node-kit/postgresql-database-driver/node_modules/mocha/lib/nodejs/esm-utils.js:7:14)
at async exports.loadFilesAsync (/home/rik/workspaces/kwaeri/node-kit/postgresql-database-driver/node_modules/mocha/lib/nodejs/esm-utils.js:91:20)
at async singleRun (/home/rik/workspaces/kwaeri/node-kit/postgresql-database-driver/node_modules/mocha/lib/cli/run-helpers.js:125:3)
at async exports.handler (/home/rik/workspaces/kwaeri/node-kit/postgresql-database-driver/node_modules/mocha/lib/cli/run.js:370:5)
I tried using named exports as the documentation seems to suggest in the Check, use, return section, but that got me:
file:///home/rik/workspaces/kwaeri/node-kit/postgresql-database-driver/dist/src/postgresql-database-driver.mjs:23
cov_1u3o9s5ali=function(){return actualCoverage;};}return actualCoverage;}cov_1u3o9s5ali();import{Pool}from'pg';import{DatabaseDriver}from'#kwaeri/database-driver';// You'll need this line and the method definitions below
^^^^
SyntaxError: Named export 'Pool' not found. The requested module 'pg' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:
import pkg from 'pg';
const {return actualCoverage;};}return actualCoverage;}cov_1u3o9s5ali();import{Pool}from'pg';import{DatabaseDriver} = pkg;
... As I had actually expected it would.
Anyways, the fix is hinted to by typescript in the syntax error above - doh:
import Postgres from `pg`;
// ...
this.pool = new Postgres.Pool( { ...bits } );
That resolves the issue.

Resources