refactor(docs-infra): update loading of custom elements to use dynamic import syntax (#30704)
Removes the usage of `NgModuleFactoryLoader` and string-based imports for lazy loading. PR Close #30704
This commit is contained in:
		
							parent
							
								
									1315d23aa4
								
							
						
					
					
						commit
						fcef39048a
					
				| @ -2,8 +2,8 @@ | ||||
|   "aio": { | ||||
|     "master": { | ||||
|       "uncompressed": { | ||||
|         "runtime-es5": 2980, | ||||
|         "runtime-es2015": 2986, | ||||
|         "runtime-es5": 2516, | ||||
|         "runtime-es2015": 2522, | ||||
|         "main-es5": 504760, | ||||
|         "main-es2015": 443497, | ||||
|         "polyfills-es5": 128751, | ||||
|  | ||||
| @ -2,9 +2,9 @@ import { NgModule, NgModuleFactoryLoader, SystemJsNgModuleLoader } from '@angula | ||||
| import { ROUTES} from '@angular/router'; | ||||
| import { ElementsLoader } from './elements-loader'; | ||||
| import { | ||||
|   ELEMENT_MODULE_PATHS, | ||||
|   ELEMENT_MODULE_PATHS_AS_ROUTES, | ||||
|   ELEMENT_MODULE_PATHS_TOKEN | ||||
|   ELEMENT_MODULE_LOAD_CALLBACKS, | ||||
|   ELEMENT_MODULE_LOAD_CALLBACKS_AS_ROUTES, | ||||
|   ELEMENT_MODULE_LOAD_CALLBACKS_TOKEN | ||||
| } from './element-registry'; | ||||
| import { LazyCustomElementComponent } from './lazy-custom-element.component'; | ||||
| 
 | ||||
| @ -14,12 +14,12 @@ import { LazyCustomElementComponent } from './lazy-custom-element.component'; | ||||
|   providers: [ | ||||
|     ElementsLoader, | ||||
|     { provide: NgModuleFactoryLoader, useClass: SystemJsNgModuleLoader }, | ||||
|     { provide: ELEMENT_MODULE_PATHS_TOKEN, useValue: ELEMENT_MODULE_PATHS }, | ||||
|     { provide: ELEMENT_MODULE_LOAD_CALLBACKS_TOKEN, useValue: ELEMENT_MODULE_LOAD_CALLBACKS }, | ||||
| 
 | ||||
|     // Providing these routes as a signal to the build system that these modules should be
 | ||||
|     // registered as lazy-loadable.
 | ||||
|     // TODO(andrewjs): Provide first-class support for providing this.
 | ||||
|     { provide: ROUTES, useValue: ELEMENT_MODULE_PATHS_AS_ROUTES, multi: true }, | ||||
|     { provide: ROUTES, useValue: ELEMENT_MODULE_LOAD_CALLBACKS_AS_ROUTES, multi: true }, | ||||
|   ], | ||||
| }) | ||||
| export class CustomElementsModule { } | ||||
|  | ||||
| @ -1,44 +1,45 @@ | ||||
| import { InjectionToken, Type } from '@angular/core'; | ||||
| import { LoadChildrenCallback } from '@angular/router'; | ||||
| 
 | ||||
| // Modules containing custom elements must be set up as lazy-loaded routes (loadChildren)
 | ||||
| // TODO(andrewjs): This is a hack, Angular should have first-class support for preparing a module
 | ||||
| // that contains custom elements.
 | ||||
| export const ELEMENT_MODULE_PATHS_AS_ROUTES = [ | ||||
| export const ELEMENT_MODULE_LOAD_CALLBACKS_AS_ROUTES = [ | ||||
|   { | ||||
|     selector: 'aio-announcement-bar', | ||||
|     loadChildren: './announcement-bar/announcement-bar.module#AnnouncementBarModule' | ||||
|     loadChildren: () => import('./announcement-bar/announcement-bar.module').then(mod => mod.AnnouncementBarModule) | ||||
|   }, | ||||
|   { | ||||
|     selector: 'aio-api-list', | ||||
|     loadChildren: './api/api-list.module#ApiListModule' | ||||
|     loadChildren: () => import('./api/api-list.module').then(mod => mod.ApiListModule) | ||||
|   }, | ||||
|   { | ||||
|     selector: 'aio-contributor-list', | ||||
|     loadChildren: './contributor/contributor-list.module#ContributorListModule' | ||||
|     loadChildren: () => import('./contributor/contributor-list.module').then(mod => mod.ContributorListModule) | ||||
|   }, | ||||
|   { | ||||
|     selector: 'aio-file-not-found-search', | ||||
|     loadChildren: './search/file-not-found-search.module#FileNotFoundSearchModule' | ||||
|     loadChildren: () => import('./search/file-not-found-search.module').then(mod => mod.FileNotFoundSearchModule) | ||||
|   }, | ||||
|   { | ||||
|     selector: 'aio-resource-list', | ||||
|     loadChildren: './resource/resource-list.module#ResourceListModule' | ||||
|     loadChildren: () => import('./resource/resource-list.module').then(mod => mod.ResourceListModule) | ||||
|   }, | ||||
|   { | ||||
|     selector: 'aio-toc', | ||||
|     loadChildren: './toc/toc.module#TocModule' | ||||
|     loadChildren: () => import('./toc/toc.module').then(mod => mod.TocModule) | ||||
|   }, | ||||
|   { | ||||
|     selector: 'code-example', | ||||
|     loadChildren: './code/code-example.module#CodeExampleModule' | ||||
|     loadChildren: () => import('./code/code-example.module').then(mod => mod.CodeExampleModule) | ||||
|   }, | ||||
|   { | ||||
|     selector: 'code-tabs', | ||||
|     loadChildren: './code/code-tabs.module#CodeTabsModule' | ||||
|     loadChildren: () => import('./code/code-tabs.module').then(mod => mod.CodeTabsModule) | ||||
|   }, | ||||
|   { | ||||
|     selector: 'live-example', | ||||
|     loadChildren: './live-example/live-example.module#LiveExampleModule' | ||||
|     loadChildren: () => import('./live-example/live-example.module').then(mod => mod.LiveExampleModule) | ||||
|   } | ||||
| ]; | ||||
| 
 | ||||
| @ -51,10 +52,10 @@ export interface WithCustomElementComponent { | ||||
| } | ||||
| 
 | ||||
| /** Injection token to provide the element path modules. */ | ||||
| export const ELEMENT_MODULE_PATHS_TOKEN = new InjectionToken('aio/elements-map'); | ||||
| export const ELEMENT_MODULE_LOAD_CALLBACKS_TOKEN = new InjectionToken<Map<string, LoadChildrenCallback>>('aio/elements-map'); | ||||
| 
 | ||||
| /** Map of possible custom element selectors to their lazy-loadable module paths. */ | ||||
| export const ELEMENT_MODULE_PATHS = new Map<string, string>(); | ||||
| ELEMENT_MODULE_PATHS_AS_ROUTES.forEach(route => { | ||||
|   ELEMENT_MODULE_PATHS.set(route.selector, route.loadChildren); | ||||
| export const ELEMENT_MODULE_LOAD_CALLBACKS = new Map<string, LoadChildrenCallback>(); | ||||
| ELEMENT_MODULE_LOAD_CALLBACKS_AS_ROUTES.forEach(route => { | ||||
|   ELEMENT_MODULE_LOAD_CALLBACKS.set(route.selector, route.loadChildren); | ||||
| }); | ||||
|  | ||||
| @ -1,13 +1,13 @@ | ||||
| import { | ||||
|   ComponentFactory, | ||||
|   ComponentFactoryResolver, ComponentRef, Injector, NgModuleFactory, NgModuleFactoryLoader, | ||||
|   ComponentFactoryResolver, ComponentRef, Injector, NgModuleFactory, | ||||
|   NgModuleRef, | ||||
|   Type | ||||
| } from '@angular/core'; | ||||
| import { TestBed, fakeAsync, flushMicrotasks } from '@angular/core/testing'; | ||||
| 
 | ||||
| import { ElementsLoader } from './elements-loader'; | ||||
| import { ELEMENT_MODULE_PATHS_TOKEN, WithCustomElementComponent } from './element-registry'; | ||||
| import { ELEMENT_MODULE_LOAD_CALLBACKS_TOKEN, WithCustomElementComponent } from './element-registry'; | ||||
| 
 | ||||
| 
 | ||||
| interface Deferred { | ||||
| @ -22,10 +22,9 @@ describe('ElementsLoader', () => { | ||||
|     const injector = TestBed.configureTestingModule({ | ||||
|       providers: [ | ||||
|         ElementsLoader, | ||||
|         { provide: NgModuleFactoryLoader, useClass: FakeModuleFactoryLoader }, | ||||
|         { provide: ELEMENT_MODULE_PATHS_TOKEN, useValue: new Map([ | ||||
|           ['element-a-selector', 'element-a-module-path'], | ||||
|           ['element-b-selector', 'element-b-module-path'] | ||||
|         { provide: ELEMENT_MODULE_LOAD_CALLBACKS_TOKEN, useValue: new Map<string, () => Promise<NgModuleFactory<WithCustomElementComponent>>>([ | ||||
|           ['element-a-selector', () => Promise.resolve(new FakeModuleFactory('element-a-module'))], | ||||
|           ['element-b-selector', () => Promise.resolve(new FakeModuleFactory('element-b-module'))] | ||||
|         ])}, | ||||
|       ] | ||||
|     }); | ||||
| @ -148,7 +147,7 @@ describe('ElementsLoader', () => { | ||||
| 
 | ||||
|       // Verify the right component was loaded/registered.
 | ||||
|       const Ctor = definedSpy.calls.argsFor(0)[1]; | ||||
|       expect(Ctor.observedAttributes).toEqual(['element-a-module-path']); | ||||
|       expect(Ctor.observedAttributes).toEqual(['element-a-module']); | ||||
|     })); | ||||
| 
 | ||||
|     it('should wait until the element is defined', fakeAsync(() => { | ||||
| @ -282,13 +281,6 @@ class FakeModuleFactory extends NgModuleFactory<any> { | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class FakeModuleFactoryLoader extends NgModuleFactoryLoader { | ||||
|   load(modulePath: string): Promise<NgModuleFactory<any>> { | ||||
|     const fakeModuleFactory = new FakeModuleFactory(modulePath); | ||||
|     return Promise.resolve(fakeModuleFactory); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| function returnPromisesFromSpy(spy: jasmine.Spy): Deferred[] { | ||||
|   const deferreds: Deferred[] = []; | ||||
|   spy.and.callFake(() => new Promise((resolve, reject) => deferreds.push({resolve, reject}))); | ||||
|  | ||||
| @ -1,24 +1,24 @@ | ||||
| import { | ||||
|   Inject, | ||||
|   Injectable, | ||||
|   NgModuleFactoryLoader, | ||||
|   NgModuleFactory, | ||||
|   NgModuleRef, | ||||
| } from '@angular/core'; | ||||
| import { ELEMENT_MODULE_PATHS_TOKEN } from './element-registry'; | ||||
| import { ELEMENT_MODULE_LOAD_CALLBACKS_TOKEN, WithCustomElementComponent } from './element-registry'; | ||||
| import { from, Observable, of } from 'rxjs'; | ||||
| import { createCustomElement } from '@angular/elements'; | ||||
| import { LoadChildrenCallback } from '@angular/router'; | ||||
| 
 | ||||
| 
 | ||||
| @Injectable() | ||||
| export class ElementsLoader { | ||||
|   /** Map of unregistered custom elements and their respective module paths to load. */ | ||||
|   private elementsToLoad: Map<string, string>; | ||||
|   private elementsToLoad: Map<string, LoadChildrenCallback>; | ||||
|   /** Map of custom elements that are in the process of being loaded and registered. */ | ||||
|   private elementsLoading = new Map<string, Promise<void>>(); | ||||
| 
 | ||||
|   constructor(private moduleFactoryLoader: NgModuleFactoryLoader, | ||||
|               private moduleRef: NgModuleRef<any>, | ||||
|               @Inject(ELEMENT_MODULE_PATHS_TOKEN) elementModulePaths: Map<string, string>) { | ||||
|   constructor(private moduleRef: NgModuleRef<any>, | ||||
|               @Inject(ELEMENT_MODULE_LOAD_CALLBACKS_TOKEN) elementModulePaths: Map<string, LoadChildrenCallback>) { | ||||
|     this.elementsToLoad = new Map(elementModulePaths); | ||||
|   } | ||||
| 
 | ||||
| @ -47,9 +47,8 @@ export class ElementsLoader { | ||||
| 
 | ||||
|     if (this.elementsToLoad.has(selector)) { | ||||
|       // Load and register the custom element (for the first time).
 | ||||
|       const modulePath = this.elementsToLoad.get(selector)!; | ||||
|       const loadedAndRegistered = this.moduleFactoryLoader | ||||
|           .load(modulePath) | ||||
|       const modulePathLoader = this.elementsToLoad.get(selector)!; | ||||
|       const loadedAndRegistered = (modulePathLoader() as Promise<NgModuleFactory<WithCustomElementComponent>>) | ||||
|           .then(elementModuleFactory => { | ||||
|             const elementModuleRef = elementModuleFactory.create(this.moduleRef.injector); | ||||
|             const injector = elementModuleRef.injector; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user