Reputation: 9045
I have the following lambda.ts
code I'm trying to make running on an AWS Lambda:
import 'aws-sdk'
import { /* bunch of stuff... */ } from "@aws-sdk/client-cloudwatch-logs";
import {Context, APIGatewayProxyResult} from 'aws-lambda';
import {DateTime} from "luxon";
export const lambdaHandler = async (event: any, context: Context): Promise<APIGatewayProxyResult> => {
/* ... stuff ... */
}
which gets transpiled to:
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.lambdaHandler = void 0;
require("aws-sdk");
//import {CloudWatchClient} from "@aws-sdk/client-cloudwatch";
const client_cloudwatch_logs_1 = require("@aws-sdk/client-cloudwatch-logs");
const luxon_1 = require("luxon");
const lambdaHandler = async (event, context) => {
/* ... transpiled stuff ... */
}
When hitting the button, I'm getting this Response:
{
"errorType": "Runtime.ImportModuleError",
"errorMessage": "Error: Cannot find module '@aws-sdk/client-cloudwatch-logs'\nRequire stack:\n- /var/task/lambda.js\n- /var/runtime/index.mjs",
"trace": [
"Runtime.ImportModuleError: Error: Cannot find module '@aws-sdk/client-cloudwatch-logs'",
"Require stack:",
"- /var/task/lambda.js",
"- /var/runtime/index.mjs",
" at _loadUserApp (file:///var/runtime/index.mjs:951:17)",
" at async Object.UserFunction.js.module.exports.load (file:///var/runtime/index.mjs:976:21)",
" at async start (file:///var/runtime/index.mjs:1137:23)",
" at async file:///var/runtime/index.mjs:1143:1"
]
}
I played a lot with tsconfig.json
, trying many things from Google / GitHub / SO / Rumors / Astrology / Numerology / Praying (monotheistic, pantheon-dwelling, neither..), but it only made me more confused.
For instance:
tsconfig.json
from Building Lambda functions with TypeScript still emits a single transpiled .js
file without embedding the import
ed @aws-sdk/client-cloudwatch-logs
module in the emitted output lambda.js
filenpm install @aws-sdk/...
(naturally), but doesn't explain anything beyond, which makes me think that maybe I shouldn't bundle them at all, but simply import
them (in the assumption that they are pre-defined/loaded in AWS's Lambda's runtime)Runtime is Node.js 16.x
, Handler is lambda.lambdaHandler
(emitted file is called lambda.js
), and this is my current tsconfig.json
:
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"module": "commonjs",
"moduleResolution": "Node",
"target": "ES2022",
"sourceMap": true,
"lib": [
"ES2021"
],
"typeRoots": ["node_modules/@types"],
"outDir": "build",
"baseUrl": "src",
"strict": true,
"forceConsistentCasingInFileNames": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"inlineSources": true,
"rootDir": "src",
"preserveConstEnums": true,
"isolatedModules": true,
"incremental": true,
"importHelpers": true
},
"exclude": [
"node_modules",
"**/*.test.ts"
]
}
So I'm trying to understand:
import
ed modules (such as @aws-sdk/client-cloudwatch-logs
) at all, or they are already loaded by AWS Lambda's runtime?tsconfig.json
properly?tsconfig.json
to emit those 3rd-party modules?index.html
) is involved, then not all of them can fit?Upvotes: 0
Views: 2598
Reputation: 3915
AWS SDK for JavaScript v3 (AKA modular) is not installed globally in the lambda execution context. You are using a v3 module (@aws-sdk/client-cloudwatch-logs
) which is why it fails. AWS SDK v2 is installed globally, you are also using it (aws-sdk
) so that require
works fine.
You should use a bundler like webpack, esbuild, parcel or rollup. If you are using AWS CDK, there is a nodejs function construct that will do the bundling with esbuild for you.
TS will only emit your compiled javascript. If you are depending on javascript found in your node_modules
directory, simply include that directory in your deployment package.
Generally, bundlers will take your application entry points (main.js, handler.js, whatever you want really) and recursively resolve all the dependencies, tree-shake any unreachable code then create one file for each entry point that has no other external dependencies. There is a runtime performance cost to this of course but it does simplify things and in a serverless context it isn't usually too impactful.
So, to resolve your error you can take one of two approaches:
Note that in either case, you need to be careful about dependencies with native bindings (binaries basically) as the one installed on your dev machine likely isn't supported in the lambda environment.
Upvotes: 1