feat(ivy): ngcc - support only compiling the first format property to match (#29092)
By default ngcc will compile all the format properties specified. With this change you can configure ngcc so that it will stop compiling an entry-point after the first property that matches the `propertiesToConsider`. PR Close #29092
This commit is contained in:
parent
c9f7cdaafd
commit
229f035969
|
@ -38,6 +38,11 @@ if (require.main === module) {
|
|||
alias: 'target',
|
||||
describe: 'A path to a single entry-point to compile (plus its dependencies).',
|
||||
})
|
||||
.option('first-only', {
|
||||
describe:
|
||||
'If specified then only the first matching package.json property will be compiled',
|
||||
type: 'boolean'
|
||||
})
|
||||
.help()
|
||||
.parse(args);
|
||||
|
||||
|
@ -50,8 +55,9 @@ if (require.main === module) {
|
|||
const propertiesToConsider: EntryPointJsonProperty[] = options['p'];
|
||||
const targetEntryPointPath =
|
||||
options['t'] ? AbsoluteFsPath.from(path.resolve(options['t'])) : undefined;
|
||||
const compileAllFormats = !options['first-only'];
|
||||
try {
|
||||
mainNgcc({baseSourcePath, propertiesToConsider, targetEntryPointPath});
|
||||
mainNgcc({baseSourcePath, propertiesToConsider, targetEntryPointPath, compileAllFormats});
|
||||
process.exitCode = 0;
|
||||
} catch (e) {
|
||||
console.error(e.stack || e.message);
|
||||
|
|
|
@ -31,6 +31,11 @@ export interface NgccOptions {
|
|||
* Each of properties contain a path to particular bundle format for a given entry-point.
|
||||
*/
|
||||
propertiesToConsider?: EntryPointJsonProperty[];
|
||||
/**
|
||||
* Whether to compile all specified formats or to stop compiling this entry-point at the first
|
||||
* matching format. Defaults to `true`.
|
||||
*/
|
||||
compileAllFormats?: boolean;
|
||||
}
|
||||
|
||||
const SUPPORTED_FORMATS: EntryPointFormat[] = ['esm5', 'esm2015'];
|
||||
|
@ -43,8 +48,8 @@ const SUPPORTED_FORMATS: EntryPointFormat[] = ['esm5', 'esm2015'];
|
|||
*
|
||||
* @param options The options telling ngcc what to compile and how.
|
||||
*/
|
||||
export function mainNgcc({baseSourcePath, targetEntryPointPath, propertiesToConsider}: NgccOptions):
|
||||
void {
|
||||
export function mainNgcc({baseSourcePath, targetEntryPointPath, propertiesToConsider,
|
||||
compileAllFormats = true}: NgccOptions): void {
|
||||
const transformer = new Transformer(baseSourcePath, baseSourcePath);
|
||||
const host = new DependencyHost();
|
||||
const resolver = new DependencyResolver(host);
|
||||
|
@ -74,7 +79,9 @@ export function mainNgcc({baseSourcePath, targetEntryPointPath, propertiesToCons
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!compiledFormats.has(formatPath)) {
|
||||
// We don't break if this if statement fails because we still want to mark
|
||||
// the property as processed even if its underlying format has been built already.
|
||||
if (!compiledFormats.has(formatPath) && (compileAllFormats || compiledFormats.size === 0)) {
|
||||
const bundle = makeEntryPointBundle(
|
||||
entryPoint.path, formatPath, entryPoint.typings, isCore, format,
|
||||
compiledFormats.size === 0);
|
||||
|
@ -86,7 +93,7 @@ export function mainNgcc({baseSourcePath, targetEntryPointPath, propertiesToCons
|
|||
console.warn(
|
||||
`Skipping ${entryPoint.name} : ${format} (no valid entry point file for this format).`);
|
||||
}
|
||||
} else {
|
||||
} else if (!compileAllFormats) {
|
||||
console.warn(`Skipping ${entryPoint.name} : ${property} (already compiled).`);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,57 +31,106 @@ describe('ngcc main()', () => {
|
|||
.not.toThrow();
|
||||
});
|
||||
|
||||
it('should only compile the given package entry-point (and its dependencies)', () => {
|
||||
mainNgcc({
|
||||
baseSourcePath: NODE_MODULES,
|
||||
targetEntryPointPath: AbsoluteFsPath.from(`${NODE_MODULES}/@angular/common/http`)
|
||||
});
|
||||
describe('with targetEntryPointPath', () => {
|
||||
it('should only compile the given package entry-point (and its dependencies).', () => {
|
||||
mainNgcc({
|
||||
baseSourcePath: NODE_MODULES,
|
||||
targetEntryPointPath: AbsoluteFsPath.from('/node_modules/@angular/common/http')
|
||||
});
|
||||
|
||||
expect(loadPackage('@angular/common/http').__modified_by_ngcc__).toEqual({
|
||||
module: '0.0.0-PLACEHOLDER',
|
||||
es2015: '0.0.0-PLACEHOLDER',
|
||||
esm5: '0.0.0-PLACEHOLDER',
|
||||
esm2015: '0.0.0-PLACEHOLDER',
|
||||
fesm5: '0.0.0-PLACEHOLDER',
|
||||
fesm2015: '0.0.0-PLACEHOLDER'
|
||||
expect(loadPackage('@angular/common/http').__modified_by_ngcc__).toEqual({
|
||||
module: '0.0.0-PLACEHOLDER',
|
||||
es2015: '0.0.0-PLACEHOLDER',
|
||||
esm5: '0.0.0-PLACEHOLDER',
|
||||
esm2015: '0.0.0-PLACEHOLDER',
|
||||
fesm5: '0.0.0-PLACEHOLDER',
|
||||
fesm2015: '0.0.0-PLACEHOLDER',
|
||||
});
|
||||
// * `common` is a dependency of `common/http`, so is compiled.
|
||||
expect(loadPackage('@angular/common').__modified_by_ngcc__).toEqual({
|
||||
module: '0.0.0-PLACEHOLDER',
|
||||
es2015: '0.0.0-PLACEHOLDER',
|
||||
esm5: '0.0.0-PLACEHOLDER',
|
||||
esm2015: '0.0.0-PLACEHOLDER',
|
||||
fesm5: '0.0.0-PLACEHOLDER',
|
||||
fesm2015: '0.0.0-PLACEHOLDER',
|
||||
});
|
||||
// * `core` is a dependency of `common`, so is compiled.
|
||||
expect(loadPackage('@angular/core').__modified_by_ngcc__).toEqual({
|
||||
module: '0.0.0-PLACEHOLDER',
|
||||
es2015: '0.0.0-PLACEHOLDER',
|
||||
esm5: '0.0.0-PLACEHOLDER',
|
||||
esm2015: '0.0.0-PLACEHOLDER',
|
||||
fesm5: '0.0.0-PLACEHOLDER',
|
||||
fesm2015: '0.0.0-PLACEHOLDER',
|
||||
});
|
||||
|
||||
// * `common/testing` is not a dependency of `common/http` so is not compiled.
|
||||
expect(loadPackage('@angular/common/testing').__modified_by_ngcc__).toBeUndefined();
|
||||
});
|
||||
expect(loadPackage('@angular/common').__modified_by_ngcc__).toEqual({
|
||||
module: '0.0.0-PLACEHOLDER',
|
||||
es2015: '0.0.0-PLACEHOLDER',
|
||||
esm5: '0.0.0-PLACEHOLDER',
|
||||
esm2015: '0.0.0-PLACEHOLDER',
|
||||
fesm5: '0.0.0-PLACEHOLDER',
|
||||
fesm2015: '0.0.0-PLACEHOLDER'
|
||||
});
|
||||
expect(loadPackage('@angular/core').__modified_by_ngcc__).toEqual({
|
||||
module: '0.0.0-PLACEHOLDER',
|
||||
es2015: '0.0.0-PLACEHOLDER',
|
||||
esm5: '0.0.0-PLACEHOLDER',
|
||||
esm2015: '0.0.0-PLACEHOLDER',
|
||||
fesm5: '0.0.0-PLACEHOLDER',
|
||||
fesm2015: '0.0.0-PLACEHOLDER'
|
||||
});
|
||||
expect(loadPackage('@angular/common/testing').__modified_by_ngcc__).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should only build the format properties specified for each entry-point', () => {
|
||||
mainNgcc({baseSourcePath: NODE_MODULES, propertiesToConsider: ['main', 'esm5', 'module']});
|
||||
describe('with propertiesToConsider', () => {
|
||||
it('should only compile the entry-point formats given in the `propertiesToConsider` list',
|
||||
() => {
|
||||
mainNgcc({
|
||||
baseSourcePath: NODE_MODULES,
|
||||
propertiesToConsider: ['main', 'esm5', 'module', 'fesm5']
|
||||
});
|
||||
|
||||
expect(loadPackage('@angular/core').__modified_by_ngcc__).toEqual({
|
||||
esm5: '0.0.0-PLACEHOLDER',
|
||||
module: '0.0.0-PLACEHOLDER',
|
||||
});
|
||||
expect(loadPackage('@angular/common').__modified_by_ngcc__).toEqual({
|
||||
esm5: '0.0.0-PLACEHOLDER',
|
||||
module: '0.0.0-PLACEHOLDER',
|
||||
});
|
||||
expect(loadPackage('@angular/common/testing').__modified_by_ngcc__).toEqual({
|
||||
esm5: '0.0.0-PLACEHOLDER',
|
||||
module: '0.0.0-PLACEHOLDER',
|
||||
});
|
||||
expect(loadPackage('@angular/common/http').__modified_by_ngcc__).toEqual({
|
||||
esm5: '0.0.0-PLACEHOLDER',
|
||||
module: '0.0.0-PLACEHOLDER',
|
||||
// * the `main` property is UMD, which is not yet supported.
|
||||
// * none of the ES2015 formats are compiled as they are not on the `propertiesToConsider`
|
||||
// list.
|
||||
expect(loadPackage('@angular/core').__modified_by_ngcc__).toEqual({
|
||||
esm5: '0.0.0-PLACEHOLDER',
|
||||
module: '0.0.0-PLACEHOLDER',
|
||||
fesm5: '0.0.0-PLACEHOLDER',
|
||||
});
|
||||
expect(loadPackage('@angular/common').__modified_by_ngcc__).toEqual({
|
||||
esm5: '0.0.0-PLACEHOLDER',
|
||||
module: '0.0.0-PLACEHOLDER',
|
||||
fesm5: '0.0.0-PLACEHOLDER',
|
||||
});
|
||||
expect(loadPackage('@angular/common/testing').__modified_by_ngcc__).toEqual({
|
||||
esm5: '0.0.0-PLACEHOLDER',
|
||||
module: '0.0.0-PLACEHOLDER',
|
||||
fesm5: '0.0.0-PLACEHOLDER',
|
||||
});
|
||||
expect(loadPackage('@angular/common/http').__modified_by_ngcc__).toEqual({
|
||||
esm5: '0.0.0-PLACEHOLDER',
|
||||
module: '0.0.0-PLACEHOLDER',
|
||||
fesm5: '0.0.0-PLACEHOLDER',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('with compileAllFormats set to false', () => {
|
||||
it('should only compile the first matching format', () => {
|
||||
mainNgcc({
|
||||
baseSourcePath: NODE_MODULES,
|
||||
propertiesToConsider: ['main', 'module', 'fesm5', 'esm5'],
|
||||
compileAllFormats: false
|
||||
});
|
||||
// * The `main` is UMD, which is not yet supported, and so is not compiled.
|
||||
// * In the Angular packages fesm5 and module have the same underlying format,
|
||||
// so both are marked as compiled.
|
||||
// * The `esm5` is not compiled because we stopped after the `fesm5` format.
|
||||
expect(loadPackage('@angular/core').__modified_by_ngcc__).toEqual({
|
||||
fesm5: '0.0.0-PLACEHOLDER',
|
||||
module: '0.0.0-PLACEHOLDER',
|
||||
});
|
||||
expect(loadPackage('@angular/common').__modified_by_ngcc__).toEqual({
|
||||
fesm5: '0.0.0-PLACEHOLDER',
|
||||
module: '0.0.0-PLACEHOLDER',
|
||||
});
|
||||
expect(loadPackage('@angular/common/testing').__modified_by_ngcc__).toEqual({
|
||||
fesm5: '0.0.0-PLACEHOLDER',
|
||||
module: '0.0.0-PLACEHOLDER',
|
||||
});
|
||||
expect(loadPackage('@angular/common/http').__modified_by_ngcc__).toEqual({
|
||||
fesm5: '0.0.0-PLACEHOLDER',
|
||||
module: '0.0.0-PLACEHOLDER',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -135,6 +184,12 @@ interface Directory {
|
|||
[pathSegment: string]: string|Directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* A mock implementation of the node.js Module._resolveFilename function,
|
||||
* which we are spying on to support mocking out the file-system in these tests.
|
||||
*
|
||||
* @param request the path to a module that needs resolving.
|
||||
*/
|
||||
function mockResolve(request: string): string|null {
|
||||
if (existsSync(request)) {
|
||||
const stat = statSync(request);
|
||||
|
|
Loading…
Reference in New Issue