feat(ngcc): support invalidating the entry-point manifest (#35931)
In some scenarios it is useful for the developer to indicate to ngcc that it should not use the entry-point manifest file, and instead write a new one. In the ngcc command line tool, this option is set by specfying ``` --invalidate-entry-point-manifest ``` PR Close #35931
This commit is contained in:
		
							parent
							
								
									ec9f4d5bc6
								
							
						
					
					
						commit
						8ea61a19cd
					
				| @ -76,6 +76,13 @@ if (require.main === module) { | |||||||
|             describe: 'The lowest severity logging message that should be output.', |             describe: 'The lowest severity logging message that should be output.', | ||||||
|             choices: ['debug', 'info', 'warn', 'error'], |             choices: ['debug', 'info', 'warn', 'error'], | ||||||
|           }) |           }) | ||||||
|  |           .option('invalidate-entry-point-manifest', { | ||||||
|  |             describe: | ||||||
|  |                 'If this is set then ngcc will not read an entry-point manifest file from disk.\n' + | ||||||
|  |                 'Instead it will walk the directory tree as normal looking for entry-points, and then write a new manifest file.', | ||||||
|  |             type: 'boolean', | ||||||
|  |             default: false, | ||||||
|  |           }) | ||||||
|           .strict() |           .strict() | ||||||
|           .help() |           .help() | ||||||
|           .parse(args); |           .parse(args); | ||||||
| @ -95,6 +102,7 @@ if (require.main === module) { | |||||||
|   const createNewEntryPointFormats = options['create-ivy-entry-points']; |   const createNewEntryPointFormats = options['create-ivy-entry-points']; | ||||||
|   const logLevel = options['l'] as keyof typeof LogLevel | undefined; |   const logLevel = options['l'] as keyof typeof LogLevel | undefined; | ||||||
|   const enableI18nLegacyMessageIdFormat = options['legacy-message-ids']; |   const enableI18nLegacyMessageIdFormat = options['legacy-message-ids']; | ||||||
|  |   const invalidateEntryPointManifest = options['invalidate-entry-point-manifest']; | ||||||
| 
 | 
 | ||||||
|   (async() => { |   (async() => { | ||||||
|     try { |     try { | ||||||
| @ -108,7 +116,7 @@ if (require.main === module) { | |||||||
|         createNewEntryPointFormats, |         createNewEntryPointFormats, | ||||||
|         logger, |         logger, | ||||||
|         enableI18nLegacyMessageIdFormat, |         enableI18nLegacyMessageIdFormat, | ||||||
|         async: options['async'], |         async: options['async'], invalidateEntryPointManifest, | ||||||
|       }); |       }); | ||||||
| 
 | 
 | ||||||
|       if (logger) { |       if (logger) { | ||||||
|  | |||||||
| @ -39,7 +39,7 @@ import {hasBeenProcessed} from './packages/build_marker'; | |||||||
| import {NgccConfiguration} from './packages/configuration'; | import {NgccConfiguration} from './packages/configuration'; | ||||||
| import {EntryPoint, EntryPointJsonProperty, EntryPointPackageJson, SUPPORTED_FORMAT_PROPERTIES, getEntryPointFormat} from './packages/entry_point'; | import {EntryPoint, EntryPointJsonProperty, EntryPointPackageJson, SUPPORTED_FORMAT_PROPERTIES, getEntryPointFormat} from './packages/entry_point'; | ||||||
| import {makeEntryPointBundle} from './packages/entry_point_bundle'; | import {makeEntryPointBundle} from './packages/entry_point_bundle'; | ||||||
| import {EntryPointManifest} from './packages/entry_point_manifest'; | import {EntryPointManifest, InvalidatingEntryPointManifest} from './packages/entry_point_manifest'; | ||||||
| import {Transformer} from './packages/transformer'; | import {Transformer} from './packages/transformer'; | ||||||
| import {PathMappings} from './utils'; | import {PathMappings} from './utils'; | ||||||
| import {cleanOutdatedPackages} from './writing/cleaning/package_cleaner'; | import {cleanOutdatedPackages} from './writing/cleaning/package_cleaner'; | ||||||
| @ -117,6 +117,15 @@ export interface SyncNgccOptions { | |||||||
|    * legacy message ids will all be stripped during translation. |    * legacy message ids will all be stripped during translation. | ||||||
|    */ |    */ | ||||||
|   enableI18nLegacyMessageIdFormat?: boolean; |   enableI18nLegacyMessageIdFormat?: boolean; | ||||||
|  | 
 | ||||||
|  |   /** | ||||||
|  |    * Whether to invalidate any entry-point manifest file that is on disk. Instead, walk the | ||||||
|  |    * directory tree looking for entry-points, and then write a new entry-point manifest, if | ||||||
|  |    * possible. | ||||||
|  |    * | ||||||
|  |    * Default: `false` (i.e. the manifest will be used if available) | ||||||
|  |    */ | ||||||
|  |   invalidateEntryPointManifest?: boolean; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
| @ -139,11 +148,12 @@ export type NgccOptions = AsyncNgccOptions | SyncNgccOptions; | |||||||
|  */ |  */ | ||||||
| export function mainNgcc(options: AsyncNgccOptions): Promise<void>; | export function mainNgcc(options: AsyncNgccOptions): Promise<void>; | ||||||
| export function mainNgcc(options: SyncNgccOptions): void; | export function mainNgcc(options: SyncNgccOptions): void; | ||||||
| export function mainNgcc( | export function mainNgcc({basePath, targetEntryPointPath, | ||||||
|     {basePath, targetEntryPointPath, propertiesToConsider = SUPPORTED_FORMAT_PROPERTIES, |                           propertiesToConsider = SUPPORTED_FORMAT_PROPERTIES, | ||||||
|                           compileAllFormats = true, createNewEntryPointFormats = false, |                           compileAllFormats = true, createNewEntryPointFormats = false, | ||||||
|                           logger = new ConsoleLogger(LogLevel.info), pathMappings, async = false, |                           logger = new ConsoleLogger(LogLevel.info), pathMappings, async = false, | ||||||
|      enableI18nLegacyMessageIdFormat = true}: NgccOptions): void|Promise<void> { |                           enableI18nLegacyMessageIdFormat = true, | ||||||
|  |                           invalidateEntryPointManifest = false}: NgccOptions): void|Promise<void> { | ||||||
|   // Execute in parallel, if async execution is acceptable and there are more than 1 CPU cores.
 |   // Execute in parallel, if async execution is acceptable and there are more than 1 CPU cores.
 | ||||||
|   const inParallel = async && (os.cpus().length > 1); |   const inParallel = async && (os.cpus().length > 1); | ||||||
| 
 | 
 | ||||||
| @ -154,7 +164,9 @@ export function mainNgcc( | |||||||
|   const absBasePath = absoluteFrom(basePath); |   const absBasePath = absoluteFrom(basePath); | ||||||
|   const config = new NgccConfiguration(fileSystem, dirname(absBasePath)); |   const config = new NgccConfiguration(fileSystem, dirname(absBasePath)); | ||||||
|   const dependencyResolver = getDependencyResolver(fileSystem, logger, config, pathMappings); |   const dependencyResolver = getDependencyResolver(fileSystem, logger, config, pathMappings); | ||||||
|   const entryPointManifest = new EntryPointManifest(fileSystem, config, logger); |   const entryPointManifest = invalidateEntryPointManifest ? | ||||||
|  |       new InvalidatingEntryPointManifest(fileSystem, config, logger) : | ||||||
|  |       new EntryPointManifest(fileSystem, config, logger); | ||||||
| 
 | 
 | ||||||
|   // Bail out early if the work is already done.
 |   // Bail out early if the work is already done.
 | ||||||
|   const supportedPropertiesToConsider = ensureSupportedProperties(propertiesToConsider); |   const supportedPropertiesToConsider = ensureSupportedProperties(propertiesToConsider); | ||||||
|  | |||||||
| @ -129,6 +129,18 @@ export class EntryPointManifest { | |||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /** | ||||||
|  |  * A specialized implementation of the `EntryPointManifest` that can be used to invalidate the | ||||||
|  |  * current manifest file. | ||||||
|  |  * | ||||||
|  |  * It always returns `null` from the `readEntryPointsUsingManifest()` method, which forces a new | ||||||
|  |  * manifest to be created, which will overwrite the current file when `writeEntryPointManifest()` is | ||||||
|  |  * called. | ||||||
|  |  */ | ||||||
|  | export class InvalidatingEntryPointManifest extends EntryPointManifest { | ||||||
|  |   readEntryPointsUsingManifest(basePath: AbsoluteFsPath): EntryPoint[]|null { return null; } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /** | /** | ||||||
|  * The JSON format of the manifest file that is written to disk. |  * The JSON format of the manifest file that is written to disk. | ||||||
|  */ |  */ | ||||||
|  | |||||||
| @ -7,22 +7,20 @@ | |||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| /// <reference types="node" />
 | /// <reference types="node" />
 | ||||||
| 
 |  | ||||||
| import * as os from 'os'; | import * as os from 'os'; | ||||||
| 
 |  | ||||||
| import {AbsoluteFsPath, FileSystem, absoluteFrom, getFileSystem, join} from '../../../src/ngtsc/file_system'; | import {AbsoluteFsPath, FileSystem, absoluteFrom, getFileSystem, join} from '../../../src/ngtsc/file_system'; | ||||||
| import {Folder, MockFileSystem, TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; | import {Folder, MockFileSystem, TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; | ||||||
| import {loadStandardTestFiles, loadTestFiles} from '../../../test/helpers'; | import {loadStandardTestFiles, loadTestFiles} from '../../../test/helpers'; | ||||||
| import {getLockFilePath} from '../../src/locking/lock_file'; | import {getLockFilePath} from '../../src/locking/lock_file'; | ||||||
| import {mainNgcc} from '../../src/main'; | import {mainNgcc} from '../../src/main'; | ||||||
| import {markAsProcessed} from '../../src/packages/build_marker'; | import {hasBeenProcessed, markAsProcessed} from '../../src/packages/build_marker'; | ||||||
| import {EntryPointJsonProperty, EntryPointPackageJson, SUPPORTED_FORMAT_PROPERTIES} from '../../src/packages/entry_point'; | import {EntryPointJsonProperty, EntryPointPackageJson, SUPPORTED_FORMAT_PROPERTIES} from '../../src/packages/entry_point'; | ||||||
|  | import {EntryPointManifestFile} from '../../src/packages/entry_point_manifest'; | ||||||
| import {Transformer} from '../../src/packages/transformer'; | import {Transformer} from '../../src/packages/transformer'; | ||||||
| import {DirectPackageJsonUpdater, PackageJsonUpdater} from '../../src/writing/package_json_updater'; | import {DirectPackageJsonUpdater, PackageJsonUpdater} from '../../src/writing/package_json_updater'; | ||||||
| import {MockLogger} from '../helpers/mock_logger'; | import {MockLogger} from '../helpers/mock_logger'; | ||||||
| import {compileIntoApf, compileIntoFlatEs5Package} from './util'; | import {compileIntoApf, compileIntoFlatEs5Package} from './util'; | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| const testFiles = loadStandardTestFiles({fakeCore: false, rxjs: true}); | const testFiles = loadStandardTestFiles({fakeCore: false, rxjs: true}); | ||||||
| 
 | 
 | ||||||
| runInEachFileSystem(() => { | runInEachFileSystem(() => { | ||||||
| @ -982,6 +980,46 @@ runInEachFileSystem(() => { | |||||||
|          }); |          }); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|  |     describe('with ignoreEntryPointManifest', () => { | ||||||
|  |       it('should not read the entry-point manifest file', () => { | ||||||
|  |         // Ensure there is a lock-file. Otherwise the manifest will not be written
 | ||||||
|  |         fs.writeFile(_('/yarn.lock'), 'DUMMY YARN LOCK FILE'); | ||||||
|  |         // Populate the manifest file
 | ||||||
|  |         mainNgcc( | ||||||
|  |             {basePath: '/node_modules', propertiesToConsider: ['esm5'], logger: new MockLogger()}); | ||||||
|  |         // Check that common/testings ES5 was processed
 | ||||||
|  |         let commonTesting = | ||||||
|  |             JSON.parse(fs.readFile(_('/node_modules/@angular/common/testing/package.json'))); | ||||||
|  |         expect(hasBeenProcessed(commonTesting, 'esm5')).toBe(true); | ||||||
|  |         expect(hasBeenProcessed(commonTesting, 'esm2015')).toBe(false); | ||||||
|  |         // Modify the manifest to test that is has no effect
 | ||||||
|  |         let manifest: EntryPointManifestFile = | ||||||
|  |             JSON.parse(fs.readFile(_('/node_modules/__ngcc_entry_points__.json'))); | ||||||
|  |         manifest.entryPointPaths = manifest.entryPointPaths.filter( | ||||||
|  |             paths => paths[1] !== _('/node_modules/@angular/common/testing')); | ||||||
|  |         fs.writeFile(_('/node_modules/__ngcc_entry_points__.json'), JSON.stringify(manifest)); | ||||||
|  |         // Now run ngcc again ignoring this manifest but trying to process ES2015, which are not yet
 | ||||||
|  |         // processed.
 | ||||||
|  |         mainNgcc({ | ||||||
|  |           basePath: '/node_modules', | ||||||
|  |           propertiesToConsider: ['esm2015'], | ||||||
|  |           logger: new MockLogger(), | ||||||
|  |           invalidateEntryPointManifest: true, | ||||||
|  |         }); | ||||||
|  |         // Check that common/testing ES2015 is now processed, despite the manifest not listing it
 | ||||||
|  |         commonTesting = | ||||||
|  |             JSON.parse(fs.readFile(_('/node_modules/@angular/common/testing/package.json'))); | ||||||
|  |         expect(hasBeenProcessed(commonTesting, 'esm5')).toBe(true); | ||||||
|  |         expect(hasBeenProcessed(commonTesting, 'esm2015')).toBe(true); | ||||||
|  |         // Check that the newly computed manifest has written to disk, containing the path that we
 | ||||||
|  |         // had removed earlier.
 | ||||||
|  |         manifest = JSON.parse(fs.readFile(_('/node_modules/__ngcc_entry_points__.json'))); | ||||||
|  |         expect(manifest.entryPointPaths).toContain([ | ||||||
|  |           _('/node_modules/@angular/common'), _('/node_modules/@angular/common/testing') | ||||||
|  |         ]); | ||||||
|  |       }); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|     describe('diagnostics', () => { |     describe('diagnostics', () => { | ||||||
|       it('should fail with formatted diagnostics when an error diagnostic is produced', () => { |       it('should fail with formatted diagnostics when an error diagnostic is produced', () => { | ||||||
|         loadTestFiles([ |         loadTestFiles([ | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user