Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ivy compiler doesn't work with secondary entry points in libraries using dist folder #35188

Closed
jeripeierSBB opened this issue Feb 6, 2020 · 6 comments

Comments

@jeripeierSBB
Copy link
Contributor

jeripeierSBB commented Feb 6, 2020

🐞 bug report

Affected Package

@angular/compiler@9.0.0 (ngcc)

Is this a regression?

Not known

Description

We have a monorepo managed with the Angular CLI with several libraries, each with secondary entry points, and a showcase. We build the libraries using the ViewEngine compiler and the showcase with Ivy. Once we build the showcase, Ivy seems to fail to compile imported symbols in secondary entry points, which results in the error code NG6002 (See error below).

We used the following guide for secondary entry points: https://github.com/ng-packagr/ng-packagr/blob/v9.0.0/docs/secondary-entrypoints.md
The built library artifacts reside in the dist folder (default Angular CLI configuration)

Strangely enough, when we copy the build artifacts into node_modules and remove the compilerOptions.paths entry in tsconfig.json, ngcc seems to compile it successfully.
If we leave it in dist, ngcc seems to stop compiling secondary entrypoints after the first/entry file.

🔬 Minimal Reproduction

  1. clone https://github.com/jeripeierSBB/lib-with-secondary-entry-points
  2. ng build my-lib --prod
  3. ng build showcase --prod (or ng serve)

🔥 Exception or Error


ERROR in dist/my-lib/my-feature/my-feature.module.d.ts:1:22 - error NG6002: Appears in the NgModule.imports of AppModule, but could not be resolved to an NgModule class

1 export declare class MyFeatureModule {

🌍 Your Environment

Angular Version:


Angular CLI: 9.0.0
Node: 13.7.0
OS: darwin x64

Angular: 9.0.0
... animations, cli, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router
Ivy Workspace: Yes

Package                            Version
------------------------------------------------------------
@angular-devkit/architect          0.900.0
@angular-devkit/build-angular      0.900.0
@angular-devkit/build-ng-packagr   0.900.0
@angular-devkit/build-optimizer    0.900.0
@angular-devkit/build-webpack      0.900.0
@angular-devkit/core               9.0.0
@angular-devkit/schematics         9.0.0
@ngtools/webpack                   9.0.0
@schematics/angular                9.0.0
@schematics/update                 0.900.0
ng-packagr                         9.0.0
rxjs                               6.5.4
typescript                         3.7.5
webpack                            4.41.2

Anything else relevant?

Workaround

  1. ng build my-lib --prod
  2. copy content of dist folder to node_modules
  3. remove compilerOptions.paths in tsconfig.json
  4. ng build showcase --prod (or ng serve)
  5. compiles successfully
@pkozlowski-opensource pkozlowski-opensource added the area: compiler Issues related to `ngc`, Angular's template compiler label Feb 6, 2020
@ngbot ngbot bot added this to the needsTriage milestone Feb 6, 2020
@jeripeierSBB
Copy link
Contributor Author

updated this issue and reproduction from Angular version 9.0.0-rc.14 to version 9.0.0

@petebacondarwin
Copy link
Member

This is a bug in our TargetedEntryPointFinder inside the computePackagePath() function, shown below for reference. The problem is that when the target is my-lib/my-feature it computes that the package path is my-lib/my-feature rather than my-lib.

This leads to ngcc creating the special "ngcc folder" that contains the processed files in the secondary entry-point rather than the primary package folder, which is where the CLI build is configured to look for it. In other words we create lib-with-secondary-entry-points/dist/my-lib/my-feature/__ivy_ngcc__ rather than lib-with-secondary-entry-points/dist/my-lib/__ivy_ngcc__.

/**
* Search down to the `entryPointPath` from each `basePath` for the first `package.json` that we
* come to. This is the path to the entry-point's containing package. For example if `basePath` is
* `/a/b/c` and `entryPointPath` is `/a/b/c/d/e` and there exists `/a/b/c/d/package.json` and
* `/a/b/c/d/e/package.json`, then we will return `/a/b/c/d`.
*
* To account for nested `node_modules` we actually start the search at the last `node_modules` in
* the `entryPointPath` that is below the `basePath`. E.g. if `basePath` is `/a/b/c` and
* `entryPointPath` is `/a/b/c/d/node_modules/x/y/z`, we start the search at
* `/a/b/c/d/node_modules`.
*/
private computePackagePath(entryPointPath: AbsoluteFsPath): AbsoluteFsPath {
for (const basePath of this.basePaths) {
if (entryPointPath.startsWith(basePath)) {
let packagePath = basePath;
const segments = this.splitPath(relative(basePath, entryPointPath));
// Start the search at the last nested `node_modules` folder if the relative
// `entryPointPath` contains one or more.
let nodeModulesIndex = segments.lastIndexOf(relativeFrom('node_modules'));
while (nodeModulesIndex >= 0) {
packagePath = join(packagePath, segments.shift() !);
nodeModulesIndex--;
}
// Note that we skip the first `packagePath` and start looking from the first folder below
// it because that will be the `node_modules` folder.
for (const segment of segments) {
packagePath = join(packagePath, segment);
if (this.fs.exists(join(packagePath, 'package.json'))) {
return packagePath;
}
}
// If we got here then we couldn't find a `packagePath` for the current `basePath` but since
// `basePath`s are guaranteed not to be a sub-directory each other then no other `basePath`
// will match either.
break;
}
}
// If we get here then none of the `basePaths` matched the `entryPointPath`, which
// is somewhat unexpected and means that this entry-point lives completely outside
// any of the `basePaths`.
// All we can do is assume that his entry-point is a primary entry-point to a package.
return entryPointPath;
}

petebacondarwin added a commit to petebacondarwin/angular that referenced this issue Feb 7, 2020
…ed correctly

The `TargetedEntryPointFinder` must work out what the
containing package is for each entry-point that it finds.

The logic for doing this was flawed in the case that the
package was in a path-mapped directory and not in a
node_modules folder. This meant that secondary entry-points
were incorrectly setting their own path as the package
path, rather than the primary entry-point path.

Fixes angular#35188
@petebacondarwin
Copy link
Member

Hopefully #35227 will fix this. I am just building and trying out on the reproduction from above.

@petebacondarwin
Copy link
Member

I can confirm that, locally, this PR fixes the repro.

@jeripeierSBB
Copy link
Contributor Author

@petebacondarwin Many Thanks, looking forward to the release :-)

@petebacondarwin petebacondarwin added comp: ngcc state: has PR and removed area: compiler Issues related to `ngc`, Angular's template compiler labels Feb 7, 2020
kara pushed a commit that referenced this issue Feb 7, 2020
…ed correctly (#35227)

The `TargetedEntryPointFinder` must work out what the
containing package is for each entry-point that it finds.

The logic for doing this was flawed in the case that the
package was in a path-mapped directory and not in a
node_modules folder. This meant that secondary entry-points
were incorrectly setting their own path as the package
path, rather than the primary entry-point path.

Fixes #35188

PR Close #35227
@kara kara closed this as completed in 54c3a5d Feb 7, 2020
sonukapoor pushed a commit to sonukapoor/angular that referenced this issue Feb 13, 2020
…ed correctly (angular#35227)

The `TargetedEntryPointFinder` must work out what the
containing package is for each entry-point that it finds.

The logic for doing this was flawed in the case that the
package was in a path-mapped directory and not in a
node_modules folder. This meant that secondary entry-points
were incorrectly setting their own path as the package
path, rather than the primary entry-point path.

Fixes angular#35188

PR Close angular#35227
sonukapoor pushed a commit to sonukapoor/angular that referenced this issue Feb 17, 2020
…ed correctly (angular#35227)

The `TargetedEntryPointFinder` must work out what the
containing package is for each entry-point that it finds.

The logic for doing this was flawed in the case that the
package was in a path-mapped directory and not in a
node_modules folder. This meant that secondary entry-points
were incorrectly setting their own path as the package
path, rather than the primary entry-point path.

Fixes angular#35188

PR Close angular#35227
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Mar 9, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.