使用CDK部署Lambda时出现模块找不到错误的求助
问题描述
使用AWS CDK开发无服务器应用,TypeScript文件编译后部署Lambda函数,调用时出现「模块未找到」错误,提示无法找到@aws-sdk/client-dynamodb模块。
部署步骤
tsc:编译TS文件cdk synth:生成CloudFormation模板cdk deploy:部署堆栈
TypeScript配置
{ "compilerOptions": { "target": "ES2018", "module": "commonjs", "lib": [ "es2018" ], "noEmit": false, "declaration": false, "strict": true, "noImplicitAny": true, "strictNullChecks": true, "noImplicitThis": true, "alwaysStrict": true, "noUnusedLocals": false, "noUnusedParameters": false, "noImplicitReturns": true, "noFallthroughCasesInSwitch": false, "inlineSourceMap": true, "inlineSources": true, "experimentalDecorators": true, "strictPropertyInitialization": false, "typeRoots": [ "./node_modules/@types" ] }, "exclude": [ "node_modules", "cdk.out" ] }
Lambda函数代码
import { APIGatewayProxyEventV2, APIGatewayProxyResultV2 } from 'aws-lambda'; import { DynamoDBClient, GetItemCommand, GetItemCommandInput } from "@aws-sdk/client-dynamodb"; import { marshall, unmarshall } from "@aws-sdk/util-dynamodb"; export async function handler(event: APIGatewayProxyEventV2): Promise<APIGatewayProxyResultV2> { console.log('event', event); let userLat = event.pathParameters?.lat; let userLng = event.pathParameters?.lng; let tableName = process.env.TABLE_NAME; let results; const dbClient: DynamoDBClient = new DynamoDBClient({ region: "ap-south-1" }); let params: GetItemCommandInput; if (tableName) { params = { TableName: tableName, Key: marshall({ "lat": userLat, "lng": userLng }), }; } const run = async function () { try { const resp = await dbClient.send(new GetItemCommand(params)); results = unmarshall(resp.Item || {}); } catch(err) { results = err; } }; run(); return { body: JSON.stringify(results), statusCode: 200 }; }
环境信息
- Node: v14.20.0
- NPM: 6.14.17
- CDK: 2.40.0 (build 56ba2ab)
- TypeScript: Version 4.8.2
错误信息
{"errorType": "Runtime.ImportModuleError","errorMessage": "Error: Cannot find module '@aws-sdk/client-dynamodb'\nRequire stack:\n- /var/task/fetchpartner.js\n- /var/runtime/UserFunction.js\n- /var/runtime/Runtime.js\n- /var/runtime/index.js","trace": ["Runtime.ImportModuleError: Error: Cannot find module '@aws-sdk/client-dynamodb'","Require stack:","- /var/task/fetchpartner.js","- /var/runtime/UserFunction.js","- /var/runtime/Runtime.js","- /var/runtime/index.js"," at _loadUserApp (/var/runtime/UserFunction.js:221:13)"," at Object.module.exports.load (/var/runtime/UserFunction.js:279:17)"," at Object. (/var/runtime/index.js:43:34)"," at Module._compile (internal/modules/cjs/loader.js:1085:14)"," at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)"," at Module.load (internal/modules/cjs/loader.js:950:32)"," at Function.Module._load (internal/modules/cjs/loader.js:790:12)"," at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:75:12)"," at internal/main/run_main_module.js:17:47"]}
解决方案
1. 检查依赖安装类型
确保@aws-sdk/client-dynamodb和@aws-sdk/util-dynamodb是生产依赖,而非开发依赖。执行以下命令重新安装:
npm install @aws-sdk/client-dynamodb @aws-sdk/util-dynamodb --save
如果之前误安装为开发依赖(--save-dev),需要先卸载再重新安装:
npm uninstall @aws-sdk/client-dynamodb @aws-sdk/util-dynamodb --save-dev npm install @aws-sdk/client-dynamodb @aws-sdk/util-dynamodb --save
2. 配置CDK正确打包Lambda代码
推荐使用CDK的NodejsFunction构造,它会自动通过esbuild打包代码并包含所需依赖,无需手动处理node_modules。示例堆栈代码:
import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs'; import { Stack, StackProps } from 'aws-cdk-lib'; import { Construct } from 'constructs'; export class YourStack extends Stack { constructor(scope: Construct, id: string, props?: StackProps) { super(scope, id, props); new NodejsFunction(this, 'FetchPartnerFunction', { entry: './path/to/your/lambda.ts', // 指向你的TS文件路径 handler: 'handler', runtime: lambda.Runtime.NODEJS_14_X, environment: { TABLE_NAME: 'your-table-name' } }); } }
如果使用普通Function构造,需要手动将node_modules和编译后的JS文件一起打包,或者使用webpack/esbuild将代码打包成单个文件,避免依赖缺失。
3. 修正Lambda异步逻辑问题
代码中run()是异步函数却未使用await,会导致函数提前返回results(此时为undefined)。修改为:
await run();
4. 验证编译后的文件结构
执行tsc后,检查编译后的JS文件是否在CDK指定的代码目录下,且该目录包含正确的依赖(如果手动打包的话)。确保CDK的Function配置中的code属性正确指向编译后的代码目录。
内容的提问来源于stack exchange,提问作者Karthik Rajan

