aws api rhok microservices

Debugging lambdas in VSCode

Solving a debugging issue with a lambda written using typescript

Shaun Wilde
a computer screen showing code

I've recently been doing some lambda development as part of my involvement with a hackathon known as Random Hack of Kindness. We ended up creating a small API using AWS-SAM-CLI and using typescript + webpack to build each lambda.

The nice thing is that it is easy to run the lambda locally, so you don't need to constantly deploy to your AWS environment to test it. It also means that there is an opportunity to debug the lambda locally should the need arise; there are even plenty of instructions to make this work but none of them worked for me. I suspected the typescript + webpack combination was somehow involved but how to investigate it and if possible find a possible solution. All the applicable samples seemed to be plain javascript + node setups and were configured something like this.


  "version": "0.2.0",
  "configurations": [
{
  "name": "Attach to SAM CLI",
  "type": "node",
  "request": "attach",
  "address": "localhost",
  "port": 5858,
  "localRoot": "${workspaceRoot}/src/<path-to-lambda-function>",
  "remoteRoot": "/var/task",
  "protocol": "inspector",
  "stopOnEntry": false,
  "sourceMaps": true
}
  ]
}

So I obviously tried the following


  "version": "0.2.0",
  "configurations": [
{
  "name": "Attach to SAM CLI",
  "type": "node",
  "request": "attach",
  "address": "localhost",
  "port": 5858,
  "localRoot": "${workspaceRoot}/dist/<path-to-lambda-function>",
  "remoteRoot": "/var/task",
  "protocol": "inspector",
  "stopOnEntry": false,
  "sourceMaps": true
}
  ]
}

It was always possible to attach the debugger but the breakpoints for them were never triggered. I even tried several of the source map options available in webpack before settling on dev-tool: source-map as the one most likely to work.

Could it be how the map files were being built? Inside the generated map files, there were references to webpack:///... andI had seen other debug tutorials using sourceMapPathOverrides in the launch.json to assist the debugger in mapping these paths to the local paths; again tried various options but nothing seemed to help. Whilst reviewing the webpack documentation, I saw that the webpack:///... path appeared to be generated by devtoolModuleFilenameTemplate and this could be overridden in the webpack config file, a common option being [absolute-resource-path]. This produced a map file that had the full pathname and as this only going to be for local development builds I was not concerned about exposing my local drive paths; I can see why we wouldn't want this for files being distributed on websites though.

Bingo - we can now debug. This is what I now have in my webpack.config.ts file.

const config: Configuration = {
 ...
 devtool: isProduction ? false : 'source-map',
 ...
 output: {
   ...
   devtoolModuleFilenameTemplate: '[absolute-resource-path]',
   ...
 }
}

However, I was still not satisfied because with the localRoot setting the way it is, we could only debug one lambda at a time and we were planning on having many lambdas as part of the application we were developing, if we wanted to debug another lambda then we would have to update the launch.json.  Changing the path to be something other than the lambda source location threw a message in the debug console that the app.map.js file couldn't be found; note: this message only showed if you happened to have the console active at the time. Would it be possible to use one of the inline source map options instead? After some trial and error, I lucked upon the following combination that allowed me to debug each lambda without having to update the launch.json file.

launch.json

{
  "version": "0.2.0",
  "configurations": [
{
  "name": "Attach to SAM CLI",
  "type": "node",
  "request": "attach",
  "address": "localhost",
  "port": 5858,
  "localRoot": "${workspaceRoot}/",
  "outFiles": [
    "${workspaceFolder}/dist/**/*.js"
  ],
  "remoteRoot": "/var/task",
  "protocol": "inspector",
  "stopOnEntry": false,
  "sourceMaps": true
}
  ]
}

webpack.config.ts

const config: Configuration = {
 ...
 devtool: isProduction ? false : 'eval-cheap-module-source-map',
 ...
 output: {
   ...
   devtoolModuleFilenameTemplate: '[absolute-resource-path]',
   ...
 }
}

I am still trying to determine which source map option is best and if it matters but at least we have a debug option available to us if we need it.

As always these entries are a reminder to my future self but if you have any feedback or tips they'll be appreciated.