AWS Lambda's failure to recognize JS modules in Node.js - node.js

I had a working Node 16 Lambda backend. After converting it to typescript, when I deploy, I get this error in CloudWatch: "SyntaxError: Cannot use import statement outside a module". This does not occur when running locally.
Changing module in tsconfig to commonjs has been suggested as a solution. However, doing so yields ReferenceError: exports is not defined in ES module scope when running locally.
What might be the solution?
full error
"Runtime.UserCodeSyntaxError: SyntaxError: Cannot use import statement outside a module",
" at _loadUserApp (file:///var/runtime/index.mjs:997:17)",
" at async Object.UserFunction.js.module.exports.load (file:///var/runtime/index.mjs:1035:21)",
" at async start (file:///var/runtime/index.mjs:1200:23)",
" at async file:///var/runtime/index.mjs:1206:1"
package.json
...
"scripts": {
...
"prebuild": "rm -rf dist",
"build": "esbuild handler.ts --bundle --minify --sourcemap --platform=node --target=esnext --format=esm --outfile=dist/handler.js",
"postbuild": "cd dist && zip -r handler.zip handler.js*"
},
"type": "module"
tsconfig.json
{
"compilerOptions": {
"lib": ["dom", "dom.iterable", "ESNext"],
"esModuleInterop": true,
"module": "esnext",
"target": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": false,
"noEmit": true,
"outDir": "dist",
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"strict": true,
"noImplicitAny": true,
"useUnknownInCatchVariables": false,
"inlineSourceMap": true,
"rootDir": ".",
"baseUrl": ".",
"paths": {
"#/*": ["./*"],
},
},
"include": [
"./*",
"*"
],
"exclude": [
"node_modules",
"public"
],
"ts-node": {
"esm": true,
"require": ["tsconfig-paths/register"]
},
"lib": ["esnext"]
}
handler.ts
process.env.NODE_ENV = "prod";
import mongoose from "mongoose";
import app from "./app.js";
...
export const lambdaHandler = async (event: any, context: any) => {
...
}
export default { lambdaHandler };
deployment
aws lambda update-function-code --function-name jigglypuff-kicks-ass --zip-file "fileb://dist/handler.zip"

Related

Error [ERR_REQUIRE_ESM]: require() of ES Module in fastify project

Trying to import fastify-openapi-glue in my fastify project but getting error ERR_REQUIRE_ESM and I'm using typescript in the application.
Code looks like below
routes.ts file
/* eslint-disable node/no-unsupported-features/es-syntax */
import { FastifyInstance } from 'fastify';
// import openapiGlue from 'fastify-openapi-glue';
// const openapiGlue = await import("fastify-openapi-glue");
import { Service } from '../controllers/service';
async function loadOpenapiGlue() {
const openapiGlueModule = await import('fastify-openapi-glue');
return openapiGlueModule.default;
}
const options = {
specification: './openapi.yaml',
service: new Service()
};
export default async (app: FastifyInstance): Promise<void> => {
const openapiGlue = await loadOpenapiGlue();
app.register(openapiGlue, options);
};
tsconfig.json file
{
"ts-node": {
"require": ["tsconfig-paths/register"]
},
"compilerOptions": {
"alwaysStrict": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"removeComments": true,
"lib": ["ES2020"],
"module": "commonjs",
"moduleResolution": "node",
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"baseUrl": "./src",
"rootDirs": ["src"],
"outDir": "dist",
"plugins": [],
"resolveJsonModule": true,
"skipLibCheck": true,
"strict": true,
"strictNullChecks": true,
"target": "ES2020",
"types": ["node", "jest"],
"paths": {
"#/*": ["*"]
}
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}
Note:
After updating the module under tsconfig.json as mentioned in other stackoverflow answer as "module": "ES2022", I'm getting error like SyntaxError: Cannot use import statement outside a module

How to use tsconfig-paths with ts-node

How do you setup paths with typescript to run with ts-node? And later compile paths to absolute paths when compiling?
I have following very minimal structure:
koki.ts:
export const calculate = (a: number, b: number) => {
return a + b;
};
index.ts:
import { calculate } from "#koki/koki";
const result = calculate(1, 2);
console.log(result);
tsconfig.json:
{
"ts-node": {
"transpileOnly": true,
"require": ["tsconfig-paths/register"]
},
"compilerOptions": {
"target": "es2017",
"module": "commonjs",
"lib": ["dom", "es6", "es2017", "esnext.asynciterable"],
"skipLibCheck": true,
"sourceMap": true,
"outDir": "./dist",
"moduleResolution": "node",
"removeComments": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"noImplicitThis": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"resolveJsonModule": true,
"baseUrl": ".",
"paths": {
"#/*": ["*"],
"#koki/*": ["koki/*"]
}
},
"exclude": ["node_modules"],
"include": ["./src/**/*.ts"]
}
I am getting:
ts-node src/index.ts
Error: Cannot find module '#koki/koki'
Require stack:
- /home/pwnage/Documents/github/test-node/src/index.ts
In my case, I added the -r option to ts-node scripts
package.json
"scripts": {
"start": "ts-node -r tsconfig-paths/register src/index.ts",
}
ts-node works well in these codes
import { env } from "#/config/env";

How to use paths with ts-node?

I have this project structure:
How to configure tsconfig.json for using paths like #app/, #server/.
I try this:
{
"compilerOptions": {
"module": "CommonJS",
"target": "es5",
"lib": [
"esnext",
"dom"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": false,
"baseUrl": "..",
"paths": {
"#app/*": [
"app/*"
],
"#server/*": [
"server/*"
]
}
},
"include": [
"."
]
}
Same config works with webpack and ts-loader, but when i run npx ts-node server/index.ts i got error:
npx ts-node server/index.ts
Error: Cannot find module '#server/a'
server/index.ts :
import a from '#server/a'
console.log('This is index.ts')
a()
Your config works for webpack because you run webpack from the project root. It does not work for server.ts because the path is relative to its directory. Try:
"paths": {
"#app/*": [
"../app/*"
],
"#server/*": [
"../server/*"
]
}
If you need to do it for both, you need two different tsconfig.json - one in the root and one in app or server.
Take a look at my project: https://github.com/mmomtchev/rlayers
It uses this feature a lot.

Cannot use import statement outside a module Electron React Typescript

How to solve the famous issue "Cannot use import statement outside a module" in an Electron-React-Typescript app?
//const { app, BrowserWindow } = require('electron');
import { app, BrowserWindow } from 'electron';
Error :
import { app, BrowserWindow } from 'electron';
^^^^^^
SyntaxError: Cannot use import statement outside a module
in package.json I added :
"type": "module",
devDependencies in package.json :
"#types/node": "^14.14.28",
"#types/react": "^17.0.2",
"electron": "^11.2.3",
"typescript": "^4.1.5",
"webpack": "^5.21.2"
tsconfig.json :
{
"compilerOptions": {
"target": "ES2018",
"module": "CommonJS",
"lib": ["dom", "esnext"],
"outDir": "dist",
"declaration": true,
"declarationMap": true,
"noEmit": true,
"jsx": "react",
"strict": true,
"pretty": true,
"sourceMap": true,
"skipLibCheck": true,
"noImplicitAny": false,
"noImplicitThis": false,
/* Additional Checks */
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
/* Module Resolution Options */
"moduleResolution": "node",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true,
"allowJs": true
},
"include": ["src/**/*"],
"exclude": [
"src/index.js",
"dist",
]
}
I also added in babel.config.json 's plugins :
["#babel/plugin-transform-modules-commonjs", {
"allowTopLevelThis": true
}],
and in package.json :
"scripts": {
"babel": "babel ./src/**/* -d dist",
"start": "yarn run babel && electron .",
electron : 11.2.3
typescript : 4.1.5
node: v14.5.0
O.S. : Ubuntu 18.04.4 Desktop
What do I have to add / modify in order to be able to use "import" ?
Thanks to and Electron's expert I discovered two errors which caused that issue:
I modified the main's path in package.json
"main": "./src/main/main.ts" ---> "main": "./dist/main/main.js"
because electron can understand only the compiled file
I removed in package.js on
"type": "module"
which otherwise wuold require to change .js to .cjs files

Node Error: Cannot find module - typescript api for custom module where I export mongoose schemas and interfaces

I have a typescript module #tlabs/models where I'm simply exporting in index.ts:
export * from '../models......'
where in each file I have something like:
export const Project = typedModel('projects', ProjectSchema);
and my only dependency is ts-mongoose imported in each file simply as:
import { createSchema, Type, typedModel, ExtractProps } from 'ts-mongoose';
ts-mongoose being a dependency that itself required mongoose + mongoose types.
In my typescript node project I have ts-mongoose, mongoose and #tlabs/models as dependencies and #types/mongoose as dev dependency.
Running tsc is fine, the files get compiled and there's no error being thrown out but then trying to run the actual files throws out:
Error: Cannot find module '#tlabs/models'
I have reinstalled all modules several times and checked package.json as well as the actual files on the disk + through vscode and they're right there.
What am I missing out?
My tsconfig is:
{
"include": ["src/**/*"],
"exclude": ["node_modules", "./node_modules", "./node_modules/*"],
"compilerOptions": {
"module": "commonjs",
"esModuleInterop": true,
"target": "es6",
"allowJs": true,
"moduleResolution": "node",
"sourceMap": true,
"outDir": "dist",
"noImplicitAny": false,
"alwaysStrict": true,
"strictNullChecks": true,
"types": [],
"lib": [],
"experimentalDecorators": true
}
}
My final TS config for my exported models:
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"outDir": "lib",
"strict": true,
"esModuleInterop": true
},
"include": ["src"]
}
and relevant package.json configuration:
{
"main": "lib/index.js",
"types": "lib",
"scripts": {
"tsc": "tsc",
"build": "tsc -p ."
},
"files": [
"lib"
],
}

Resources