aws-powertools / powertools-lambda-typescript

Powertools is a developer toolkit to implement Serverless best practices and increase developer velocity.
https://docs.powertools.aws.dev/lambda/typescript/latest/
MIT No Attribution
1.57k stars 138 forks source link

Bug: lib not working for node12 if not bundled with tools like esbuild #899

Closed flochaz closed 2 years ago

flochaz commented 2 years ago

Bug description

Node12 with standard bundling of lambda does not work and throw Runtime.UserCodeSyntaxError: SyntaxError: Unexpected token '.'

Expected Behavior

Installing and bundling my lambda with powertools "normally" should work on node12 runtime.

Current Behavior

Given a function bundled as a zip including @aws-lambda-powertools/* modules in node_modules and importing the lib in the index.js such as:

const { Logger } = require('@aws-lambda-powertools/logger');
const { Metrics } = require('@aws-lambda-powertools/metrics');
const { Tracer } = require('@aws-lambda-powertools/tracer');

When triggered, it will throw the following exception if runtime is Node12.x:

{"errorType":"Runtime.UserCodeSyntaxError","errorMessage":"SyntaxError: Unexpected token '.'","stack":["Runtime.UserCodeSyntaxError: SyntaxError: Unexpected token '.'"," at _loadUserApp (/var/runtime/UserFunction.js:98:13)"," at Object.module.exports.load (/var/runtime/UserFunction.js:140:17)"," at Object.<anonymous> (/var/runtime/index.js:43:30)"," at Module._compile (internal/modules/cjs/loader.js:999:30)"," at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)"," at Module.load (internal/modules/cjs/loader.js:863:32)"," at Function.Module._load (internal/modules/cjs/loader.js:708:14)"," at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:60:12)"," at internal/main/run_main_module.js:17:47"]}

Possible Solution

  1. Update the doc to mention that
    1. lambda should be bundled with tools like esbuild
    2. lambda layer won't work for node12
  2. Fix the bundling of the lib to work with node12

Steps to Reproduce

Check https://github.com/awslabs/aws-lambda-powertools-typescript/runs/6521588868?check_suite_focus=true

or

An easyway to reproduce is to test the lambda layer

git clone https://github.com/awslabs/aws-lambda-powertools-typescript.git
cd layer-publisher
npm ci
RUNTIME=node12.x npm run test:e2e

You will get the following failure

    console.log
      [{"logs":["START RequestId: 334e421c-54ec-4fbe-b88b-f6db69398589 Version: $LATEST","2022-05-20T09:51:44.303Z\tundefined\tERROR\tUncaught Exception \t{\"errorType\":\"Runtime.UserCodeSyntaxError\",\"errorMessage\":\"SyntaxError: Unexpected token '.'\",\"stack\":[\"Runtime.UserCodeSyntaxError: SyntaxError: Unexpected token '.'\",\"    at _loadUserApp (/var/runtime/UserFunction.js:98:13)\",\"    at Object.module.exports.load (/var/runtime/UserFunction.js:140:17)\",\"    at Object.<anonymous> (/var/runtime/index.js:43:30)\",\"    at Module._compile (internal/modules/cjs/loader.js:999:30)\",\"    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)\",\"    at Module.load (internal/modules/cjs/loader.js:863:32)\",\"    at Function.Module._load (internal/modules/cjs/loader.js:708:14)\",\"    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:60:12)\",\"    at internal/main/run_main_module.js:17:47\"]}","2022-05-20T09:51:45.903Z\tundefined\tERROR\tUncaught Exception \t{\"errorType\":\"Runtime.UserCodeSyntaxError\",\"errorMessage\":\"SyntaxError: Unexpected token '.'\",\"stack\":[\"Runtime.UserCodeSyntaxError: SyntaxError: Unexpected token '.'\",\"    at _loadUserApp (/var/runtime/UserFunction.js:98:13)\",\"    at Object.module.exports.load (/var/runtime/UserFunction.js:140:17)\",\"    at Object.<anonymous> (/var/runtime/index.js:43:30)\",\"    at Module._compile (internal/modules/cjs/loader.js:999:30)\",\"    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)\",\"    at Module.load (internal/modules/cjs/loader.js:863:32)\",\"    at Function.Module._load (internal/modules/cjs/loader.js:708:14)\",\"    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:60:12)\",\"    at internal/main/run_main_module.js:17:47\"]}","END RequestId: 334e421c-54ec-4fbe-b88b-f6db69398589","REPORT RequestId: 334e421c-54ec-4fbe-b88b-f6db69398589\tDuration: 1771.15 ms\tBilled Duration: 1772 ms\tMemory Size: 128 MB\tMax Memory Used: 13 MB\t","Unknown application error occurred","Runtime.UserCodeSyntaxError"]}]

      at Object.<anonymous> (tests/e2e/happy-case.test.ts:74:13)
          at runMicrotasks (<anonymous>)

  ● Without layer package is usable with nodejs12.x runtime lambda

Environment

Related issues, RFCs

detected while testing layer: #884

dreamorosi commented 2 years ago

In our current tsconfig.json we are using ES2020 as target (example here) but according to the TS documentation (link) the mapping for node12.x should be ES2019:

{
  "compilerOptions": {
    "lib": ["ES2019"],
    "module": "commonjs",
    "target": "ES2019"
  }
}

Maybe this is the issue?

But then I don't fully understand why the integration tests we are running don't break.

saragerion commented 2 years ago

Example of compiler options for Node 12

ijemmy commented 2 years ago

Note on this. Target2019 doesn't support ?. argument. So code like this:

//in target 2020
subsegment?.close();

will be:

//in target 2019
subsegment === null || subsegment === void 0 ? void 0 : subsegment.close();

This is fine functionally. But it reduces our unit test branch coverage and breaks our commit/push hooks.

The options to fix this are:

  1. use as to cast to a type that is not optional
  2. use ! to tell typescript that there is always a value (but we'll need to ignore with // eslint-disable-next-line @typescript-eslint/no-non-null-assertion)
  3. Add test case where it makes sense.

?. is used in many places. I'll be using different options based on situation.

Ref: https://linguinecode.com/post/how-to-solve-typescript-possibly-undefined-value

github-actions[bot] commented 2 years ago

⚠️ COMMENT VISIBILITY WARNING ⚠️

Comments on closed issues are hard for our team to see. If you need more assistance, please either tag a team member or open a new issue that references this one. If you wish to keep having a conversation with other community members under this issue feel free to do so.