fix(core): mark NgModule as not the root if APP_ROOT is set to false (#24814)

Tree shakable providers use the APP_ROOT token to determine where to attach themselves. APP_ROOT gets set on NgModule with BrowserModule irrespective of whether it is actually the root(Ex. in case of SSR app where the shell app is first bootstrapped without BrowserModule being the root module).

This change allows a NgModule with BrowserModule to explicitly mark itself as not the root by setting APP_ROOT token to false. This allows tree shakable providers to be attached to the right rott module.

PR Close #24814
This commit is contained in:
Vikram Subramanian 2018-07-10 08:17:45 -07:00 committed by Miško Hevery
parent ddb792da28
commit 1089261717
2 changed files with 27 additions and 1 deletions

View File

@ -43,7 +43,7 @@ export function moduleDef(providers: NgModuleProviderDef[]): NgModuleDefinition
let isRoot: boolean = false; let isRoot: boolean = false;
for (let i = 0; i < providers.length; i++) { for (let i = 0; i < providers.length; i++) {
const provider = providers[i]; const provider = providers[i];
if (provider.token === APP_ROOT) { if (provider.token === APP_ROOT && provider.value === true) {
isRoot = true; isRoot = true;
} }
if (provider.flags & NodeFlags.TypeNgModule) { if (provider.flags & NodeFlags.TypeNgModule) {

View File

@ -14,6 +14,7 @@ import {NgModuleDefinition, NgModuleProviderDef, NodeFlags} from '@angular/core/
import {moduleDef, moduleProvideDef, resolveNgModuleDep} from '@angular/core/src/view/ng_module'; import {moduleDef, moduleProvideDef, resolveNgModuleDep} from '@angular/core/src/view/ng_module';
import {createNgModuleRef} from '@angular/core/src/view/refs'; import {createNgModuleRef} from '@angular/core/src/view/refs';
import {tokenKey} from '@angular/core/src/view/util'; import {tokenKey} from '@angular/core/src/view/util';
import {APP_ROOT} from '../../src/di/scope';
class Foo {} class Foo {}
@ -229,4 +230,29 @@ describe('NgModuleRef_ injector', () => {
ref.destroy(); ref.destroy();
expect(Service.destroyed).toBe(1); expect(Service.destroyed).toBe(1);
}); });
describe('moduleDef', () => {
function createProvider(token: any, value: any) {
return {
index: 0,
flags: NodeFlags.TypeValueProvider | NodeFlags.LazyProvider,
deps: [], token, value
};
}
it('sets isRoot to `true` when APP_ROOT is `true`', () => {
const def = moduleDef([createProvider(APP_ROOT, true)]);
expect(def.isRoot).toBe(true);
});
it('sets isRoot to `false` when APP_ROOT is absent', () => {
const def = moduleDef([]);
expect(def.isRoot).toBe(false);
});
it('sets isRoot to `false` when APP_ROOT is `false`', () => {
const def = moduleDef([createProvider(APP_ROOT, false)]);
expect(def.isRoot).toBe(false);
});
});
}); });