nrwl-nxpnpmpnpm-workspace

Cannot import `readConfiguration` from `@angular/compiler-cli` in a pnpm with nx monorepo


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.

Reproduction

Option A: Clone the repo

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)

Option B: Manual setup

  1. 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
    
  2. Create builder.ts:

    import { readConfiguration } from '@angular/compiler-cli';
    //           ~~~~~~~~~~~~~~~~~~
    // Module '"@angular/compiler-cli"' has no exported member 'readConfiguration'.ts(2305)
    

What I’ve Tried


Why isn’t readConfiguration exposed in the public API of @angular/compiler-cli? how to solve it?


Solution

  • 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.


    Fix

    1. Open your root tsconfig.base.json (or tsconfig.json if you’re not using the Nx base config).

    2. Locate the compilerOptions.moduleResolution setting.

    3. Change it from "nodenext" to "node":

      {
        "compilerOptions": {
      -   "moduleResolution": "nodenext",
      +   "moduleResolution": "node",
          // …other options…
        }
      }
      
      
    4. 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.