I’m building a plain Node-based utility (not an Angular application) that uses the @angular/compiler-cli
package directly. When I try to import readConfiguration
, TypeScript reports that it’s not exported.
Module '"@angular/compiler-cli"' has no exported member 'readConfiguration'.ts(2305)
I’ve created a minimal repro—either clone the repo or follow the steps below to see the TS error.
git clone https://github.com/wizardnet972/nx-tsapp
cd nx-tsapp
pnpm install
Then open packages/builder/src/lib/builder.ts
in your editor; the import there triggers the error:
import { readConfiguration } from '@angular/compiler-cli';
// ~~~~~~~~~~~~~~~~~~
// Module '"@angular/compiler-cli"' has no exported member 'readConfiguration'.ts(2305)
Create a new directory and initialize:
npx create-nx-workspace@latest --pm pnpm --name nx-tsapp
Which stack do you want to use? · none
...
cd nx-tsapp
pnpm nx g @nx/js:library --directory=packages/builder --bundler=vite --linter=eslint --publishable=true --unitTestRunner=vitest
NX Generating @nx/js:library
Fetching @nx/vite...
Fetching @nx/eslint...
CREATE packages/builder/src/lib/builder.ts
...
CREATE packages/builder/eslint.config.mjs
CREATE .verdaccio/config.yml
Scope: all 2 workspace projects
$ pnpm approve-builds
$ pnpm add @angular/compiler-cli
...
dependencies:
+ @angular/compiler-cli ^20.1.0
...
Done in 2.8s using pnpm v10.13.1
Create builder.ts
:
import { readConfiguration } from '@angular/compiler-cli';
// ~~~~~~~~~~~~~~~~~~
// Module '"@angular/compiler-cli"' has no exported member 'readConfiguration'.ts(2305)
@angular/compiler-cli@^20.1.0
.node_modules/@angular/compiler-cli/index.d.ts
—no readConfiguration
export.readConfiguration
in the source under src/perform_compile.ts
.index.d.ts
refers to files under ./src
, which aren’t present in the installed package layout under PNPM.Why isn’t readConfiguration
exposed in the public API of @angular/compiler-cli
? how to solve it?
I did some digging and discovered that the root cause is your TypeScript moduleResolution strategy. When you scaffold a plain Node-based library with Nx (e.g. via pnpm nx g @nx/js:library …
), the generated tsconfig.base.json
defaults to:
{
"compilerOptions": {
"moduleResolution": "nodenext",
// …other defaults…
}
}
Under nodenext
, TypeScript applies Node’s new ESM lookup rules (requiring explicit extensions, honoring "exports"
maps, etc.). Since @angular/compiler-cli
ships a CommonJS build with an index.d.ts
that isn’t covered by an ESM "exports"
entry, the compiler never “sees” its readConfiguration
export.
Open your root tsconfig.base.json
(or tsconfig.json
if you’re not using the Nx base config).
Locate the compilerOptions.moduleResolution
setting.
Change it from "nodenext"
to "node"
:
{
"compilerOptions": {
- "moduleResolution": "nodenext",
+ "moduleResolution": "node",
// …other options…
}
}
Restart your IDE/TypeScript server (and rerun your build).
After that, this import
import { readConfiguration } from '@angular/compiler-cli';
will resolve cleanly under the classic CommonJS-style lookup.