【问题标题】:TypeScript debugging of AWS SAM serverless apps in VS Code在 VS Code 中对 AWS SAM 无服务器应用程序进行 TypeScript 调试
【发布时间】:2021-10-19 21:47:07
【问题描述】:

我在 Visual Studio Code 中使用 AWS SAM 构建了一个无服务器函数。我使用的运行时是 nodejs12.x,但我在 TypeScript 中编写所有内容,然后将其编译为 JS 到 /dist 目录中。这是我将所有 CloudFormation 模板指向的目录,以便找到处理程序。比如右边是TS,左边是我编译的JS。

在侧边栏中,您可以看到运行 tsc 后放置我的 JS 文件的 /dist 目录,而再往下一点是我的模板和 TypeScript 源代码。

我的模板如下所示:

  LibraryAddMangaFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: dist/src/handlers.LibraryAddMangaHandler
      FunctionName: Foobar
      Runtime: nodejs12.x
      MemorySize: 256
      Timeout: 300

我关注Amazon's documentation 在 VS Code 中执行本地调试,并让它为 JS 文件工作。我可以毫无问题地设置断点并逐步执行编译的 JS 代码。

我想知道是否可以在单步执行 TypeScript 代码时进行调试,类似于我在 Chrome 中使用 Angular/React 中的客户端应用程序执行的操作。我知道框架处理 JS 到 TS 的映射作为构建过程的一部分,以支持 Chrome 调试工具的需求。如果没有 SAM/AWS 的支持,我不确定我想做的事情是否可行。

另外,当我的 HTTP 请求完成时,调试会话结束,而不是继续运行并监听下一个请求 - 类似于 sam local start-api。有没有办法配置调试运行器以保持应用程序运行?我看到有人推荐使用Thundra,但这需要将 Lambda 部署到 AWS 中,我真的很喜欢本地调试、调整、调试的快速循环。我真的不希望每 15 秒执行一次 sam deploy 并等待堆栈部署。

谢谢!

【问题讨论】:

    标签: typescript aws-lambda vscode-debugger aws-sam


    【解决方案1】:

    是的,可以做到:你需要的是源地图

    在我的例子中,我将我的 lambdas 编译并捆绑到 dist 文件夹下的 1 个 index.js 文件中。我使用 webpack 作为捆绑器将其与单个 .map 文件一起提供。

    const path = require('path');
    const glob = require('glob');
    const webpack = require('webpack');
    const CreateFileWebpack = require('create-file-webpack');
    const nodeExternals = require('webpack-node-externals');
    
    // Credits: https://hackernoon.com/webpack-creating-dynamically-named-outputs-for-wildcarded-entry-files-9241f596b065
    const entryArray = glob.sync('./src/lambda/**/handler.ts');
    
    const entryObject = entryArray.reduce((acc, item) => {
      let name = path.dirname(item.replace('./src/lambda', ''));
      // conforms with Webpack entry API
      // Example: { ingest: './src/ingest/index.ts' }
      acc[name] = item;
      return acc;
    }, {});
    
    /** @type {import('webpack').Configuration} */
    module.exports = {
      cache: {
        type: 'memory',
      },
      entry: entryObject,
      devtool: false,
      target: 'node',
      // externals: [nodeExternals()],  // use if dependencies should not be bundled (like when using layers)
      module: {
        rules: [
          {
            test: /\.tsx?$/,
            loader: 'ts-loader',
            exclude: /node_modules/,
            options: {
              transpileOnly: true,
            },
          },
        ],
      },
      resolve: {
        extensions: ['.tsx', '.ts', '.js'],
      },
      plugins: [
        new webpack.IgnorePlugin({ resourceRegExp: /^pg-native$/ }),
        new webpack.IgnorePlugin({ resourceRegExp: /^hiredis$/ }),
        ...Object.keys(entryObject).map(lambda => {
          return new CreateFileWebpack({
            path: path.resolve(__dirname, 'build'),
            fileName: `${lambda}/package.json`,
            content: JSON.stringify({
              name: 'dummy_dependencies',
              dependencies: {},
              version: '1.0.0',
            }),
          });
        }),
        new webpack.SourceMapDevToolPlugin({
          columns: false,
          module: true,
          filename: '[file].map',
        }),
      ],
      // Output directive will generate build/<function-name>/index.js
      output: {
        filename: '[name]/index.js',
        path: path.resolve(__dirname, 'build'),
        devtoolModuleFilenameTemplate: '[absolute-resource-path]',
        // Credit to Richard Buggy!!
        libraryTarget: 'commonjs2',
      },
    };
    
    

    我不知道在你的情况下有多个编译文件会怎样,但我认为这是与 webpack 或任何其他“编译”工具类似的场景(我最近一直在研究 esbuild)。

    即使是激活源映射的普通 tsc 也应该足够了。

    完成后,您还应该使用正确的 .vscode 启动配置,以便 vs code 可以将容器的远程文件与本地文件进行映射,同时还可以通过 sourcemaps 连接其相应的 typescript 文件。

        {
          "name": "[Serverless] <lambda-name> attach",
          "type": "node",
          "request": "attach",
          "address": "localhost",
          "port": 5678,
          "localRoot": "${workspaceRoot}/.serverless/build/<lambda-folder>",
          "remoteRoot": "/var/task",
          "protocol": "inspector",
          "stopOnEntry": false,
          "outFiles": ["${workspaceRoot}/.serverless/build/<lambda-folder>"],
          "sourceMaps": true
        }
    

    有没有办法配置调试运行器以保持应用运行?

    如果我理解正确,您正在寻找的是在请求之间保持调试器连接,这样您就不必每次在本地调用 lambda 时都手动连接它。

    如果是这种情况,您可以通过使用 --shutdown--warm-containers LAZY 标志 (reference) 运行 sam local start-lambda 来实现:

    sam local start-lambda -d 5678 --host 0.0.0.0 --shutdown --debug --warm-containers LAZY
    

    这将创建一个类似于 AWS 在云上使用的 API,因此您可以使用 aws-sdkaws cli 访问它

    aws lambda invoke --function-name \"<sam-template-lambda-id>\" --payload <stringified-json-input> --endpoint-url \"http://127.0.0.1:3001\" lambda_invoke_output.log
    

    aws sam 将使容器保持温暖,直到 lambda 代码更改,并且调试器将在您触发的所有 INVOKE 事件中保持激活状态,有效地停止在您每次调用时设置的打字稿断点lambda

    TL;DR

    使用源地图,并在整个互联网上搜索如何将所有东西粘合在一起


    个人笔记:我第一次处理这个问题时,我在互联网上经历了漫长而痛苦的航行来完成它。

    生活不应该是这样的:')

    【讨论】:

    • 感谢您的信息 - 我已经能够创建 .map 文件,但我仍然在 VSCode 上苦苦挣扎。我可以让sam local start-api 使用调试端口运行,通过 Postman 调用 API 并在输入时观察 VSCode 中断(感到困惑,因为我在launch.json 中将其设置为 false)。当我按 F5 让 VSCode 继续执行时,SAM index.js 条目文件在尝试加载我的函数时会引发恐慌异常。如果我只是使用调试端口运行sam local start-api,则该函数将成功运行至完成。不知道为什么附加调试器会导致它崩溃。
    • 好吧 - 显然,在我所做的所有试验和错误中,我搞砸了一些事情。我撤消了所有配置更改,并开始从头开始尝试。我使用这个 repo 作为设置它的参考并让它现在可以工作github.com/jafreitas90/AWS/tree/master/Lambda/typescript/lambda 感谢您为我指明正确的方向!
    【解决方案2】:

    如果你想在没有 webpack 的情况下做到这一点,现在有一个更简单的方法。

    首先确保您正在制作源地图。 在您的 tsconfig.js 中(执行此操作的不同方法,我更喜欢内联源映射)

    {
      "compilerOptions": {
        ...,
        "inlineSourceMap": true,
        ...
      },
      ...
    }
    

    为 VSCode 安装 AWS Tookit 扩展。 现在,在您的 template.yaml 文件中,您将拥有一个生成调试配置的魔术按钮 =]

    【讨论】:

      猜你喜欢
      • 2019-09-23
      • 1970-01-01
      • 1970-01-01
      • 2018-01-08
      • 2016-11-01
      • 1970-01-01
      • 2022-12-17
      • 2021-06-03
      相关资源
      最近更新 更多