diff --git a/packages/compiler-cli/test/ngtsc/local_compilation_spec.ts b/packages/compiler-cli/test/ngtsc/local_compilation_spec.ts index 8e2201a79b6..2a8084e797c 100644 --- a/packages/compiler-cli/test/ngtsc/local_compilation_spec.ts +++ b/packages/compiler-cli/test/ngtsc/local_compilation_spec.ts @@ -562,5 +562,55 @@ runInEachFileSystem(() => { expect(text).toContain('either inline it or move it to a separate file'); }); }); + + describe('ng module bootstrap def', () => { + it('should include the bootstrap definition in ɵɵsetNgModuleScope instead of ɵɵdefineNgModule', + () => { + env.write('test.ts', ` + import {NgModule} from '@angular/core'; + import {App} from './some-where'; + + @NgModule({ + declarations: [App], + bootstrap: [App], + }) + export class AppModule { + } + `); + + env.driveMain(); + const jsContents = env.getContents('test.js'); + + expect(jsContents) + .toContain( + 'AppModule.ɵmod = /*@__PURE__*/ i0.ɵɵdefineNgModule({ type: AppModule });'); + expect(jsContents) + .toContain( + 'ɵɵsetNgModuleScope(AppModule, { declarations: [App], bootstrap: [App] }); })();'); + }); + + it('should include no bootstrap definition in ɵɵsetNgModuleScope if the NgModule has no bootstrap field', + () => { + env.write('test.ts', ` + import {NgModule} from '@angular/core'; + import {App} from './some-where'; + + @NgModule({ + declarations: [App], + }) + export class AppModule { + } + `); + + env.driveMain(); + const jsContents = env.getContents('test.js'); + + expect(jsContents) + .toContain( + 'AppModule.ɵmod = /*@__PURE__*/ i0.ɵɵdefineNgModule({ type: AppModule });'); + expect(jsContents) + .toContain('ɵɵsetNgModuleScope(AppModule, { declarations: [App] }); })();'); + }); + }); }); }); diff --git a/packages/compiler/src/render3/r3_module_compiler.ts b/packages/compiler/src/render3/r3_module_compiler.ts index 9471c16efec..a1485cb30dd 100644 --- a/packages/compiler/src/render3/r3_module_compiler.ts +++ b/packages/compiler/src/render3/r3_module_compiler.ts @@ -204,15 +204,11 @@ export function compileNgModule(meta: R3NgModuleMetadata): R3CompiledExpression const definitionMap = new DefinitionMap(); definitionMap.set('type', meta.type.value); - // Assign bootstrap definition - if (meta.kind === R3NgModuleMetadataKind.Global) { - if (meta.bootstrap.length > 0) { - definitionMap.set('bootstrap', refsToArray(meta.bootstrap, meta.containsForwardDecls)); - } - } else { - if (meta.bootstrapExpression) { - definitionMap.set('bootstrap', meta.bootstrapExpression); - } + // Assign bootstrap definition. In local compilation mode (i.e., for + // `R3NgModuleMetadataKind.LOCAL`) we assign the bootstrap field using the runtime + // `ɵɵsetNgModuleScope`. + if (meta.kind === R3NgModuleMetadataKind.Global && meta.bootstrap.length > 0) { + definitionMap.set('bootstrap', refsToArray(meta.bootstrap, meta.containsForwardDecls)); } if (meta.selectorScopeMode === R3SelectorScopeMode.Inline) { @@ -321,8 +317,12 @@ export function createNgModuleType(meta: R3NgModuleMetadata): o.ExpressionType { * symbols to become tree-shakeable. */ function generateSetNgModuleScopeCall(meta: R3NgModuleMetadata): o.Statement|null { - const scopeMap = new DefinitionMap< - {declarations: o.Expression, imports: o.Expression, exports: o.Expression}>(); + const scopeMap = new DefinitionMap<{ + declarations: o.Expression, + imports: o.Expression, + exports: o.Expression, + bootstrap: o.Expression + }>(); if (meta.kind === R3NgModuleMetadataKind.Global) { if (meta.declarations.length > 0) { @@ -354,6 +354,10 @@ function generateSetNgModuleScopeCall(meta: R3NgModuleMetadata): o.Statement|nul } } + if (meta.kind === R3NgModuleMetadataKind.Local && meta.bootstrapExpression) { + scopeMap.set('bootstrap', meta.bootstrapExpression); + } + if (Object.keys(scopeMap.values).length === 0) { return null; }