cannot use imported stacks and constructs from libs/packages in nx monorepo
Closed this issue · 3 comments
There is an issue when importing stacks/constructs in an aws-cdk infra app created using @ago-dev/nx-aws-cdk-v2.
This was a surprise issue for me given that one of the key reasons to use an nx workspace is to be able to split up projects into different libs/packages and import them into project apps. This approach is recommended by nx's authors nrwl.io as well.
I am not sure however I wonder if this may be related to not using something like tsconfig-paths/register
or another solution (tsc-alias etc?) to resolve paths in the definition of nodeCommandWithRelativePath
in nx-aws-cdk-v2/packages/aws-cdk-v2/src/utils/executor.util.ts
.
If the issue is indeed related to paths, an unrelated project that might be of interest to reference is nx-builders by Web & Söhne that registers TS paths in its solution for supporting ts-node in the monorepo: https://github.com/tailoredmedia/backend-nx-skeleton/tree/master/packages/nx-builders#ts-node-dev.
Also of potential interest: aws/jsii#865
Replication:
- create a new nx node:lib or js:lib and add a stack or construct to it
- import the stack and/or construct in the aws-cdk infra app created using the generator from @ago-dev/nx-aws-cdk-v2 and rig it up
- try to deploy the stack
- observe the error "Cannot find module @myorg/my-library" where "@myorg/my-library" is the
importPath
of the package/library within the nx workspace
Example error output from trying to deploy:
OptionsParsedExecutorInterface {"_":["TestBucketStack"],"parseArgs":{"_":["TestBucketStack"]},"sourceRoot":"apps/infra/src","root":"apps/infra"}
nodeCommandWithRelativePath node /home/username/projects/my-nx-project/node_modules/aws-cdk/bin/cdk.js deploy
Executing command: node /home/username/projects/my-nx-project/node_modules/aws-cdk/bin/cdk.js deploy --_ TestBucketStack
Error: Cannot find module '@myorg/cdk-stacks'
Require stack:
- /home/username/projects/my-nx-project/apps/infra/src/main.ts
at Function.Module._resolveFilename (node:internal/modules/cjs/loader:995:15)
at Function.Module._resolveFilename.sharedData.moduleResolveFilenameHook.installedValue [as _resolveFilename] (/home/username/projects/my-nx-project/node_modules/.pnpm/@cspotcode+source-map-support@0.8.1/node_modules/@cspotcode/source-map-support/source-map-support.js:811:30)
at Function.Module._load (node:internal/modules/cjs/loader:841:27)
at Module.require (node:internal/modules/cjs/loader:1061:19)
at require (node:internal/modules/cjs/helpers:103:18)
at Object.<anonymous> (/home/username/projects/my-nx-project/apps/infra/src/main.ts:2:1)
at Module._compile (node:internal/modules/cjs/loader:1159:14)
at Module.m._compile (/home/username/projects/my-nx-project/node_modules/.pnpm/ts-node@10.9.1_72wjdbglblrsksmmmhzpvueijy/node_modules/ts-node/src/index.ts:1618:23)
at Module._extensions..js (node:internal/modules/cjs/loader:1213:10)
at Object.require.extensions.<computed> [as .ts] (/home/username/projects/my-nx-project/node_modules/.pnpm/ts-node@10.9.1_72wjdbglblrsksmmmhzpvueijy/node_modules/ts-node/src/index.ts:1621:12) {
code: 'MODULE_NOT_FOUND',
requireStack: [ '/home/username/projects/my-nx-project/apps/infra/src/main.ts' ]
}
Versions:
- running current versions of everything including nx 15.8.6 (latest) + @ago-dev/nx-aws-cdk-v2 1.3.1
If there's a way to successfully import constants / functions / constructs + stacks from other libraries within the nx workspace, please let me know! Thanks for your work on this package!
For anyone stuck on this, I believe I have found a workaround solution that works for now.
Running the following command from the root path of an nx workspace will successfully run cdk synth
and any stacks/constructs/functions/etc imported in the code from other libs within the monorepo will work.
Ensure you have tsconfig-paths
installed as at least a dev dependency in your project's package.json
(e.g. via npm install tsconfig-paths --save-dev
or pnpm add -D tsconfig-paths
).
Be sure to edit all the paths in the following example and change the command (from "synth" to "deploy", "destroy", etc.) to suit your particular needs:
node --require ts-node/register node_modules/aws-cdk/bin/cdk.js -a "npx ts-node --require tsconfig-paths/register --project apps/infra/tsconfig.app.json apps/infra/src/main.ts" synth DemoBucketStack
If you use pnpm like me and want to go full hog with it, substitute npx
with pnpm dlx
:
node --require ts-node/register node_modules/aws-cdk/bin/cdk.js -a "pnpm dlx ts-node --require tsconfig-paths/register --project apps/infra/tsconfig.app.json apps/infra/src/main.ts" synth DemoBucketStack
What's going on:
- the above command examples run the
cdk
command directly fromnode_modules/
ascdj.js
. cdk.js
is provided thets-node
command to run the aws-cdk app entrypoint filemain.ts
via the-a
argumentts-node
is run withtsconfig-paths/register
and the--project
argument is provided to specify the tsconfig to use:tsconfig.app.json
tsconfig.app.json
is as generated by the generator and extends fromtsconfig.json
which in turn extends fromtsconfig.base.json
in the root path of the nx workspace. The filetsconfig.base.json
is where nx tooling adds thepaths
for each library/package added to the nx workspace, undercompilerOptions
>paths
.- at the very end of the example we pass the cdk command (
synth
in my example, you can change this todeploy
,destroy
, etc) and the name of the stack we're targeting (in my case: "DemoBucketStack", which is specified inmain.ts
)
In my project, I will add scripts
targets to package.json
so that I can run the required cdk commands easily.
I believe the above resolution may be of assistance in terms of fixing the commands implemented by the @ago-dev/nx-aws-cdk-v2
package to support imports from other libraries/packages within the nx workspace.
In case it helps anyone, to build on the above, here's what I added to my package.json
in the scripts
section:
"cdk:command": "node --require ts-node/register node_modules/aws-cdk/bin/cdk.js -a \"pnpm dlx ts-node --require tsconfig-paths/register --project apps/infra/tsconfig.app.json apps/infra/src/main.ts\""
This enables me to run:
pnpm cdk:command <cdk_command_name> <StackToTarget> --profile <aws_profile_name>
For example: pnpm cdk:command synth DemoBucketStack --profile default
If you have ts-node
installed as a project dependency / dev dependency in package.json
you can omit running it via npx
or pnpm dlx
and instead use the version installed in your node_modules
:
"cdk:command": "node --require ts-node/register node_modules/aws-cdk/bin/cdk.js -a \"pnpm ts-node --require tsconfig-paths/register --project apps/infra/tsconfig.app.json apps/infra/src/main.ts\""
@firxworx I have a PR up to fix this.