Node18环境下AWS Lambda TypeScript部署报错Runtime.ImportModuleError求助
问题描述
之前在Node.js 16环境用JavaScript部署AWS Lambda完全正常,现在切换到Node.js 18环境开发TypeScript版本的Lambda函数,通过AWS SAM生成并使用AWS Toolkit部署后,调用函数时出现以下错误:
2023-08-03T14:59:27.311Z undefined ERROR Uncaught Exception
{
"errorType": "Runtime.ImportModuleError",
"errorMessage": "Error: Cannot find module 'index'\nRequire stack:\n- /var/runtime/index.mjs",
"stack": [
"Runtime.ImportModuleError: Error: Cannot find module 'index'",
"Require stack:",
"- /var/runtime/index.mjs",
" at _loadUserApp (file:///var/runtime/index.mjs:997:17)",
" at async UserFunction.js.module.exports.load (file:///var/runtime/index.mjs:1029:21)",
" at async start (file:///var/runtime/index.mjs:1192:23)",
" at async file:///var/runtime/index.mjs:1198:1"
]
用户当前的配置文件如下:
index.ts
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda'; export const handler = async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => { try { return { statusCode: 200, body: JSON.stringify({ message: 'hello world', }), }; } catch (err) { console.log(err); return { statusCode: 500, body: JSON.stringify({ message: 'some error happened', }), }; } };
package.json
{ "name": "hello_world", "version": "0.3.0", "description": "", "main": "index.ts", "scripts": { "compile": "tsc" }, "dependencies": { "esbuild": "^0.14.14" }, "devDependencies": { "@types/aws-lambda": "^8.10.92", "@types/node": "^18.11.4", "ts-node": "^10.9.1", "typescript": "^4.8.4" } }
template.yaml
AWSTemplateFormatVersion: '2010-09-09' Transform: 'AWS::Serverless-2016-10-31' Description: An AWS Serverless Specification template describing your function. Resources: generateblogpostv1: Type: 'AWS::Serverless::Function' Properties: Handler: index.handler Runtime: nodejs18.x CodeUri: . Description: '' MemorySize: 128 Timeout: 900 Role: >- arn:aws:iam::921222634505:role/service-role/... RuntimeManagementConfig: UpdateRuntimeOn: Auto
tsconfig.json
{ "compilerOptions": { "target": "es2020", "strict": true, "preserveConstEnums": true, "noEmit": true, "sourceMap": false, "module":"es2015", "moduleResolution":"node", "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, }, "exclude": ["node_modules"] }
问题原因分析
- TypeScript未编译为JavaScript:
tsconfig.json中noEmit设为true,TypeScript编译器不会生成JavaScript文件,而Lambda运行时无法直接执行.ts文件。 - 入口文件指向错误:
package.json的main字段设为index.ts,Lambda运行时需要的是编译后的.js文件。 - 部署配置未适配编译产物:SAM的
CodeUri指向源码目录,未指向编译后的JavaScript文件目录,导致部署包中没有可执行的代码。
解决方案
步骤1:修改tsconfig.json,启用编译输出
将noEmit改为false,指定输出目录,并调整module为commonjs以适配Node.js运行时:
{ "compilerOptions": { "target": "es2020", "strict": true, "preserveConstEnums": true, "noEmit": false, // 允许生成JS文件 "outDir": "./dist", // 指定编译产物输出目录 "sourceMap": false, "module":"commonjs", // 切换为commonjs,适配Node.js运行时 "moduleResolution":"node", "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, }, "exclude": ["node_modules"] }
步骤2:更新package.json
修改main字段指向编译后的入口文件,同时完善编译脚本:
{ "name": "hello_world", "version": "0.3.0", "description": "", "main": "dist/index.js", // 指向编译后的JS入口 "scripts": { "compile": "tsc", "build": "tsc && cp package.json dist/" // 编译后复制package.json到产物目录 }, "dependencies": { "esbuild": "^0.14.14" }, "devDependencies": { "@types/aws-lambda": "^8.10.92", "@types/node": "^18.11.4", "ts-node": "^10.9.1", "typescript": "^4.8.4" } }
步骤3:调整template.yaml的部署配置
将CodeUri改为编译后的产物目录:
AWSTemplateFormatVersion: '2010-09-09' Transform: 'AWS::Serverless-2016-10-31' Description: An AWS Serverless Specification template describing your function. Resources: generateblogpostv1: Type: 'AWS::Serverless::Function' Properties: Handler: index.handler Runtime: nodejs18.x CodeUri: ./dist/ # 指向编译后的产物目录 Description: '' MemorySize: 128 Timeout: 900 Role: >- arn:aws:iam::921222634505:role/service-role/... RuntimeManagementConfig: UpdateRuntimeOn: Auto
步骤4:编译并重新部署
- 执行编译命令生成产物:
npm run build
- 通过AWS Toolkit重新部署Lambda函数。
可选优化:用SAM自动编译
在template.yaml中添加Metadata配置,让SAM部署时自动用esbuild编译TypeScript,无需手动执行编译命令:
Resources: generateblogpostv1: Type: 'AWS::Serverless::Function' Metadata: BuildMethod: esbuild BuildProperties: Minify: true Target: es2020 Sourcemap: false EntryPoints: - index.ts Properties: Handler: index.handler Runtime: nodejs18.x CodeUri: . Description: '' MemorySize: 128 Timeout: 900 Role: >- arn:aws:iam::921222634505:role/service-role/... RuntimeManagementConfig: UpdateRuntimeOn: Auto
内容的提问来源于stack exchange,提问作者laprof

