fix(ngcc): correctly identify the package path of secondary entry-points (#36249)
Previously we only searched for package paths below the set of `basePaths` that were computed from the `basePath` provided to ngcc and the set of `pathMappings`. In some scenarios, such as hoisted packages, the entry-point is not within any of the `basePaths` identified above. For example: ``` project packages app node_modules app-lib (depends on lib1) node_modules lib1 (depends on lib2) node_modules lib2 (depends on lib3/entry-point) lib3 entry-point ``` When CLI is compiling `app-lib` ngcc will be given `project/packages/app/node_modules` as the `basePath. If ngcc is asked to target `lib2`, the `targetPath` will be `project/node_modules/lib1/node_modules/lib2`. Since `lib2` depends upon `lib3/entry-point`, ngcc will need to compute the package path for `project/node_modules/lib3/entry-point`. Since `project/node_modules/lib3/entry-point` is not contained in the `basePath` `project/packages/app/node_modules`, ngcc failed to compute the `packagePath` correctly, instead assuming that it was the same as the entry-point path. Now we also consider the nearest `node_modules` folder to the entry-point path as an additional `basePath`. If one is found then we use the first directory directly below that `node_modules` directory as the package path. In the case of our example this extra `basePath` would be `project/node_modules` which allows us to compute the `packagePath` of `project/node_modules/lib3`. Fixes #35747 PR Close #36249
This commit is contained in:

committed by
Alex Rickabaugh

parent
5c28af0e74
commit
e53b686375
@ -150,13 +150,35 @@ export class TargetedEntryPointFinder implements EntryPointFinder {
|
||||
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;
|
||||
}
|
||||
|
||||
// We couldn't find a `packagePath` using `basePaths` so try to find the nearest `node_modules`
|
||||
// that contains the `entryPointPath`, if there is one, and use it as a `basePath`.
|
||||
let packagePath = entryPointPath;
|
||||
let scopedPackagePath = packagePath;
|
||||
let containerPath = this.fs.dirname(packagePath);
|
||||
while (!this.fs.isRoot(containerPath) && !containerPath.endsWith('node_modules')) {
|
||||
scopedPackagePath = packagePath;
|
||||
packagePath = containerPath;
|
||||
containerPath = this.fs.dirname(containerPath);
|
||||
}
|
||||
|
||||
if (this.fs.exists(join(packagePath, 'package.json'))) {
|
||||
// The directory directly below `node_modules` is a package - use it
|
||||
return packagePath;
|
||||
} else if (
|
||||
this.fs.basename(packagePath).startsWith('@') &&
|
||||
this.fs.exists(join(scopedPackagePath, 'package.json'))) {
|
||||
// The directory directly below the `node_modules` is a scope and the directory directly
|
||||
// below that is a scoped package - use it
|
||||
return scopedPackagePath;
|
||||
} else {
|
||||
// If we get here then none of the `basePaths` contained the `entryPointPath` and the
|
||||
// `entryPointPath` contains no `node_modules` that contains a package or a scoped
|
||||
// package. All we can do is assume that this entry-point is a primary entry-point to a
|
||||
// package.
|
||||
return entryPointPath;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Split the given `path` into path segments using an FS independent algorithm.
|
||||
|
@ -30,7 +30,7 @@ import {PathMappings} from '../utils';
|
||||
export function getBasePaths(
|
||||
sourceDirectory: AbsoluteFsPath, pathMappings: PathMappings | undefined): AbsoluteFsPath[] {
|
||||
const fs = getFileSystem();
|
||||
let basePaths = [sourceDirectory];
|
||||
const basePaths = [sourceDirectory];
|
||||
if (pathMappings) {
|
||||
const baseUrl = resolve(pathMappings.baseUrl);
|
||||
Object.values(pathMappings.paths).forEach(paths => paths.forEach(path => {
|
||||
|
Reference in New Issue
Block a user