From f626b19d28914809730239523c699bfd7a389403 Mon Sep 17 00:00:00 2001 From: Paul Gammans Date: Thu, 23 Apr 2020 16:17:33 +0100 Subject: [PATCH] fix(router): fix change in behaviour on load error occur Clear the stored loader promise so that subsequent load will try the fetch again. The restores the same behaviour as before we cached the loader to fix #26557 --- packages/router/src/router_config_loader.ts | 6 ++- packages/router/test/router_preloader.spec.ts | 53 +++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/packages/router/src/router_config_loader.ts b/packages/router/src/router_config_loader.ts index 5413e2d493958..88dc48505f770 100644 --- a/packages/router/src/router_config_loader.ts +++ b/packages/router/src/router_config_loader.ts @@ -8,7 +8,7 @@ import {Compiler, InjectionToken, Injector, NgModuleFactory, NgModuleFactoryLoader} from '@angular/core'; import {from, Observable, of} from 'rxjs'; -import {map, mergeMap, share, tap} from 'rxjs/operators'; +import {catchError, map, mergeMap, share} from 'rxjs/operators'; import {LoadChildren, LoadedRouterConfig, Route, standardizeConfig} from './config'; import {flatten, wrapIntoObservable} from './utils/collection'; @@ -35,6 +35,10 @@ export class RouterConfigLoader { const moduleFactory$ = this.loadModuleFactory(route.loadChildren!); route._loader$ = moduleFactory$.pipe( + catchError((err) => { + route._loader$ = undefined; + throw err; + }), map((factory: NgModuleFactory) => { if (this.onLoadEndListener) { this.onLoadEndListener(route); diff --git a/packages/router/test/router_preloader.spec.ts b/packages/router/test/router_preloader.spec.ts index efa06760a5147..43949ee26a949 100644 --- a/packages/router/test/router_preloader.spec.ts +++ b/packages/router/test/router_preloader.spec.ts @@ -7,6 +7,7 @@ */ import {Compiler, Component, NgModule, NgModuleFactoryLoader, NgModuleRef} from '@angular/core'; +import {resolveComponentResources} from '@angular/core/src/metadata/resource_loading'; import {fakeAsync, inject, TestBed, tick} from '@angular/core/testing'; import {PreloadAllModules, PreloadingStrategy, RouterPreloader} from '@angular/router'; import {BehaviorSubject, Observable, of} from 'rxjs'; @@ -316,6 +317,58 @@ describe('RouterPreloader', () => { ]); }))); + it('and cope with the loader throwing exceptions', + fakeAsync(inject( + [NgModuleFactoryLoader, RouterPreloader, Router, NgModuleRef, Compiler], + (loader: SpyNgModuleFactoryLoader, preloader: RouterPreloader, router: Router, + testModule: NgModuleRef, compiler: Compiler) => { + router.events.subscribe(e => { + if (e instanceof RouteConfigLoadEnd || e instanceof RouteConfigLoadStart) { + events.push(e); + } + }); + + loader.stubbedModules = { + 'expectedreload#error:1:Fake module load error (expectedreload)': LoadedModule1, + submodule: LoadedModule2 + }; + + let loadedConfig: LoadedRouterConfig; + const c = router.config; + expect(c[0].loadChildren).toEqual('expectedreload'); + loadedConfig = (c[0] as any)._loadedConfig; + expect(loadedConfig).toBeUndefined(); + + preloader.preload().subscribe((x) => {}); + + tick(); + loadedConfig = (c[0] as any)._loadedConfig; + expect(loadedConfig).toBeUndefined(); + expect(logMessages).toEqual([ + 'Add route loader for expectedreload', + 'list changed: ', + ]); + + router.navigateByUrl('/lazy/LoadedModule1').catch((reason) => { + expect(reason).toEqual(Error('Fake module load error (expectedreload)')); + }); + tick(); + loadedConfig = (c[0] as any)._loadedConfig; + expect(loadedConfig).toBeUndefined(); + expect((c[0] as any)._loader$).toBeUndefined(); + + router.navigateByUrl('/lazy/LoadedModule1').catch(() => { + expect('Not to get here').toBeUndefined('Not to throw'); + }); + tick(); + + expect(events.map(e => e.toString())).toEqual([ + 'RouteConfigLoadStart(path: lazy)', 'RouteConfigLoadStart(path: lazy)', + 'RouteConfigLoadEnd(path: lazy)' + ]); + }))); + + it('without autoloading loading submodules', fakeAsync(inject( [NgModuleFactoryLoader, RouterPreloader, Router, NgModuleRef, Compiler],