使用AWS CDK TypeScript创建的Lambda Layer无法被Lambda函数导入的问题
问题:Lambda Layer模块无法导入的排查与修复
问题场景
使用API Gateway、Lambda与AWS CDK(TypeScript)构建无服务器API时,创建Lambda Layer并在Lambda函数中复用,调用函数时出现Cannot find module '/opt/nodejs/calculator'错误。
相关代码
Lambda Handler代码(路径:{root}/api/src/handlers/layer-lambda.handlers.ts)
import { add } from "/opt/nodejs/calculator"; import {APIGatewayProxyHandler} from "aws-lambda"; export const calculate: APIGatewayProxyHandler = async (event) => { const result = add(1, 2); return { statusCode: 200, headers: { "Content-Type": "application/json" }, body: JSON.stringify({ message: `1 + 2 = ${result}` }) } }
Lambda Layer代码(路径:{root}/api/src/layers/calculator/nodejs/calculator.js)
export const add = (num1: number, num2: number) => { return num1 + num2; }
Layer的package.json(路径:{root}/api/src/layers/calculator/nodejs/package.json)
{ "name": "calculator", "version": "0.1.0", "dependencies": {} }
tsconfig.json路径配置
{ "compilerOptions": { // 其他配置 "paths": { "/opt/nodejs/calculator": [ "src/layers/calculator/nodejs/calculator" ] } } }
CDK中的Layer与Lambda配置
const layerVersion = new LayerVersion(this, getStageSpecificResourceId(`calculator-layer`), { compatibleRuntimes: [ Runtime.NODEJS_18_X ], compatibleArchitectures: [ Architecture.X86_64 ], code: Code.fromAsset(path.resolve(__dirname, `../../api/src/layers/calculator`)), description: `Simple calculator lambda layer`, }); const calHandler = new NodejsFunction(this, `calculate`, { entry: path.resolve(__dirname, `../../api/src/handlers/layer-lambda.handlers.ts`), functionName: getVariantSpecificResourceId(`calculate`), handler: `calculate`, memorySize: 1024, runtime: Runtime.NODEJS_18_X, timeout: cdk.Duration.seconds(30), bundling: { sourceMap: true, minify: false, externalModules: [ `/opt/nodejs/calculator` ], }, environment: {}, layers: [ layerVersion, ], }); this.api.root.addResource("calculate").addMethod("GET", new LambdaIntegration(calHandler));
错误信息
{ "errorType": "Runtime.ImportModuleError", "errorMessage": "Error: Cannot find module '/opt/nodejs/calculator'\nRequire stack:\n- /var/task/index.js\n- /var/runtime/index.mjs", "stack": [ "Runtime.ImportModuleError: Error: Cannot find module '/opt/nodejs/calculator'", "Require stack:", "- /var/task/index.js", "- /var/runtime/index.mjs", " at _loadUserApp (file:///var/runtime/index.mjs:1087:17)", " at async UserFunction.js.module.exports.load (file:///var/runtime/index.mjs:1119:21)", " at async start (file:///var/runtime/index.mjs:1282:23)", " at async file:///var/runtime/index.mjs:1288:1" ] }
错误原因分析
- Layer代码未编译为JavaScript:Layer中的
calculator.js实际是TypeScript代码,但扩展名错误标注为.js,Lambda Node.js运行时无法直接执行TS代码,必须编译为JS。 - externalModules配置错误:
bundling.externalModules中配置绝对路径/opt/nodejs/calculator无效,该配置需要指定模块名称(对应Layer中package.json的name字段),而非运行时绝对路径。 - Layer目录结构与打包逻辑问题:CDK打包Layer时,未将TS代码编译为JS,导致部署到Lambda的Layer中没有可执行的JS文件;同时Node.js模块查找逻辑是从
/opt/nodejs/node_modules下查找模块,直接用绝对路径导入不符合模块解析规则。
修复步骤
1. 修正Layer代码的扩展名与编译
- 将
{root}/api/src/layers/calculator/nodejs/calculator.js重命名为calculator.ts。 - 在Layer的
nodejs目录下添加tsconfig.json(或复用项目根目录的配置),确保编译输出到当前目录:
{ "compilerOptions": { "target": "ES2020", "module": "ESNext", "outDir": ".", "strict": true, "moduleResolution": "node" } }
2. 调整CDK中Layer的打包逻辑
让CDK在打包Layer时自动编译TS代码,修改LayerVersion的code配置:
const layerVersion = new LayerVersion(this, getStageSpecificResourceId(`calculator-layer`), { compatibleRuntimes: [Runtime.NODEJS_18_X], compatibleArchitectures: [Architecture.X86_64], code: Code.fromAsset(path.resolve(__dirname, `../../api/src/layers/calculator`), { bundling: { image: Runtime.NODEJS_18_X.bundlingImage, command: [ 'bash', '-c', 'cd nodejs && npm install && npx tsc && rm -rf node_modules && cd .. && cp -r nodejs/* /asset-output/' ], }, }), description: `Simple calculator lambda layer`, });
这段命令会进入nodejs目录,安装依赖(如果有),编译TS代码,清理不必要的依赖,最后将编译后的内容复制到Layer的输出目录。
3. 修正Lambda函数的导入与配置
- 修改Lambda Handler的导入语句,使用模块名(对应Layer中package.json的
name字段):
import { add } from "calculator";
- 更新tsconfig.json的paths配置,对应模块名:
{ "compilerOptions": { // 其他配置 "paths": { "calculator": [ "src/layers/calculator/nodejs/calculator" ] } } }
- 调整NodejsFunction的externalModules配置,使用模块名:
bundling: { sourceMap: true, minify: false, externalModules: ["calculator"], },
4. 验证Layer目录结构
部署后,Lambda运行时会将Layer挂载到/opt,正确的目录结构应为:
/opt └── nodejs ├── package.json └── calculator.js
Node.js会自动将/opt/nodejs加入模块查找路径,因此可以直接通过模块名calculator导入。
验证
重新部署CDK栈后,调用API Gateway的/calculate接口,应返回{"message":"1 + 2 = 3"},无模块导入错误。
内容的提问来源于stack exchange,提问作者Wai Yan Hein
相关产品推荐
相关产品推荐

