fix(core): undecorated-classes-with-di migration should handle libraries generated with CLI versions past v6.2.0 (#35824)
The options for `flatModuleId` and `flatModuleOutFile` had been removed in the CLI
from generated libraries with 718ee15b9a
.
This has been done because `ng-packagr` (which is used to build the
libraries) automatically set these options in-memory when it compiles the library.
No migration has been created for this because there was no actual need to get rid of
this. Keeping the options in the library `tsconfig` does not cause any problems unless
the `tsconfig` is used outside of `ng-packagr`. This was not anticipated, but is now
commonly done in `ng update` migrations.
The `ng update` migrations try to create an instance of the `AngularCompilerProgram` by
simply parsing the `tsconfig`. The migrations make the valid assumption that `tsconfig` files
are not incomplete/invalid. They _definitely_ are in the file system though. It just works for
libraries because `ng-packagr` in-memory completes the invalid `tsconfig` files, so that they
can be passed to the `@angular/compiler-cli`.
We can't have this logic in the `ng update` migrations because it's
out-of-scope for individual migrations to distinguish between libraries
and applications. Also it would be out-of-scope to parse the
`ng-packagr` configuration and handle the tsconfig in-memory completion.
As a workaround though, we can remove the flat-module bundle options
in-memory when creating the compiler program. This is acceptable since
we don't emit the program and the flat module bundles are not needed.
Fixes #34985.
PR Close #35824
This commit is contained in:
parent
bef14cf424
commit
59607dc495
@ -20,6 +20,19 @@ export function createNgcProgram(
|
|||||||
// NGC program. In order to ensure that the migration runs properly, we set "enableIvy" to false.
|
// NGC program. In order to ensure that the migration runs properly, we set "enableIvy" to false.
|
||||||
options.enableIvy = false;
|
options.enableIvy = false;
|
||||||
|
|
||||||
|
// Libraries which have been generated with CLI versions past v6.2.0, explicitly set the
|
||||||
|
// flat-module options in their tsconfig files. This is problematic because by default,
|
||||||
|
// those tsconfig files do not specify explicit source files which can be considered as
|
||||||
|
// entry point for the flat-module bundle. Therefore the `@angular/compiler-cli` is unable
|
||||||
|
// to determine the flat module entry point and throws a compile error. This is not an issue
|
||||||
|
// for the libraries built with `ng-packagr`, because the tsconfig files are modified in-memory
|
||||||
|
// to specify an explicit flat module entry-point. Our migrations don't distinguish between
|
||||||
|
// libraries and applications, and also don't run `ng-packagr`. To ensure that such libraries
|
||||||
|
// can be successfully migrated, we remove the flat-module options to eliminate the flat module
|
||||||
|
// entry-point requirement. More context: https://github.com/angular/angular/issues/34985.
|
||||||
|
options.flatModuleId = undefined;
|
||||||
|
options.flatModuleOutFile = undefined;
|
||||||
|
|
||||||
const host = createHost(options);
|
const host = createHost(options);
|
||||||
|
|
||||||
// For this migration, we never need to read resources and can just return
|
// For this migration, we never need to read resources and can just return
|
||||||
|
@ -1473,6 +1473,40 @@ describe('Undecorated classes with DI migration', () => {
|
|||||||
'TypeScript program failures');
|
'TypeScript program failures');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Regression test for: https://github.com/angular/angular/issues/34985.
|
||||||
|
it('should be able to migrate libraries with multiple source files and flat-module ' +
|
||||||
|
'options set',
|
||||||
|
async() => {
|
||||||
|
writeFile('/tsconfig.json', JSON.stringify({
|
||||||
|
compilerOptions: {
|
||||||
|
lib: ['es2015'],
|
||||||
|
},
|
||||||
|
angularCompilerOptions:
|
||||||
|
{flatModuleId: 'AUTOGENERATED', flatModuleOutFile: 'AUTOGENERATED'}
|
||||||
|
}));
|
||||||
|
|
||||||
|
writeFile('/second.ts', ``);
|
||||||
|
writeFile('/test.ts', `
|
||||||
|
import {Injectable, NgModule, NgZone} from '@angular/core';
|
||||||
|
|
||||||
|
export class BaseClass {
|
||||||
|
constructor(zone: NgZone) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable({template: ''})
|
||||||
|
export class MyService extends BaseClass {}
|
||||||
|
|
||||||
|
@NgModule({providers: [MyService]})
|
||||||
|
export class AppModule {}
|
||||||
|
`);
|
||||||
|
|
||||||
|
await runMigration();
|
||||||
|
|
||||||
|
expect(errorOutput.length).toBe(0);
|
||||||
|
expect(warnOutput.length).toBe(0);
|
||||||
|
expect(tree.readContent('/test.ts')).toMatch(/@Injectable\(\)\nexport class BaseClass {/);
|
||||||
|
});
|
||||||
|
|
||||||
it('should not throw if resources could not be read', async() => {
|
it('should not throw if resources could not be read', async() => {
|
||||||
writeFile('/index.ts', `
|
writeFile('/index.ts', `
|
||||||
import {Component, NgModule} from '@angular/core';
|
import {Component, NgModule} from '@angular/core';
|
||||||
|
Loading…
x
Reference in New Issue
Block a user