fix(migrations): migrate HttpClientModule to provideHttpClient() (#48949)

The `standalone-bootstrap` migration now migrates `HttpClientModule` imports to `provideHttpClient(withInterceptorsFromDi())` instead of `importProvidersFrom(HttpClientModule)`.

The `withInterceptorsFromDi()` feature is added to make sure class-based interceptors still works if there are any in the application.

Fixes #48948

PR Close #48949
This commit is contained in:
cexbrayat 2023-02-03 18:21:10 +01:00 committed by Alex Rickabaugh
parent 323ffc98eb
commit 660fbf5d27
2 changed files with 63 additions and 0 deletions

View file

@ -308,6 +308,22 @@ function migrateImportsForBootstrapCall(
tracker.addImport(sourceFile, 'provideNoopAnimations', animationsImport), [], []));
continue;
}
// `HttpClientModule` can be replaced with `provideHttpClient()`.
const httpClientModule = 'common/http';
const httpClientImport = `@angular/${httpClientModule}`;
if (isClassReferenceInAngularModule(
element, 'HttpClientModule', httpClientModule, typeChecker)) {
const callArgs = [
// we add `withInterceptorsFromDi()` to the call to ensure that class-based interceptors
// still work
ts.factory.createCallExpression(
tracker.addImport(sourceFile, 'withInterceptorsFromDi', httpClientImport), [], [])
];
providersInNewCall.push(ts.factory.createCallExpression(
tracker.addImport(sourceFile, 'provideHttpClient', httpClientImport), [], callArgs));
continue;
}
}
const target =

View file

@ -124,6 +124,16 @@ describe('standalone migration', () => {
}
`);
writeFile('/node_modules/@angular/common/http/index.d.ts', `
import {ModuleWithProviders} from '@angular/core';
export declare class HttpClientModule {
static ɵfac: i0.ɵɵFactoryDeclaration<HttpClientModule, never>;
static ɵmod: i0.ɵɵNgModuleDeclaration<HttpClientModule, never, never, never>;
static ɵinj: i0.ɵɵInjectorDeclaration<HttpClientModule>;
}
`);
writeFile('/node_modules/@angular/core/testing/index.d.ts', `
export declare class TestBed {
static configureTestingModule(config: any): any;
@ -3393,6 +3403,43 @@ describe('standalone migration', () => {
`));
});
it('should convert HttpClientModule references to provideHttpClient(withInterceptorsFromDi())',
async () => {
writeFile('main.ts', `
import {AppModule} from './app/app.module';
import {platformBrowser} from '@angular/platform-browser';
platformBrowser().bootstrapModule(AppModule).catch(e => console.error(e));
`);
writeFile('./app/app.module.ts', `
import {NgModule, Component} from '@angular/core';
import {HttpClientModule} from '@angular/common/http';
@Component({template: 'hello'})
export class AppComponent {}
@NgModule({
declarations: [AppComponent],
bootstrap: [AppComponent],
imports: [HttpClientModule]
})
export class AppModule {}
`);
await runMigration('standalone-bootstrap');
expect(stripWhitespace(tree.readContent('main.ts'))).toBe(stripWhitespace(`
import {AppComponent} from './app/app.module';
import {platformBrowser, bootstrapApplication} from '@angular/platform-browser';
import {withInterceptorsFromDi, provideHttpClient} from '@angular/common/http';
bootstrapApplication(AppComponent, {
providers: [provideHttpClient(withInterceptorsFromDi())]
}).catch(e => console.error(e));
`));
});
it('should omit standalone directives from the imports array from the importProvidersFrom call',
async () => {
writeFile('main.ts', `