You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将TypeScript类转为Lambda Layer时遇exports未定义错误求助

问题:将TypeScript类打包为Lambda Layer后运行报错

我尝试把下面这个AthenaHelper TypeScript类做成Node.js的Lambda Layer:

import { Athena } from "aws-sdk";

export class AthenaHelper {
  private athena = new Athena();

  public queryAthena = async (
    databaseParams: Athena.StartQueryExecutionInput
  ) => {
    const { QueryExecutionId: queryExecutionId } =
      (await this.athena.startQueryExecution(databaseParams).promise()) ?? {};

    if (!queryExecutionId) {
      throw new Error("No query execution ID");
    }

    const params = {
      QueryExecutionId: queryExecutionId,
    };

    // 等待查询完成
    await this.waitForQueryCompletion(queryExecutionId);

    // 以JSON格式获取Athena查询结果
    const results = await this.getQueryResultsInJsonFormat(params);

    return results;
  };

  private waitForQueryCompletion = async (
    queryExecutionId: string | undefined
  ) => {
    try {
      if (!queryExecutionId) {
        throw new Error("No query execution ID");
      }
      let state: string | null | undefined = null;
      while (
        state !== "SUCCEEDED" &&
        state !== "FAILED" &&
        state !== "CANCELLED"
      ) {
        await new Promise((res) => setTimeout(res, 1000));

        const { QueryExecution } = await this.athena
          .getQueryExecution({
            QueryExecutionId: queryExecutionId,
          })
          .promise();

        state = QueryExecution?.Status?.State;
      }
      return state;
    } catch (error) {
      throw error;
    }
  };

  private getQueryResultsInJsonFormat = async (
    params: Athena.GetQueryResultsInput
  ): Promise<Record<string, string | null>[]> => {
    const result: Athena.GetQueryResultsOutput = await this.athena
      .getQueryResults(params)
      .promise();

    const columnInfo: Athena.ColumnInfo[] =
      result.ResultSet?.ResultSetMetadata?.ColumnInfo || [];

    const rows =
      // 第一行是列名,这里跳过
      result.ResultSet?.Rows?.slice(1).map((row) => {
        const rowData: Record<string, string | null> = {};
        row.Data?.forEach((data, index) => {
          rowData[columnInfo[index].Name] = data?.VarCharValue || null;
        });
        return rowData;
      }) || [];
    return rows;
  };
  public helloWorld() {
    console.log("Hello World");
  }
}

用tsc编译成原生JavaScript后上传到Lambda Layer,然后运行下面的Lambda函数:

exports.handler = async (event, context) => {
  try {
  
  const AthenaHelper = require('/opt/nodejs/AthenaHelper');
  
  const athenaHelper = new AthenaHelper()
  
  athenaHelper.helloWorld()
    return {
        statusCode: 200,
        body: 'Hello, World!'
    };
  } catch (error) {
    console.log('error', JSON.stringify(error))
  }
};

执行时出现错误:

{
  "errorType": "ReferenceError",
  "errorMessage": "exports is not defined in ES module scope",
}

我的TS Config配置如下:

{   "compilerOptions": {     "lib": ["es2018", "dom"]   } } 

求解决建议,有没有人试过把自定义TypeScript类导出为Lambda Layer?


解决建议

这个错误的核心是编译后的JS文件是ES模块格式,但Lambda里用CommonJS的require()去加载,导致模块系统冲突。下面是具体的修复步骤:

1. 修改TypeScript配置,编译为CommonJS模块

更新你的tsconfig.json,明确指定模块格式为CommonJS,同时补充必要的编译选项:

{
  "compilerOptions": {
    "lib": ["es2018"],
    "module": "CommonJS",
    "target": "ES2018",
    "outDir": "./dist",
    "esModuleInterop": true,
    "skipLibCheck": true,
    "strict": false
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}
  • module: "CommonJS":强制编译成Lambda兼容的CommonJS格式,避免生成ES模块的export语法
  • outDir:指定编译后的文件输出目录,方便打包上传
  • esModuleInterop:解决CommonJS和ES模块之间的兼容性问题

2. 调整Lambda函数的导入方式

TypeScript编译CommonJS后,类会挂在exports对象上,需要修改导入语句:

// 解构导入类
const { AthenaHelper } = require('/opt/nodejs/AthenaHelper');
// 或者如果编译后是默认导出,用下面的写法:
// const AthenaHelper = require('/opt/nodejs/AthenaHelper').default;

3. 正确打包Lambda Layer

  • 编译TypeScript:执行tsc命令,确保编译后的文件输出到dist目录
  • 打包Layer:将dist目录下的文件放到nodejs文件夹中(Lambda Layer的Node.js文件必须放在nodejs目录下),然后压缩成zip包上传
    示例目录结构:
    lambda-layer.zip
    └── nodejs
        └── AthenaHelper.js
    

4. 备选方案:改用ES模块格式

如果想保持ES模块,需要:

  • 在Lambda函数的根目录添加package.json,声明"type": "module"
  • 修改Lambda代码为ES模块的import语法:
    export const handler = async (event, context) => {
      try {
        import AthenaHelper from '/opt/nodejs/AthenaHelper';
        const athenaHelper = new AthenaHelper();
        athenaHelper.helloWorld();
        return { statusCode: 200, body: 'Hello, World!' };
      } catch (error) {
        console.log('error', JSON.stringify(error));
      }
    };
    
    同时确保TypeScript编译时module设置为ESNext或ES2020,并且编译后的JS文件使用export default语法。

内容的提问来源于stack exchange,提问作者Coder Noob

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 10:27:42