angular-cli library create secondary entry point
Asked Answered
I

3

19

I am trying to create what I believe is called a secondary entry point into my angular npm package. I want the following two entry points

@scope/data-service
@scope/data-service/models

Using the angular-cli to generate the base package generates the following structure

scope
└───data-service
    │   karma.conf.js
    │   ng-package.json
    │   ng-package.prod.json
    │   package.json
    │   tsconfig.lib.json
    │   tsconfig.spec.json
    │   tslint.json
    │
    └───src
        │   public_api.ts
        │   test.ts
        │
        └───lib
                data-service.component.spec.ts
                data-service.component.ts
                data-service.module.ts
                data-service.service.spec.ts
                data-service.service.ts

Based on ng-packagr documentation you would add a folder under data-service called models then add a second package.json to that folder but ng-packagr seems to use a slightly different structure than the angular-cli. Ideally I am trying to model the structure similar to https://github.com/angular/angular/tree/master/packages/common but as long as the public exposed is @scope/data-service and @scope/data-service/models I would be happy.

When I try to create the structure similar to ng-packager recommendation I get

error TS6059: File 'C:/projects/data-service-app/projects/scope/data-service/models/src/index.ts' is not under 'rootDir' 'C:\projects\data-service-app\projects\scope\data-service\src'. 'rootDir' is expected to contain all source files.

When I move the models directory into the data-service\src directory my entrypoints are

@scope/data-service
@scope/data-service/src/models

How do I get rid of the src on my secondary entry point?

What is the correct approach for creating a library with a secondary entry point when using the angular-cli?

Infrequency answered 11/6, 2018 at 16:39 Comment(1)
This is the closest discussion to my issue but I still can't seem to find the solution github.com/dherges/ng-packagr/issues/900Infrequency
I
8

Thanks for the reply. Here is the solution I ended up with, it all revolved around setting up the index.ts and public_api.ts files correctly

\---projects
    \---scope
        \---ngx-package
            |   karma.conf.js
            |   ng-package.json
            |   ng-package.prod.json
            |   package.json
            |   tsconfig.lib.json
            |   tsconfig.spec.json
            |   tslint.json
            |
            \---src
                |   public_api.ts
                |   test.ts
                |
                +---lib
                |       package-client-config.ts
                |       package-client.spec.ts
                |       package-client.ts
                |       package.module.ts
                |
                \---models
                    |   index.ts  (1)
                    |   package.json (2)
                    |   public_api.ts  (3)
                    |
                    \---src
                        |   public_api.ts  (4)
                        |
                        \---lib
                            |   model-a.ts
                            |   model-b.ts
                            |
                            \---hateoas
                                    hateoas.ts

Ok so in the tree above notes the parens with numbers inside they correspond to the files below.

1) /projects/scope/ngx-package/src/models/index.ts

// export what ./public_api exports so we can reference models like
// import { modelA } from './models'
export * from './public_api';

2) /projects/scope/ngx-package/src/models/package.json

{
  "ngPackage": {}
}

3) /projects/scope/ngx-package/src/models/public_api.ts

export * from './src/public_api';

4) /projects/scope/ngx-package/src/models/src/public_api.ts

export * from './lib/model-a';
export * from './lib/model-b';
export * from './lib/hateoas/hateoas';

With this setup you only need to maintain your list of exports in one place. I tried a lot of other variations that didn't work this seemed to work without problem.

Infrequency answered 28/9, 2018 at 15:57 Comment(3)
I see a similar pattern in angular project itself. Have anyone heard of cli support to do this?Zepeda
@Zepeda - Yep, the reason you see similarity is that I referenced the angular repo, ng-bootstrap, and rxjs while investigating how to do this. But I have not stayed up to date on the CLI's or packgr's implementation to see if they have built in this functionality.Infrequency
Ok. that's cool. I will update if I find something interesting. They must be using something under the hood to keep the repo that clean.. :)Zepeda
B
7

I'm afraid that this is not an easy task with ng-packagr.

For every "project" that you try to package, ng-packagr automatically detects all secondary packages.

ng-packagr ignores tsconfig.lib.json files of secondary packages, it will use the tsconfig file provided with the primary package.

It then loads a TS program for the primary and all secondaries, before compiling, with the tsconfig of the primary.

This is done this way so the packager can then parse the code and create a dependency tree, which will tell it which package to render first, 2nd etc... YES, it also means that ng-packagr DOES NOT assume that a secondary package always depends on the primary, it might be the other way and it's valid...

Now, up to this point everything should be ok, no errors etc... A TS program is created for all packages but without emitting anything so all is good.

The error you see comes in the compilation phase, where the compiler try to emit files and throws. This is when ng-packagr logs "Compiling TypeScript sources through ngc"

At this point, typescript is not happy with the reference to a file outside of the root, which is the case.

One solution is to update the paths property in tsconfig to point to the output directory for every package that was built. So if package A was just compiled, we change/create paths record that points to the output library which will not be considered as a TS source... thus no error.

This will work, I have tested it, but sadly it requires some work either in ng-packagr source code or, as I did it, using a custom angular devkit builder...

With it you can replace the paths right after each compilation has finished, so next compilation will reference the built output and not the source code.

Because ng-packagr build packages based on dependency graph we are safe to assume that this will work.

Berner answered 28/9, 2018 at 3:32 Comment(0)
W
2

Example Folder Layout for Secondary Entrypoints

All you have to do is create a package.json file and put it where you want a secondary entry point to be created. One way this can be done is by mimicking the folder structure of the following example which has a testing entry point in addition to its main entry point.

my_package
├── src
|   ├── public_api.ts
|   └── *.ts
├── ng-package.json
├── package.json
└── testing
    ├── src
    |   ├── public_api.ts
    |   └── *.ts
    └── package.json

The contents of my_package/testing/package.json can be as simple as:

{
  "ngPackage": {}
}

No, that is not a typo. No name is required. No version is required. It's all handled for you by ng-packagr! When built, the primary entry point is imported by import {..} from '@my/library' and the secondary entry point with import {..} from '@my/library/testing'

Source - https://github.com/ng-packagr/ng-packagr/blob/master/docs/secondary-entrypoints.md

Whereupon answered 19/8, 2019 at 11:8 Comment(3)
I thought I tried something like this but haven't had the need to go back and refactor, I am actually working on this library now so maybe I will give it a quick test and let you know.Infrequency
@Whereupon This structure will cause an error stating that all source files must be within the 'rootDir'.Tenant
I am having an issue with code coverage report. Despite running all tests, it only reports for the primary endpoint.Dysentery

© 2022 - 2024 — McMap. All rights reserved.