Expected Behavior
Importing a prebuilt provider construct subpath, e.g.:
import { DataAwsCallerIdentity } from '@cdktn/provider-aws/lib/data-aws-caller-identity';
should resolve and run under Node's strict ESM resolution ("type": "module"), the same way it already works under CommonJS.
Actual Behavior
Error [ERR_UNSUPPORTED_DIR_IMPORT]: Directory import '.../node_modules/@cdktn/provider-aws/lib/data-aws-caller-identity' is not supported resolving ES modules imported from <bundle>.js
Did you mean to import "@cdktn/provider-aws/lib/data-aws-caller-identity/index.js"?
Prebuilt provider packages expose each resource as a subpath that resolves to a directory (e.g. @cdktn/provider-aws/lib/data-aws-caller-identity/{index.js,index.d.ts}), with no "exports" map in package.json and no "type" field. CommonJS require() resolves this fine via the legacy directory→index.js fallback, but Node's strict ESM resolver does not support directory imports at all, so any consumer bundling/running as ESM and referencing these subpaths fails outright.
This is a different, unaddressed case from #100 ("provider-generator: support ESM"), which only covers the locally generated TypeScript bindings produced by cdktn get / @cdktn/provider-generator (fixed via #150/#151 by adding file extensions to relative imports). The prebuilt, published provider packages are built via a completely different pipeline (jsii + jsii-pacmak/projen) and ship compiled JS, not TypeScript source, so that fix does not apply here.
Steps to Reproduce
- In an ESM project (
"type": "module" in package.json), import a prebuilt provider construct:
import { DataAwsCallerIdentity } from '@cdktn/provider-aws/lib/data-aws-caller-identity';
- Bundle with esbuild
format: 'esm', externalizing @cdktn/provider-aws (leaving the import specifier intact for Node to resolve at runtime), or just run the un-bundled import directly under Node.
- Execute with plain
node.
Versions
language: typescript
node: v22.23.2
cdktn: 0.23.2
constructs: 10.6.0
@cdktn/provider-aws: 24.3.0
arch: arm64
os: darwin (macOS)
Migration Context
Not sure / don't remember — we migrated to CDKTN before switching our build to ESM, so we can't confirm whether this reproduced under the original cdktf. Given the root cause (a package.json shape issue shared by the jsii/projen-based prebuilt-provider generator), it seems plausible this also affects/affected upstream cdktf's prebuilt provider packages, since they're generated by essentially the same pipeline — but this is unverified.
Upstream cdktf Issue
Not confirmed/found — flagging as plausible given the shared jsii/projen-based generation pipeline (see Migration Context above), but we did not locate a specific existing upstream report for this exact symptom.
Providers
┌───────┬──────────────────┬─────────┬────────────┬─────────────────────┬─────────────────┐
│ Provider Name │ Provider Version │ CDKTN │ Constraint │ Package Name │ Package Version │
├───────┼──────────────────┼─────────┼────────────┼─────────────────────┼─────────────────┤
│ aws │ 6.47.0 │ ^0.23.0 │ │ @cdktn/provider-aws │ 24.3.0 │
│ archive │ 2.8.0 │ ^0.23.0 │ │ @cdktn/provider-archive │ 13.1.0 │
│ external │ 2.4.0 │ ^0.23.0 │ │ @cdktn/provider-external│ 13.1.0 │
│ null │ 3.3.0 │ ^0.23.0 │ │ @cdktn/provider-null │ 13.1.0 │
│ random │ 3.9.0 │ ^0.23.0 │ │ @cdktn/provider-random │ 14.1.0 │
└───────┴──────────────────┴─────────┴────────────┴─────────────────────┴─────────────────┘
Possible Solutions
Generate an "exports" map (mapping each lib/<resource> subpath to its concrete index.js/index.d.ts) in the prebuilt-provider package template (jsii/projen-based), so these packages can be imported under strict ESM resolution — independent of, and in addition to, the generator-level fix already done for locally-generated bindings in #100.
Workarounds
Keep the bundler output format as CommonJS (e.g. esbuild format: 'cjs') for any code that imports @cdktn/provider-* subpaths, even in an otherwise-ESM ("type": "module") project — CJS's directory→index.js resolution fallback works fine, only the strict ESM resolver rejects it.
Anything Else?
Found while converting a CDKTF app's build to a single bundled file with esbuild; bundling to format: 'esm' (our original goal) fails specifically because of this, forcing us to keep format: 'cjs' for that bundle.
References
Help Wanted
Community Note
- Please vote on this issue by adding a 👍 reaction to the original issue to help the community and maintainers prioritize this request
- Please do not leave "+1" or other comments that do not add relevant new information or questions, they generate extra noise for issue followers and do not help prioritize the request
- If you are interested in working on this issue or have submitted a pull request, please leave a comment
Expected Behavior
Importing a prebuilt provider construct subpath, e.g.:
should resolve and run under Node's strict ESM resolution (
"type": "module"), the same way it already works under CommonJS.Actual Behavior
Prebuilt provider packages expose each resource as a subpath that resolves to a directory (e.g.
@cdktn/provider-aws/lib/data-aws-caller-identity/{index.js,index.d.ts}), with no"exports"map inpackage.jsonand no"type"field. CommonJSrequire()resolves this fine via the legacy directory→index.jsfallback, but Node's strict ESM resolver does not support directory imports at all, so any consumer bundling/running as ESM and referencing these subpaths fails outright.This is a different, unaddressed case from #100 ("provider-generator: support ESM"), which only covers the locally generated TypeScript bindings produced by
cdktn get/@cdktn/provider-generator(fixed via #150/#151 by adding file extensions to relative imports). The prebuilt, published provider packages are built via a completely different pipeline (jsii + jsii-pacmak/projen) and ship compiled JS, not TypeScript source, so that fix does not apply here.Steps to Reproduce
"type": "module"inpackage.json), import a prebuilt provider construct:format: 'esm', externalizing@cdktn/provider-aws(leaving the import specifier intact for Node to resolve at runtime), or just run the un-bundledimportdirectly under Node.node.Versions
Migration Context
Not sure / don't remember — we migrated to CDKTN before switching our build to ESM, so we can't confirm whether this reproduced under the original
cdktf. Given the root cause (apackage.jsonshape issue shared by the jsii/projen-based prebuilt-provider generator), it seems plausible this also affects/affected upstreamcdktf's prebuilt provider packages, since they're generated by essentially the same pipeline — but this is unverified.Upstream cdktf Issue
Not confirmed/found — flagging as plausible given the shared jsii/projen-based generation pipeline (see Migration Context above), but we did not locate a specific existing upstream report for this exact symptom.
Providers
Possible Solutions
Generate an
"exports"map (mapping eachlib/<resource>subpath to its concreteindex.js/index.d.ts) in the prebuilt-provider package template (jsii/projen-based), so these packages can beimported under strict ESM resolution — independent of, and in addition to, the generator-level fix already done for locally-generated bindings in #100.Workarounds
Keep the bundler output format as CommonJS (e.g. esbuild
format: 'cjs') for any code that imports@cdktn/provider-*subpaths, even in an otherwise-ESM ("type": "module") project — CJS's directory→index.jsresolution fallback works fine, only the strict ESM resolver rejects it.Anything Else?
Found while converting a CDKTF app's build to a single bundled file with esbuild; bundling to
format: 'esm'(our original goal) fails specifically because of this, forcing us to keepformat: 'cjs'for that bundle.References
Help Wanted
Community Note