ng-packagr icon indicating copy to clipboard operation
ng-packagr copied to clipboard

Secondary entry point bug: `src/` path gets part of package import path

Open georgiee opened this issue 6 years ago β€’ 30 comments

Type of Issue

[x] Bug Report
[ ] Feature Request

Description

When placing the main entry point in src/ and every subentry point in a new folder inside src/ you will get the primary point correctly at @my/package-name but every secondary entry point is only accessible by the path @my/package-name/src/*.

This is a remaining error after fixing the base url stuff in this PR https://github.com/dherges/ng-packagr/pull/862

Relates to: https://github.com/dherges/ng-packagr/issues/854

How To Reproduce

I created a new example in the ng-packagr project. See my branch https://github.com/georgiee/ng-packagr/tree/src-entry-point-bug.

  1. Launch example nested-src.
  2. It works. But only because it's fixed by providing this import
import { STATIC_FOO_VALUE, FooClass } from '@sample/nested-src/src/foo';

instead of

import { STATIC_FOO_VALUE, FooClass } from '@sample/nested-src/foo';

Expected Behaviour

This path should work:

import { STATIC_FOO_VALUE, FooClass } from '@sample/nested-src/foo';

Version Information

$: ng -v
@angular-devkit/architect    0.6.3 (cli-only)
@angular-devkit/core         0.6.0
@angular-devkit/schematics   0.6.3 (cli-only)
@angular/cdk                 6.0.1
@angular/router              6.0.1
@ngtools/json-schema         1.1.0
@schematics/angular          0.6.3 (cli-only)
@schematics/update           0.6.3 (cli-only)
rxjs                         6.1.0
typescript                   2.7.2

georgiee avatar May 23 '18 10:05 georgiee

As far as I know this behaviour was already there before #862. Are you sure they are related? This is the reason all my secondary entry point are directly in my root (know I tried everything to get this working, but gave up and never had time to file a feature request for this)

I am dying to see this feature though, I would prefer to move all my secondary entry points to src or an even deeper path so I can separate the package source, the demo application, and the files needed for tests and build.

I would see multiple options resolving this:

  • use the secondary entry point directory name only instead of the relative path to the primary as suggested by @georgiee
  • ability to add a package name in package.json in secondary entry point folder (@x/y/z is invalid name property though, so must be a property in ngPackage config within)
  • more complex use the path alias in tsconfig.json configuration to detect which alias you want for the package name (I am using alias already to depend secondary packages on each other)

abbazabacto avatar May 23 '18 21:05 abbazabacto

Yes, I don’t think this is related to that change aswell tbh.

On Wed, 23 May 2018 at 23:58, Bart Meinders [email protected] wrote:

As far as I know this behaviour was already there before #862 https://github.com/dherges/ng-packagr/pull/862. Are you sure they are related? This is the reason all my secondary entry point are directly in my root (know I tried everything to get this working, but gave up and never had time to file a feature request for this)

I am dying to see this feature though, I would prefer to move all my secondary entry points to src or an even deeper path so I can separate the package source, the demo application, and the files needed for tests and build.

I would see multiple options resolving this:

  • use the secondary entry point directory name only instead of the relative path to the primary as suggested by @georgiee https://github.com/georgiee
  • ability to add a package name in package.json in secondary entry point folder (@x/y/z is invalid name property though, so must be a property in ngPackage config within)
  • more complex use the path alias in tsconfig.json configuration to detect which alias you want for the package name (I am using alias already to depend secondary packages on each other)

β€” You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/dherges/ng-packagr/issues/900#issuecomment-391509691, or mute the thread https://github.com/notifications/unsubscribe-auth/AQv-Wp85gEJffpp9xEDgOBIz3aop96Tdks5t1dtqgaJpZM4UKJOk .

alan-agius4 avatar May 23 '18 22:05 alan-agius4

Could we turn this in a feature request? πŸ‘Ό

abbazabacto avatar May 23 '18 22:05 abbazabacto

This also effects when adding secondary entry point to lib generated from ng g library

william-lohan avatar May 25 '18 22:05 william-lohan

Placing secondary entry points under src is not the ideal solutions for several reasons.

  1. Path resolutions work out of the box, and you might end up with complex tsconfig path mappings which will be different for development and build. IMHO I would keep the distributable structure as close as the development structure. It's just the most scalable and future proof way to code.
  2. From an architectural point of view, one could start mixing feature folders with secondary entry points folders since they are under src. My suggested way is to use src for the source of the entry point. This is also something which is done by Angular, and makes total sense.
  3. We determine the structure based on the location of your package.json, we are assuming that your are creating the structure as how you want it to be generated. Thus, having a 'correct' folder structure here is imperative.

Using the last part of secondary entry point directory name is a bit a problem. For instance when you have a 3-level entrypoint such as foo/bar/baz getting only the last part would mean you drop the bar and resulting in foo/baz which is incorrect.

That said, I will try to think about something.

alan-agius4 avatar May 26 '18 08:05 alan-agius4

Hey @alan-agius4, first of all sorry for mixing this with the base url issue. It just felt that its related. I do agree with all of your points πŸ‘Œ

Regarding 2) At the moment you have no way of separating source files and things that you need around, like all of your config files, your README file, a generated node_modules folder and the like. Everything have to be placed in the same folder as your code. I got the idea of placing the files in the src/ folder, as the Angular CLI currently generates it like this for library projects. It looks pretty neat as as everything that is not part of your sources are located outside of the src folder.

You also suggest what I want:

My suggested way is to use src for the source of the entry point

My idea is that you determine the root for all of your entry points just by looking at the base folder of the file lib.entryFile provided in the ng-packagr config. That way I can place my source folder wherever I want (e.g. src/) and leaving everything near the package.json. Those files (readme, configs) are not part of the generated package and need to be copied manually if wanted anyway.

In case this is a feature request not happening very soon, maybe the Angular CLI should change their schematics not to cause any confusion when people try to use secondary entry points? Or do you think there is an easy way of getting this working soon ?

georgiee avatar May 28 '18 08:05 georgiee

@georgiee, You are free to put your code in src it's just the secondary entrypoints shouldn't be in src, because the folder structure will be retained and in my option it should be retained as I won't like to make distinctions based on if the folder is named src or not and in some cases this might be breaking, as well, as consumers might rely on the folder structure they are developing in to be emitted. With Angular-CLI, you can create secondary entry points by placing it outside of the src,

Ex you should have this folder strucuture:

- library
-- src
--- lib (feature)
-- secondary (2nd Entry Point)
--- src

With regards to the Angular CLI Schematics, I don't see any problem with it the generation library schematic. Angular CLI generates a single entrypoint. (Everything under src is for one entrypoint) If you want to generate an addition entrypoint, you need to create an additional folder parallel to src. The only thing which is a bit confusing is that test.ts which is under source and if you want a secondary entrypoint that might make sense to be moved outside.

//cc @filipesilva

alan-agius4 avatar May 28 '18 10:05 alan-agius4

@alan-agius4 it is not about the src folder or not, it is about placing it in a deeper directory to avoid clutter with the rest of the files and folder in the root directory. For me there is demo, dist, docs, e2e, node_modules, next to all the files like .gitignore, tsconfig.json, package.json, and so on. Add a bunch of secondary entrypoint directories and you can imagine it gets hard on the eyes to determine what is part of the eventual build and what is just there for development or documentation purpose.

I do agree that it less configuration is better, so by default it is good that you follow the original file structure. I would just like to see a way to overwrite this default behaviour to make the file structure better readable when desired. Maybe just an extra setting name/moduleName/path in the ngPackage.lib config?

I mentioned the tsconfig path alias, as I am using this this already to make secondary entypoints depend on each other and to use these mapped imports for demo/example code.

abbazabacto avatar May 28 '18 10:05 abbazabacto

Yeah it's exactly like @abbazabacto describes it. To draw a picture of it:

  1. This is a mess All secondary entry points (feature-*) are in the same folder as anything else.
.
β”œβ”€β”€ node_modules
β”œβ”€β”€ README.md
β”œβ”€β”€ feature-a
β”‚Β Β  └── public-api.ts
β”œβ”€β”€ feature-b
β”‚Β Β  └── public-api.ts
β”œβ”€β”€ feature-c
β”‚Β Β  └── public-api.ts
β”œβ”€β”€ karma.conf.js
β”œβ”€β”€ package.json
β”œβ”€β”€ postinstall-message.js
β”œβ”€β”€ public-api.ts
β”œβ”€β”€ test.ts
β”œβ”€β”€ tsconfig.lib.json
└── tsconfig.spec.json

  1. While this will collect any source in src/ and files like test.ts, README.md are located one level higher.
.
β”œβ”€β”€ node_modules
β”œβ”€β”€ README.md
β”œβ”€β”€ karma.conf.js
β”œβ”€β”€ package.json
β”œβ”€β”€ src
β”‚Β Β  β”œβ”€β”€ feature-a
β”‚Β Β  β”‚Β Β  └── public-api.ts
β”‚Β Β  β”œβ”€β”€ feature-b
β”‚Β Β  β”‚Β Β  └── public-api.ts
β”‚Β Β  β”œβ”€β”€ feature-c
β”‚Β Β  β”‚Β Β  └── public-api.ts
β”‚Β Β  └── public-api.ts
β”œβ”€β”€ test.ts
β”œβ”€β”€ tsconfig.lib.json
└── tsconfig.spec.json

georgiee avatar May 28 '18 10:05 georgiee

tsconfig path alias, are already in used in ng-packagr for the same reason, to map entry points together with secondary entrypoints.

Reading the path of ngPackage.lib and get the structure from there might be an option, but that ofc will be a breaking change, as the structure outputted will be slightly different. If users have something like primary/public_api.ts and we take the primary as path for the primary entrypoint and not the location of package.json we will get incorrect namings and paths check this for instance: https://github.com/dherges/ng-packagr/tree/master/integration/samples/secondary

Looping in @dherges here as well, maybe he has some ideas.

alan-agius4 avatar May 28 '18 10:05 alan-agius4

@alan-agius4 The primary endpoint should always be based on the name of the package.json as this is the name of the node module upon publishing, even if the public_api.ts is placed somewhere else. (Actually when I tried to place the public_api.ts somewhere else, it failed on some of my own aliases, guess I kind of understand why this is happening now)

The request is all about the secondary endpoints (and maybe also on the location of the main entry point), they are based on the paths relative to this package.json. Which means that your development files should always be in the same file structure as you want the eventual package/bundle paths to be.

I can understand that it become quite cumbersome to make this work on your end. Maybe it is just something we have to learn to live with.

I did updated a previous ngpackagr issue repo to demonstrate what a desired architecture would be https://github.com/abbazabacto/ngpackagr-issue:

  • package.json is pointing the primary entry point to src/index.ts
  • secondary entry points are all under src/**
  • tsconfig has path alias of entry points so they can depend on each other
  • primary entry point uses the path alias to make a module containing all sub modules, and re-exporting all contents (because the aliases are used, they are seen as an external dependencies and therefor not included in the primary bundle)
  • ./demo (Angular CLI) is using path alias to have examples demonstrating implementation

abbazabacto avatar May 28 '18 11:05 abbazabacto

Okay, so from my understanding you want something like (Angular Material2)[https://github.com/angular/material2/tree/master/src/lib], IMHO, if you want something like that you should place a package.json under src And trigger the build there. That is the most straight forward way to achieve the desired structure, and If you do this you wouldn't even need to create path mappings yourselves as ng-packagr handles these.

I will still try to find a solution for this feature/issue but from my end, I am a bit busy with other stuff right now. So it has to wait a couple of days, maybe weeks.

My worries is that basing the structure and naming of secondaries based on the lib.entryPoint is quite fragile. For instance, if you have something like the below it it will be hell to create the proper naming for 2nd and 3rd level entry point. And in this instance, why should ng-packagr make a distinction if the folder is src or not? It will become rather complex to create the naming of the packages, and where they should be emitted.

I don't think that using ngPackage.lib is good enough. Especially for 3 level entrypoints.

β”œβ”€β”€ src
β”‚   β”œβ”€β”€ feature-a
β”‚      └── src
β”‚         └── public-api.ts
β”‚         β”œβ”€β”€ sub-feature-a
β”‚            └── src
β”‚                  └── public-api.ts

alan-agius4 avatar May 28 '18 12:05 alan-agius4

Why do you use so many src folders in your example? It's only about the location of the very first src folder. Any other entrypoint should be located directly in a folder without any separate src folder. It's moving the root not allowing to specify a src holding folder for every entry point.

Instead of looking for the location of the primary public_api.ts, what about allowing to pass in a different root path? That would not break anything as you could default to ./ and we could change it to ./src.

georgiee avatar May 28 '18 12:05 georgiee

@alan-agius4 I do agree with you that a structure like @angular/material is even better! The surrounding repo would have to duplicate the dependencies for demo and docs, but it will also mean a better separation of those dependencies. Thanks for the insight!

abbazabacto avatar May 28 '18 12:05 abbazabacto

@alan-agius4 really thanks so much again, I was able to get it working in my dummy issue repo fairly easy, without even duplication of dependencies: https://github.com/abbazabacto/ngpackagr-issue/commit/9534c2b6271e4618002c75253a84ad3c9837cdd4

I can totally live with the package.json file in the ./src directory!

I did the simple steps:

  • rename package.json name to some src name
  • add package.json to ./src with the correct package name, version, ngPacakge-config and just the peerDependencies
  • then build ng-packagr from the original root by just pointing to the new pacakge.json in src ng-packagr -p src/package.json
  • (not in commit above) alternatively I configured dest ngPackage-config in ./src/package.json to be ../dist so the output is the same as in my other repos

abbazabacto avatar May 28 '18 13:05 abbazabacto

@georgiee I am taking your example to the extreme, usually, when one has a secondary entrypoint, there will be another src folder. A src is usually specific for an entrypoint.

Angular themselves follow this pattern, See here for an instance https://github.com/angular/angular/tree/master/packages/common

alan-agius4 avatar May 28 '18 13:05 alan-agius4

@abbazabacto glad that it worked for you :)

alan-agius4 avatar May 28 '18 13:05 alan-agius4

Thanks for the clarification about the src folders. Makes sense this way finally :) I will give the second package.json a try. Looks promising what @abbazabacto have done in the showcased commit πŸ‘ŒThanks for this!

georgiee avatar May 28 '18 15:05 georgiee

I am happy to see that everyone is a bit more happy now πŸ˜„

alan-agius4 avatar May 28 '18 15:05 alan-agius4

Thanks for your endless support @alan-agius4!

abbazabacto avatar May 28 '18 16:05 abbazabacto

@alan-agius4 Where I would love to say this is a resolved subject, there is still something quite huge failing in mimicking the proposed setup like Angular Material's public_api.ts

export * from '@angular/material/autocomplete';
export * from '@angular/material/badge';
export * from '@angular/material/bottom-sheet';
export * from '@angular/material/button';
// etc..

For material this results into metadata which points to the same repo:

// ~/node_modules/@angular/material/material.metadata.json
{
  "__symbolic": "module",
  "version": 3,
  "metadata": {},
  "exports": [
    {
      "from": "./expansion"
    },
    {
      "from": "./core"
    },
    {
      "from": "./grid-list"
    },
    {
      "from": "./tree"
    },

The problem is that when I re-export modules in a similar way under the primary endpoint the metadata doesn't get generated like that (added a commit to previous example repo so you can see for yourself). There is not even a mention of the @abbazabacto/ngpackagr-issue/core module.

// ~/dist/abbazabacto-ngpackagr-issue.metadata.json
{
  "__symbolic": "module",
  "version": 4,
  "exports": [
    {
      "from": "@abbazabacto/ngpackagr-issue/foo"
    }
  ],
  "metadata": {},
  "origins": {},
  "importAs": "@abbazabacto/ngpackagr-issue"
}

With this missing/broken metadata another module using the primary endpoint will fail to build in AOT mode...

No idea how @angular/material does it... Maybe a hint lays in the fact that for me the generated primary bundle just re-exports the modules content as if it they are external references:

(function (global, factory) {
	typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@abbazabacto/ngpackagr-issue/core'), require('@abbazabacto/ngpackagr-issue/foo')) :
	typeof define === 'function' && define.amd ? define('@abbazabacto/ngpackagr-issue', ['exports', '@abbazabacto/ngpackagr-issue/core', '@abbazabacto/ngpackagr-issue/foo'], factory) :
	(factory((global.abbazabacto = global.abbazabacto || {}, global.abbazabacto['ngpackagr-issue'] = {}),global.abbazabacto['ngpackagr-issue'].core,global.abbazabacto['ngpackagr-issue'].foo));
}(this, (function (exports,core,foo) { 'use strict';

	/**
	 * @fileoverview added by tsickle
	 * @suppress {checkTypes} checked by tsc
	 */

	/**
	 * @fileoverview added by tsickle
	 * @suppress {checkTypes} checked by tsc
	 */

	exports.CoreModule = core.CoreModule;
	exports.CORE_CONFIG = core.CORE_CONFIG;
	exports.CoreService = core.CoreService;
	exports.FooModule = foo.FooModule;
	exports.FooService = foo.FooService;

	Object.defineProperty(exports, '__esModule', { value: true });

})));

This is similar to how secondary endpoints are depending on each other, like @angular/material/core in bundle files like: ~/node_modules/@angular/material/bundles/material-badge.umd.js

But remarkable is that the bundle for the primary material module just includes the content of all modules: ~/node_modules/@angular/material/bundles/material.umd.js

abbazabacto avatar May 31 '18 15:05 abbazabacto

@alan-agius4 I went one step further, so you could actually see the AOT build when using the package.

Added another commit where I point the tsconfig alias to the dist folder with the eventual package, and including both CoreModule and FooModule in the demo application from the primary endpoint.

If you run the following commands

yarn install
yarn ng-packagr
yarn build --prod

You will see an error:

ERROR in : Unexpected value 'CoreModule in ~/ngpackagr-issue/dist/abbazabacto-ngpackagr-issue.d.ts' imported by the module 'AppModule in ~/ngpackagr-issue/demo/app/app.module.ts'. Please add a @NgModule annotation.

Like I mentioned in the comment above the metadata looks incomplete, as there is no reference to the CoreModule of @abbazabacto/ngpackagr-issue/core:

{
  "__symbolic": "module",
  "version": 4,
  "exports": [
    {
      "from": "@abbazabacto/ngpackagr-issue/foo"
    }
  ],
  "metadata": {},
  "origins": {},
  "importAs": "@abbazabacto/ngpackagr-issue"
}

If I remove the CoreModule import in the demo application, the error disappears. So it seemed the @abbazabacto/ngpackagr-issue/foo reference is working.

If I add the missing reference of @abbazabacto/ngpackagr-issue/core to the metadata file manually, the build also succeeds

{
  "__symbolic": "module",
  "version": 4,
  "exports": [
    {
      "from": "@abbazabacto/ngpackagr-issue/core"
    },
    {
      "from": "@abbazabacto/ngpackagr-issue/foo"
    }
  ],
  "metadata": {},
  "origins": {},
  "importAs": "@abbazabacto/ngpackagr-issue"
}

The FooModule depends on the CoreModule, and FooService on the CORE_CONFIG, CoreConfig and CoreService. I had a hunch it might be as of this dependency that the @abbazabacto/ngpackagr-issue/core is missing, but when I remove all inner dependencies the meta data still is still missing the reference to core

{
  "__symbolic": "module",
  "version": 4,
  "exports": [
    {
      "from": "@abbazabacto/ngpackagr-issue/foo"
    }
  ],
  "metadata": {},
  "origins": {},
  "importAs": "@abbazabacto/ngpackagr-issue"
}

abbazabacto avatar May 31 '18 15:05 abbazabacto

Thanks for the detailed info I’ll try to download your branch maybe today or tomorrow and have a lot.

Can you create a branch for this issue with the latest commits you did?

Thanks.

On Thu, 31 May 2018 at 17:35, Bart Meinders [email protected] wrote:

@alan-agius4 https://github.com/alan-agius4 I went one step further, so you could actually see the AOT build when using the package.

Added another commit https://github.com/abbazabacto/ngpackagr-issue/commit/974068c921dbe2042ff310a71eb092269ec2c439 where I point the tsconfig alias to the dist folder with the eventual package, and including both CoreModule and FooModule.

If you run the following commands

yarn install yarn ng-packagr yarn build --prod

You will see an error:

ERROR in : Unexpected value 'CoreModule in ~/ngpackagr-issue/dist/abbazabacto-ngpackagr-issue.d.ts' imported by the module 'AppModule in ~/ngpackagr-issue/demo/app/app.module.ts'. Please add a @NgModule annotation.

Like I mentioned in the comment above the metadata looks incomplete, as there is no reference to the CoreModule of @abbazabacto/ngpackagr-issue/core:

{ "__symbolic": "module", "version": 4, "exports": [ { "from": "@abbazabacto/ngpackagr-issue/foo" } ], "metadata": {}, "origins": {}, "importAs": "@abbazabacto/ngpackagr-issue" }

If I remove the CoreModule import, the error disappears.

If I add the missing reference of @abbazabacto/ngpackagr-issue/core to the metadata file manually, the build also succeeds

{ "__symbolic": "module", "version": 4, "exports"

: [ { "from": "@abbazabacto/ngpackagr-issue/core" }, {

"from": "@abbazabacto/ngpackagr-issue/foo" } ], "metadata": {}, "origins": {}, "importAs": "@abbazabacto/ngpackagr-issue" }

The FooModule depends on the CoreModule, and FooService on the CORE_CONFIGa, CoreConfig and CoreService. I had a hunch it might be as of this dependency that the @abbazabacto/ngpackagr-issue/core is missing, but when I remove all inner dependencies the meta data still is still missing the reference to core

{ "__symbolic": "module", "version": 4, "exports": [ { "from": "@abbazabacto/ngpackagr-issue/foo" } ], "metadata": {}, "origins": {}, "importAs": "@abbazabacto/ngpackagr-issue" }

β€”

You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/dherges/ng-packagr/issues/900#issuecomment-393572087, or mute the thread https://github.com/notifications/unsubscribe-auth/AQv-WvYsfpbHYV5Dxgl_00qZrAJxZlbgks5t4A3PgaJpZM4UKJOk .

alan-agius4 avatar May 31 '18 15:05 alan-agius4

@alan-agius4 I just pushed the commits to master, added one more commit to update the README.md with the same issue description as above. Hope you can spot where the issue in metadata generation comes from. GL and thanks again!

abbazabacto avatar May 31 '18 16:05 abbazabacto

I had a look at this, and it seems to be an Angular bug. I have opened an issue: https://github.com/angular/angular/issues/24225

It looks like it's a problem with barrel exports.

alan-agius4 avatar May 31 '18 17:05 alan-agius4

Is there any intention on clarifying why placing package.json under the src folder works here? First, it is very commonplace and standard for the package.json to be at the root level of the package it is describing. Second, it's not intuitive that

root (abc/def)
|--package.json
|--ng-package.json
|--src
  |--main
    |--public_api.ts
    |--...
  |--secondary
    |--package.json
    |--public_api.ts
    |--...

produces the packages:

abc/def
abc/def/src/secondary

while

root (abc/def
|--src
  |--package.json
  |--ng-package.json
  |--main
    |--public_api.ts
    |--...
  |--secondary
    |--package.json
    |--public_api.ts
    |--...

produces the packages:

abc/def
abc/def/secondary

Issues with pathing and dependencies notwithstanding, the location of my source code does not change. Why does the location of the package.json file itself dictate package destinations?

My exact use case doesn't need a main module so I would rather have a package.json at the root that has a name of the common namespace (abc/def, in my example) and is completely independent from the packaged code itself and ng/package.json files in each of the feature modules that dictate how they would be packaged.

stweedie avatar Nov 05 '18 21:11 stweedie

Hey everyone, so I managed to compile my library without the use of a /src in the root but I had to make some changes that's worth mentioning. I followed the suggestion by @alan-agius4 to put secondary entry points at the root of the library. Also combined what I could gather from the Angular Package Format and the secondary entry points documentation. Notice the absence of a /src folder in my root directory.

My versions:

@angular-devkit/architect          0.803.25
@angular-devkit/build-angular      0.803.25
@angular-devkit/build-ng-packagr   0.803.25
@angular-devkit/build-optimizer    0.803.25
@angular-devkit/build-webpack      0.803.25
@angular-devkit/core               8.3.25
@angular-devkit/schematics         8.3.25
@angular/cli                       8.3.25
@ngtools/webpack                   8.3.25
@schematics/angular                8.3.25
@schematics/update                 0.803.25
ng-packagr                         5.7.1
rxjs                               6.4.0
typescript                         3.5.3
webpack                            4.39.2

The following is my library directory structure:

my-lib
β”œβ”€β”€ ng-package.json
β”œβ”€β”€ package.json
β”œβ”€β”€ public-api.ts
β”œβ”€β”€ test.ts
└── feature-1
    β”œβ”€β”€ src
    |   β”œβ”€β”€ public_api.ts
    |   └── *.ts
    └── package.json
└── feature-2
    β”œβ”€β”€ src
    |   β”œβ”€β”€ public_api.ts
    |   └── *.ts
    └── package.json
  • Inside my angular.json file, for my library project, i changed my sourceRoot from "project/my-lib/src" to "project/my-lib"
  • My package.json at the root of my library is:
{
  "name": "my-lib",
  "version": "0.0.1",
  "private": true,
  "peerDependencies": {
    "@angular/common": "^8.2.14",
    "@angular/core": "^8.2.14"
  },
  "ngPackage": {
    "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
    "dest": "../../dist/my-lib",
    "lib": {
      "entryFile": "./public-api.ts"
    }
  }
}
  • My ng-package.json at the root of my library is:
{
  "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
  "dest": "../../dist/my-lib",
  "lib": {
    "entryFile": "./public-api.ts"
  }
}

After I run ng build --project=my-lib, I get the following directory structure in dist/my-lib:

my-lib
β”œβ”€β”€ bundles (folder)
β”œβ”€β”€ esm5 (folder)
β”œβ”€β”€ esm2015 (folder)
β”œβ”€β”€ fesm5 (folder)
β”œβ”€β”€ fesm2015 (folder)
β”œβ”€β”€ feature-1 (folder)
β”œβ”€β”€ feature-2 (folder)
β”œβ”€β”€ my-lib.d.ts
β”œβ”€β”€ my-lib.metadata.json
β”œβ”€β”€ package.json
β”œβ”€β”€ public-api.d.ts
β”œβ”€β”€ README.md

Just as a side note as well, the public-api.ts at my root has the following code:

/*
 * Public API Surface of my-lib
 */

 export * from 'my-lib/feature-1';
 export * from 'my-lib/feature-2';

Hopefully this helps and I didn't miss out anything. Also my first time contributing.

Qarun-Qadir-Bissoondial avatar Feb 06 '20 14:02 Qarun-Qadir-Bissoondial

@Qarun-Qadir-Bissoondial

Inside my angular.json file, for my library project, i changed my sourceRoot from "project/my-lib/src" to "project/my-lib"

Don't forget testing:

        "test": {
          "builder": "@angular-devkit/build-angular:karma",
          "options": {
            "main": "projects/my-lib/test.ts",   <--------------- remove src/
            "tsConfig": "projects/my-lib/tsconfig.spec.json",
            "karmaConfig": "projects/my-lib/karma.conf.js"
          }
        },

I too have been fighting this for far too long. Your setup has gotten me the closest with only one annoyance, that that test.ts file shows up in test coverage reports. A small price to pay though.

CharlyRipp avatar Dec 07 '20 04:12 CharlyRipp

@CharlyRipp Hey, thanks for pointing out the testing to me. I honestly forgot it in my frustration. But I'm glad my setup helped you make progress :)

Qarun-Qadir-Bissoondial avatar Dec 07 '20 05:12 Qarun-Qadir-Bissoondial

One of the nice solutions mentioned in this issues is to move test.ts outside of src. A permanent change for this was pending for @angular-devkit/build-ng-packagr, but was lost in https://github.com/angular/devkit/pull/977 back in September 2018. Maybe you could take this change up again, @alan-agius4?

LayZeeDK avatar Dec 08 '20 18:12 LayZeeDK