Search code examples
angulartypescriptmonorepoangular-library

Angular monorepo error TS6059: File 'ng-youtube-api.service.ngtypecheck.ts' is not under 'rootDir'. 'rootDir' is expected to contain all source files


I've created 3 angular libraries/packages:

Now I wanted to create a library containing a VideoPlayerComponent, using only the packages providing the YoutubeApiService, DailymotionApiService and VimeoApiService. In order to not include the other components unnecessarily, I want to split the 3 libraries each, so that I can install only the Service classes.

You could argue that angular uses tree-shaking, so the components will not be bundled with the application anyway, but anyhow I'd rather have those dependencies seperated for brevity.

I've tried setting up a monorepo containing 2 libraries and a test application, but from the moment I reference a service from another library, the build fails. I've created a very basic example workspace to reproduce the issue:

git clone https://github.com/PieterjanDeClippel/angular-monorepo-test
cd angular-monorepo-test
npm install
ng build @mintplayer/ng-youtube-api
ng build @mintplayer/ng-youtube-player
ng build ng-youtube-player-demo

# All projects compile successfully
# Now go to the NgYoutubePlayerComponent and uncomment the injection parameter in the constructor (line 16)

ng build @mintplayer/ng-youtube-player

The build fails with tons of the following errors:

✖ Compiling with Angular sources in Ivy partial compilation mode.
projects/mintplayer/ng-youtube-api/src/lib/ng-youtube-api.service.ts:1:1 - error TS6059: File 'C:/Users/user/source/repos/Tmp/mintplayer-ng-youtube-player/projects/mintplayer/ng-youtube-api/src/lib/ng-youtube-api.service.ngtypecheck.ts' is not under 'rootDir' 'C:\Users\user\source\repos\Tmp\mintplayer-ng-youtube-player\projects\mintplayer\ng-youtube-player\src'. 'rootDir' is expected to contain all source files.
1 import { Injectable } from '@angular/core';
 
projects/mintplayer/ng-youtube-api/src/public-api.ts:1:1 - error TS6059: File 'C:/Users/user/source/repos/Tmp/mintplayer-ng-youtube-player/projects/mintplayer/ng-youtube-api/src/public-api.ngtypecheck.ts' is not under 'rootDir' 'C:\Users\user\source\repos\Tmp\mintplayer-ng-youtube-player\projects\mintplayer\ng-youtube-player\src'. 'rootDir' is expected to contain all source files.

There are 2 main problems here:

  1. You have to build each project seperately, in the correct order
  2. You cannot use services from libraries in other libraries

I've already read the following similar question, but it didn't help me out:

Code

My test code is hosted here. All instructions to reproduce the issue are noted in the code block above. The main changes I made are in the root tsconfig.json:

{
  ...
  "compilerOptions": {
    ...,
    "paths": {
      "@mintplayer/ng-youtube-api": [
        "projects/mintplayer/ng-youtube-api/src/public-api.ts"
      ],
      "@mintplayer/ng-youtube-player": [
        "projects/mintplayer/ng-youtube-player/src/public-api.ts"
      ]
    }
  }
}

I've already setup a workspace containing a library and application, where the application consumes classes from the library without any problems (see the 3 repositories on top of the question), but from the moment a library consumes classes from another library, the build is broken.

How can I fix this, and have a single workspace with 2 libraries and a test application?


Solution

  • NX it is apparently: https://nx.dev. If you ever need to create an angular library, it's best to generate an NX project rightaway.

    npm install -g @angular/cli@latest
    npm install -g nx
    npx create-nx-workspace
    cd mycompany-ng-youtube-player
    

    Generate a library for the youtube player:

    nx g @nrwl/angular:lib mycompany-ng-youtube-player --buildable --publishable --import-path @mycompany/ng-youtube-player
    

    Specify your package name and version in the package.json:

    {
      "name": "@mycompany/ng-youtube-player",
      "version": "1.0.0",
      ...
    }
    

    Generate a library for the IFrame API:

    nx g @nrwl/angular:lib mycompany-ng-youtube-api --buildable --publishable --import-path @mycompany/ng-youtube-api
    

    Specify your package name and version in the package.json:

    {
      "name": "@mycompany/ng-youtube-api",
      "version": "1.0.0",
      ...
    }
    

    Generate a component in the @mycompany/ng-youtube-player package:

    cd .\libs\mycompany-ng-youtube-player\src\lib
    nx g component ng-youtube-player --project=mycompany-ng-youtube-player --module=mycompany-ng-youtube-player --export
    

    Generate a service in the @mycompany/ng-youtube-api package:

    cd ..\..\..\mycompany-ng-youtube-api\src\lib
    nx g service ng-youtube-api --project=mycompany-ng-youtube-api
    

    Now you can add the package dependency to the package.json of the player:

    {
      ...,
      "peerDependencies": {
        "@mycompany/ng-youtube-api": "~3.0.0",
        ...
      }
    }
    

    Now it's just a matter of modifying the code.

    To build and run the application:

    npm run nx run-many -- --target=build --projects=ng-youtube-player-demo --with-deps
    npm run nx serve -- --open
    

    Important note

    If you're considering using NX, then you apparently need to bear the following in mind:

    • Angular releases a new version (v14)
    • Whoever uses your library, is waiting for you to release a @angular/core@v14 compatible version of your library
    • You will be waiting for NX to support Angular 14
    • NX is waiting for jest-preset-angular to release a v14 compatible version
    • ...