简体   繁体   English

如何在 VS Code 中调试本地 AWS Lambda function 与 API 网关编写在 Z558B544CF685F39D8B67E4 中?

[英]How to debug in VS Code a local AWS Lambda function with API Gateway written in TypeScript?

We are about to start working with Lambda functions.我们即将开始使用 Lambda 函数。
We have that technology constraint that we have to use TypeScript.我们有必须使用 TypeScript 的技术限制。
I want to be able to debug my ts file in VS Code when the related endpoint is called from Postman.当从 Postman 调用相关端点时,我希望能够在 VS Code 中调试我的 ts 文件。

So, we have the following development environment:所以,我们有如下的开发环境:

  • Windows 10 Windows 10
  • Docker for Windows (with Hyper-V not with WSL 2) Docker 用于 Windows(使用 Hyper-V,不使用 WSL 2)
  • TypeScript 4.1 TypeScript 4.1
  • Node 12.17节点 12.17
  • SAM CLI 1.13.2 SAM CLI 1.13.2

I've used sam init with the Hello World template to generate the initial folder structure.我使用sam init和 Hello World 模板来生成初始文件夹结构。
I've enhanced it (mostly based on this article ) to work with TypeScript.我已经对其进行了增强(主要基于这篇文章)以使用 TypeScript。

Folder structure文件夹结构

.
├── template.yaml
├── .aws-sam
├── .vscode
|   └── launch.json
├── events
├── hello-world
|   ├── dist
|       ├── app.js
|       └── app.js.map
|   ├── src  
|       └── app.ts
|   ├── package.json
|   └── tsconfig.json

template.yaml

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  LambdaWithApiGateWayDebug

  Sample SAM Template for LambdaWithApiGateWayDebug

Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function 
    Properties:
      CodeUri: hello-world/dist
      Handler: app.lambdaHandler
      Runtime: nodejs12.x
      Events:
        HelloWorld:
          Type: Api
          Properties:
            Path: /hello
            Method: get

tsconfig.json

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "sourceMap": true,
    "outDir": "./dist",
    "strict": true,
    "noImplicitAny": true,
    "esModuleInterop": true,
    "sourceRoot": "./src",
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "**/*.spec.ts"]
}

package.json

{
  "name": "hello_world",
  "version": "1.0.0",
  "description": "hello world sample for NodeJS",
  "main": "app.js",
  "repository": "https://github.com/awslabs/aws-sam-cli/tree/develop/samcli/local/init/templates/cookiecutter-aws-sam-hello-nodejs",
  "scripts": {
    "compile": "tsc",
    "start": "sam local start-api -t ../template.yaml -p 5000 -d 5678"
  },
  "dependencies": {
    "@types/aws-lambda": "^8.10.64",
    "@types/node": "^14.14.10",
    "aws-sdk": "^2.805.0",
    "source-map-support": "^0.5.19",
    "typescript": "^4.1.2"
  }
}

app.ts

import { APIGatewayProxyEvent, APIGatewayProxyResult } from "aws-lambda";

export const lambdaHandler = async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => {
    const queries = JSON.stringify(event.queryStringParameters);
    return {
      statusCode: 200,
      body: `Queries: ${queries}`
    }
}

app.js

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.lambdaHandler = void 0;
const lambdaHandler = async (event) => {
    const queries = JSON.stringify(event.queryStringParameters);
    return {
        statusCode: 200,
        body: `Queries: ${queries}`
    };
};
exports.lambdaHandler = lambdaHandler;
//# sourceMappingURL=app.js.map

app.js.map

{"version":3,"file":"app.js","sourceRoot":"./src/","sources":["app.ts"],"names":[],"mappings":";;;AAEO,MAAM,aAAa,GAAG,KAAK,EAAE,KAA2B,EAAkC,EAAE;IAC/F,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;IAC5D,OAAO;QACL,UAAU,EAAE,GAAG;QACf,IAAI,EAAE,YAAY,OAAO,EAAE;KAC5B,CAAA;AACL,CAAC,CAAA;AANY,QAAA,aAAa,iBAMzB"}

launch.json

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "node",
            "request": "attach",
            "name": "attach Program",
            "port": 5678,
            "address": "localhost",
            "localRoot": "${workspaceFolder}/hello-world/dist",
            "remoteRoot": "/var/task",
            "protocol": "inspector",
            "sourceMaps": true,
            "smartStep": true,
            "outFiles": ["${workspaceFolder}/hello-world/dist"]
        }
    ]
}

As you can see:如你看到的:

  • My lambda function is defined in the hello-world/src/app.ts我的 lambda function 定义在hello-world/src/app.ts
  • It is complied with commonJs and ES2020 target to hello-world/dist/app.js with sourcemap它符合 commonJs 和 ES2020 目标到hello-world/dist/app.js和 sourcemap
  • The template exposes that handler which in located under the hello-world/dist via the localhost:5000/hello endpoint该模板通过localhost:5000/hello端点公开位于hello-world/dist下的处理程序
  • The debugger is listening on the port 5678调试器正在监听端口 5678

So, when I call npm run start then it prints the following output:因此,当我调用npm run start ,它会打印以下 output:

> hello_world@1.0.0 start C:\temp\AWS\LambdaWithApiGateWayDebug\hello-world
> sam local start-api -t ../template.yaml -p 5000 -d 5678

Mounting HelloWorldFunction at http://127.0.0.1:5000/hello [GET]
You can now browse to the above endpoints to invoke your functions. You do not need to restart/reload SAM CLI while working on your functions, changes will be reflected instantly/automatically. You only need to restart SAM CLI if you update your AWS SAM template
2020-12-08 11:40:48  * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

When I make a request against the endpoint via Postman then the console is extended with the following text:当我通过 Postman 向端点发出请求时,控制台将扩展为以下文本:

Mounting C:\temp\AWS\LambdaWithApiGateWayDebug\hello-world\dist as /var/task:ro,delegated inside runtime container
START RequestId: 04d884cf-fa96-4d58-b41c-e4196e12de13 Version: $LATEST
Debugger listening on ws://0.0.0.0:5678/d6702717-f291-42cd-8056-22b9f029f4dd
For help, see: https://nodejs.org/en/docs/inspector

When I attach my VS Code to the node process then I can only debug the app.js and not the app.ts .当我将 VS Code 附加到节点进程时,我只能调试app.js而不能调试app.ts
End of the console log:控制台日志结束:

Debugger attached.
END RequestId: 04d884cf-fa96-4d58-b41c-e4196e12de13
REPORT RequestId: 04d884cf-fa96-4d58-b41c-e4196e12de13  Init Duration: 0.12 ms  Duration: 7064.19 ms    Billed Duration: 7100 ms        Memory Size: 128 MB     Max Memory Used: 128 MB
No Content-Type given. Defaulting to 'application/json'.
2020-12-08 11:40:58 127.0.0.1 - - [08/Dec/2020 11:40:58] "GET /hello HTTP/1.1" 200 -

Question问题

What should I change to be able to debug my app.ts instead of app.js ?我应该改变什么才能调试我的app.ts而不是app.js

I wrote a medium article explaining how to create, invoke and debug a TypeScript lambda function.我写了一篇中篇文章,解释如何创建、调用和调试 TypeScript lambda function。 Please for more details check the following link .请查看以下链接了解更多详情。

Requirements要求

1- Create a nodejs12x; 1-创建一个nodejs12x;

  1. Create a nodejs12x lambda;创建一个nodejs12x lambda;

  2. Install TypeScript: npm i -g typescript安装 TypeScript: npm i -g typescript

  3. Initialize typescript: tsc --init (It will create the tsconfig.json file)初始化 typescript: tsc --init (它将创建 tsconfig.json 文件)

  4. Replace the created tsconfig.json file with the following code:将创建的 tsconfig.json 文件替换为以下代码:

     { "compilerOptions": { "module": "CommonJS", "target": "ES2017", "noImplicitAny": true, "preserveConstEnums": true, "outDir": "./built", "sourceMap": true }, "include": ["handler/**/*"], "exclude": ["node_modules", "**/*.spec.ts"] }
  5. Delete app.js file;删除 app.js 文件;

  6. Create your lambda in TypeScript code inside of handler folder (you need o create it):在处理程序文件夹内的 TypeScript 代码中创建 lambda (您需要创建它):

     import { APIGatewayProxyEvent, APIGatewayProxyResult } from "aws-lambda"; export const lambdaHandler = async ( event: APIGatewayProxyEvent ): Promise<APIGatewayProxyResult> => { const queries = JSON.stringify(event.queryStringParameters); return { statusCode: 200, body: `Queries: ${queries}` } }
  7. Adapt the template.yaml.适配模板.yaml。 Change the CodeUri path of your lambda: CodeUri: hello-world/built更改 lambda 的 CodeUri 路径: CodeUri: hello-world/built

  8. Install the needed node packages: npm install typescript @types/aws-lambda @types/node -save-dev安装所需的节点包: npm install typescript @types/aws-lambda @types/node -save-dev

  9. Package json: Package json:

     { "name": "typescript_lambda", "version": "1.0.0", "description": "hello world sample for TypeScript", "main": "app.js", "repository": "https://github.com/jafreitas90/AWS", "author": "Jorge Freitas", "license": "JorgeFreitas Ltd:)", "dependencies": { }, "scripts": { "compile": "tsc" }, "devDependencies": { "@types/aws-lambda": "^8.10.71", "@types/node": "^14.14.22", "aws-sdk": "^2.815.0", "typescript": "^4.1.3" } }
  10. npm install npm安装

  11. npm run compile npm 运行编译

  12. Set a breakpoint in your lambda function (TypeScript code).在 lambda function(TypeScript 代码)中设置断点。 On the left panel select Debug and then Start debugging (green button on top).在左侧面板上 select 调试然后开始调试(顶部的绿色按钮)。 And that's it:)就是这样:)

  13. Project structure项目结构

在此处输入图像描述

Please find more details in my tutorial. 请在我的教程中找到更多详细信息。

source code 源代码

As it turned out I have made two tiny mistakes:事实证明,我犯了两个小错误:

sourceRoot源根

I've set sourceRoot inside tsconfig.json which is unnecessary in this case.我在tsconfig.json中设置sourceRoot ,在这种情况下这是不必要的。 include is enough: include就足够了:

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "sourceMap": true,
    "outDir": "./dist",
    "strict": true,
    "noImplicitAny": true,
    "esModuleInterop": true,
    // "sourceRoot": "./src",
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "**/*.spec.ts"]
}

BreakPoints断点

I've set two breakpoints: one inside app.js and another inside app.ts .我设置了两个断点:一个在app.js中,另一个在app.ts中。
As it turned out if app.js does have a breakpoint then the other one will not be trigger.事实证明,如果app.js确实有断点,则不会触发另一个断点。

调试js

So after I've removed the breakpoint from app.js then the debugger stopped inside the app.ts .因此,在我从app.js中删除断点后,调试器在app.ts内停止。

调试ts

Your Lambda's runtime is JavaScript, yet you write your code in TypeScript.您的 Lambda 运行时是 JavaScript,但您在 TypeScript 中编写代码。 When you use TypeScript, behind the scenes the compiler is converting your code to JavaScript which is the debuggable code.当您使用 TypeScript 时,编译器会在后台将您的代码转换为可调试代码 JavaScript。

In another words, you code your lambda in TS, complier then converts it to JS which at the end is the code that gets executed and can be debugged.换句话说,您在 TS 中编写 lambda 代码,编译器然后将其转换为 JS,最后是可以执行并可以调试的代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM