aws / aws-cdk

The AWS Cloud Development Kit is a framework for defining cloud infrastructure in code
https://aws.amazon.com/cdk
Apache License 2.0
11.65k stars 3.91k forks source link

aws-lambda-nodejs: Precompilation excludes path aliases in tsc command #20666

Open villecoder opened 2 years ago

villecoder commented 2 years ago

Describe the bug

Given the following compiler options:

{
    "lib": ["ESNext"],
    "moduleResolution": "node",
    "module": "commonjs",
    "target": "ES2020",
    "baseUrl": ".",
    "paths": {
      "@core/*": ["./backend/core/*"],
      "@framework/*": ["./backend/framework/*"],
      "@application/*": ["./backend/application/*"],
      "@graphql/*": ["./backend/graphql/*"],
      "@graphql/types": ["./backend/graphql/generated/types"],
      "@tests/*": ["./backend/tests/*"]
    },
    "allowSyntheticDefaultImports": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "outDir": "dist",
    "rootDir": "./",
    "strict": true,
    "noImplicitAny": false,
    "strictNullChecks": false,
    "noUnusedLocals": false,
    "noUnusedParameters": false,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "removeComments": true,
    "sourceMap": true,
    "strictPropertyInitialization": false
  }

The resultant compiler options given to the tsc runner excludes the paths object. This results in compiler errors. I've tracked this down to getTsconfigCompilerOptions(). The code handles only objects that are arrays.

Expected Behavior

Compiler options string should be (newlines added for readability)

--lib ESNext
--moduleResolution node 
--module commonjs 
--target ES2020 
--baseUrl . 
--paths {
      "@core/*": ["./backend/core/*"],
      "@framework/*": ["./backend/framework/*"],
      "@application/*": ["./backend/application/*"],
      "@graphql/*": ["./backend/graphql/*"],
      "@graphql/types": ["./backend/graphql/generated/types"],
      "@tests/*": ["./backend/tests/*"]
} 
--allowSyntheticDefaultImports
--experimentalDecorators
--emitDecoratorMetadata
--esModuleInterop
--skipLibCheck
--outDir ./ 
--rootDir ./ 
--strict
--noImplicitReturns
--noFallthroughCasesInSwitch
--removeComments
--sourceMap

Current Behavior

Compiler options are (newlines added for readability)

--lib ESNext
--moduleResolution node 
--module commonjs 
--target ES2020 
--baseUrl . 
--allowSyntheticDefaultImports
--experimentalDecorators
--emitDecoratorMetadata
--esModuleInterop
--skipLibCheck
--outDir ./ 
--rootDir ./ 
--strict
--noImplicitReturns
--noFallthroughCasesInSwitch
--removeComments
--sourceMap

Which results in Error: Failed to bundle asset...

Reproduction Steps

tsconfig.json

{
  "compilerOptions": {
    "lib": ["ESNext"],
    "moduleResolution": "node",
    "baseUrl": "."
    "paths": {
      "@utils/*": "./utils/*"
    }
  }
}

utils/calculator.ts

export function add(a: number, b: number): number {
  return a + b;
}

index.ts

import { add } from '@utils/calculator';
console.log(add(1,2));

Possible Solution

In getTsconfigCompilerOptions(), add an else condition to emit the json object as part of the command.

Additional Information/Context

No response

CDK CLI Version

2.27.0 (build 8e89048)

Framework Version

No response

Node.js Version

v18.2.0

OS

Ubuntu 22.04 LTS

Language

Typescript

Language Version

Typescript (4.7.2)

Other information

No response

villecoder commented 2 years ago

Well, I found out that you can't specify paths on the command line. So perhaps a better solution would be to use the custom tsconfig as a --project parameter instead of deconstructing the tsconfig down to command line options.

villecoder commented 2 years ago

Further research shows that you cannot specify both a --project parameter and a source file. This is a limitation of Typescript. See https://github.com/microsoft/TypeScript/issues/27379. Is the solution to not use custom paths in this case?

villecoder commented 2 years ago

Sorry to chaingun the replies here, but the more research I do, the more workarounds I find.

I found a related workaround on StackOverflow. Perhaps the solution is to create a temporary tsconfig that extends the project tsconfig and only includes the target file?

peterwoodworth commented 2 years ago

Thanks for submitting this other bug report! We accept contributions, check out our contributing guide if you're interested - there's a low chance the team will be able to address this soon but we'd be happy to review a PR 🙂

villecoder commented 2 years ago

I do have a question about the esbuild implementation. Why does it use the command line opposed to using the esbuild typescript API?

zbarbuto commented 2 years ago

For anyone who finds this issue via Google, you can get tsconfig.paths working in CDK (as well as emitDecoratorMetadata) by using a custom esbuild setup and esbuild-plugin-tsc.

Since CDK does not support esbuild plugins yet - using the cdk-esbuild construct TypeScriptCode allows you to add the plugin and build the code before passing it to a lambda.Function construct.

cdk-esbuild has an example showing plugin use.

madeline-k commented 1 year ago

Related: https://github.com/aws/aws-cdk/issues/20650