fix(ivy): platform module bootstrap does not resolve resources (#29083)
Currently with ViewEngine, if someone runs the platform's `bootstrapModule` method in order to boostrap a module in JIT mode, external component resources are properly resolved *automatically*. Currently with Ivy, the developer would need to manually call `resolveComponentResources` in order to asynchronously fetch the determined external component resources. In order to make this backwards compatible with ViewEngine, and also since platforms can already specify a `ResourceLoader` compiler provider, we need to automatically resolve all external component resources on module bootstrap. -- Since the `ResourceLoader` is part of the `@angular/compiler`, because ViewEngine performed the factory creation in the compiler, we can't access the `ResourceLoader` token from within core. In order to workaround this without introducing a breaking change, we just proxy the `ResourceLoader` token to `core` through the compiler facade. In the future, we should be able to move the `ResourceLoader` to core when ViewEngine code no longer exists in the `@angular/compiler`. PR Close #29083
This commit is contained in:

committed by
Kara Erickson

parent
7315a68ac6
commit
6085f335e8
@ -11,15 +11,17 @@ import {share} from 'rxjs/operators';
|
||||
|
||||
import {ApplicationInitStatus} from './application_init';
|
||||
import {APP_BOOTSTRAP_LISTENER, PLATFORM_INITIALIZER} from './application_tokens';
|
||||
import {getCompilerFacade} from './compiler/compiler_facade';
|
||||
import {Console} from './console';
|
||||
import {Injectable, InjectionToken, Injector, StaticProvider} from './di';
|
||||
import {ErrorHandler} from './error_handler';
|
||||
import {Type} from './interface/type';
|
||||
import {CompilerFactory, CompilerOptions} from './linker/compiler';
|
||||
import {COMPILER_OPTIONS, CompilerFactory, CompilerOptions} from './linker/compiler';
|
||||
import {ComponentFactory, ComponentRef} from './linker/component_factory';
|
||||
import {ComponentFactoryBoundToModule, ComponentFactoryResolver} from './linker/component_factory_resolver';
|
||||
import {InternalNgModuleRef, NgModuleFactory, NgModuleRef} from './linker/ng_module_factory';
|
||||
import {InternalViewRef, ViewRef} from './linker/view_ref';
|
||||
import {isComponentResourceResolutionQueueEmpty, resolveComponentResources} from './metadata/resource_loading';
|
||||
import {WtfScopeFn, wtfCreateScope, wtfLeave} from './profile/profile';
|
||||
import {assertNgModuleType} from './render3/assert';
|
||||
import {ComponentFactory as R3ComponentFactory} from './render3/component_ref';
|
||||
@ -49,7 +51,30 @@ export function compileNgModuleFactory__POST_R3__<M>(
|
||||
injector: Injector, options: CompilerOptions,
|
||||
moduleType: Type<M>): Promise<NgModuleFactory<M>> {
|
||||
ngDevMode && assertNgModuleType(moduleType);
|
||||
return Promise.resolve(new R3NgModuleFactory(moduleType));
|
||||
const moduleFactory = new R3NgModuleFactory(moduleType);
|
||||
|
||||
if (isComponentResourceResolutionQueueEmpty()) {
|
||||
return Promise.resolve(moduleFactory);
|
||||
}
|
||||
|
||||
const compilerOptions = injector.get(COMPILER_OPTIONS, []).concat(options);
|
||||
const compilerProviders = _mergeArrays(compilerOptions.map(o => o.providers !));
|
||||
|
||||
// In case there are no compiler providers, we just return the module factory as
|
||||
// there won't be any resource loader. This can happen with Ivy, because AOT compiled
|
||||
// modules can be still passed through "bootstrapModule". In that case we shouldn't
|
||||
// unnecessarily require the JIT compiler.
|
||||
if (compilerProviders.length === 0) {
|
||||
return Promise.resolve(moduleFactory);
|
||||
}
|
||||
|
||||
const compiler = getCompilerFacade();
|
||||
const compilerInjector = Injector.create({providers: compilerProviders});
|
||||
const resourceLoader = compilerInjector.get(compiler.ResourceLoader);
|
||||
// The resource loader can also return a string while the "resolveComponentResources"
|
||||
// always expects a promise. Therefore we need to wrap the returned value in a promise.
|
||||
return resolveComponentResources(url => Promise.resolve(resourceLoader.get(url)))
|
||||
.then(() => moduleFactory);
|
||||
}
|
||||
|
||||
let isBoundToModule: <C>(cf: ComponentFactory<C>) => boolean = isBoundToModule__PRE_R3__;
|
||||
@ -671,3 +696,9 @@ function remove<T>(list: T[], el: T): void {
|
||||
list.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
function _mergeArrays(parts: any[][]): any[] {
|
||||
const result: any[] = [];
|
||||
parts.forEach((part) => part && result.push(...part));
|
||||
return result;
|
||||
}
|
||||
|
Reference in New Issue
Block a user