diff --git a/packages/core/src/core_private_export.ts b/packages/core/src/core_private_export.ts index 76e14ab5c3a..ed2f1869c03 100644 --- a/packages/core/src/core_private_export.ts +++ b/packages/core/src/core_private_export.ts @@ -105,6 +105,7 @@ export { } from './metadata/resource_loading'; export {PendingTasksInternal as ɵPendingTasksInternal} from './pending_tasks'; export {ALLOW_MULTIPLE_PLATFORMS as ɵALLOW_MULTIPLE_PLATFORMS} from './platform/platform'; +export {ENABLE_ROOT_COMPONENT_BOOTSTRAP as ɵENABLE_ROOT_COMPONENT_BOOTSTRAP} from './platform/bootstrap'; export {ReflectionCapabilities as ɵReflectionCapabilities} from './reflection/reflection_capabilities'; export {AnimationRendererType as ɵAnimationRendererType} from './render/api'; export { diff --git a/packages/core/src/platform/bootstrap.ts b/packages/core/src/platform/bootstrap.ts index c9d80275477..3fdce7155df 100644 --- a/packages/core/src/platform/bootstrap.ts +++ b/packages/core/src/platform/bootstrap.ts @@ -8,7 +8,7 @@ import {Subscription} from 'rxjs'; import {PROVIDED_NG_ZONE} from '../change_detection/scheduling/ng_zone_scheduling'; -import {EnvironmentInjector, R3Injector} from '../di/r3_injector'; +import {R3Injector} from '../di/r3_injector'; import {ErrorHandler} from '../error_handler'; import {RuntimeError, RuntimeErrorCode} from '../errors'; import {DEFAULT_LOCALE_ID} from '../i18n/localization'; @@ -22,10 +22,34 @@ import {NgZone} from '../zone/ng_zone'; import {ApplicationInitStatus} from '../application/application_init'; import {_callAndReportToErrorHandler, ApplicationRef, remove} from '../application/application_ref'; import {PROVIDED_ZONELESS} from '../change_detection/scheduling/zoneless_scheduling'; -import {Injector} from '../di'; +import {InjectionToken, Injector} from '../di'; import {InternalNgModuleRef, NgModuleRef} from '../linker/ng_module_factory'; import {stringify} from '../util/stringify'; +/** + * InjectionToken to control root component bootstrap behavior. + * + * This token is primarily used in Angular's server-side rendering (SSR) scenarios, + * particularly by the `@angular/ssr` package, to manage whether the root component + * should be bootstrapped during the application initialization process. + * + * ## Purpose: + * During SSR route extraction, setting this token to `false` prevents Angular from + * bootstrapping the root component. This avoids unnecessary component rendering, + * enabling route extraction without requiring additional APIs or triggering + * component logic. + * + * ## Behavior: + * - **`false`**: Prevents the root component from being bootstrapped. + * - **`true`** (default): Proceeds with the normal root component bootstrap process. + * + * This mechanism ensures SSR can efficiently separate route extraction logic + * from component rendering. + */ +export const ENABLE_ROOT_COMPONENT_BOOTSTRAP = new InjectionToken( + ngDevMode ? 'ENABLE_ROOT_COMPONENT_BOOTSTRAP' : '', +); + export interface BootstrapConfig { platformInjector: Injector; } @@ -125,6 +149,17 @@ export function bootstrap( // If the `LOCALE_ID` provider is defined at bootstrap then we set the value for ivy const localeId = envInjector.get(LOCALE_ID, DEFAULT_LOCALE_ID); setLocaleId(localeId || DEFAULT_LOCALE_ID); + + const enableRootComponentBoostrap = envInjector.get(ENABLE_ROOT_COMPONENT_BOOTSTRAP, true); + if (!enableRootComponentBoostrap) { + if (isApplicationBootstrapConfig(config)) { + return envInjector.get(ApplicationRef); + } + + config.allPlatformModules.push(config.moduleRef); + return config.moduleRef; + } + if (typeof ngDevMode === 'undefined' || ngDevMode) { const imagePerformanceService = envInjector.get(ImagePerformanceWarning); imagePerformanceService.start(); diff --git a/packages/core/test/bundling/animations-standalone/bundle.golden_symbols.json b/packages/core/test/bundling/animations-standalone/bundle.golden_symbols.json index f64ab6e4d4f..a8716ce50b8 100644 --- a/packages/core/test/bundling/animations-standalone/bundle.golden_symbols.json +++ b/packages/core/test/bundling/animations-standalone/bundle.golden_symbols.json @@ -191,6 +191,9 @@ { "name": "EMPTY_SUBSCRIPTION" }, + { + "name": "ENABLE_ROOT_COMPONENT_BOOTSTRAP" + }, { "name": "ENTER_TOKEN_REGEX" }, diff --git a/packages/core/test/bundling/animations/bundle.golden_symbols.json b/packages/core/test/bundling/animations/bundle.golden_symbols.json index 9e1fee21f58..11aff6ade55 100644 --- a/packages/core/test/bundling/animations/bundle.golden_symbols.json +++ b/packages/core/test/bundling/animations/bundle.golden_symbols.json @@ -218,6 +218,9 @@ { "name": "EMPTY_SUBSCRIPTION" }, + { + "name": "ENABLE_ROOT_COMPONENT_BOOTSTRAP" + }, { "name": "ENTER_TOKEN_REGEX" }, diff --git a/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json b/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json index bee79d36895..36acd8ea667 100644 --- a/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json +++ b/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json @@ -134,6 +134,9 @@ { "name": "EMPTY_SUBSCRIPTION" }, + { + "name": "ENABLE_ROOT_COMPONENT_BOOTSTRAP" + }, { "name": "ENVIRONMENT_INITIALIZER" }, diff --git a/packages/core/test/bundling/defer/bundle.golden_symbols.json b/packages/core/test/bundling/defer/bundle.golden_symbols.json index 921050b67c3..2daaa765882 100644 --- a/packages/core/test/bundling/defer/bundle.golden_symbols.json +++ b/packages/core/test/bundling/defer/bundle.golden_symbols.json @@ -182,6 +182,9 @@ { "name": "EMPTY_SUBSCRIPTION" }, + { + "name": "ENABLE_ROOT_COMPONENT_BOOTSTRAP" + }, { "name": "ENVIRONMENT_INITIALIZER" }, diff --git a/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json b/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json index 0f4181a8a92..69441fd5f94 100644 --- a/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json +++ b/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json @@ -188,6 +188,9 @@ { "name": "EMPTY_SUBSCRIPTION" }, + { + "name": "ENABLE_ROOT_COMPONENT_BOOTSTRAP" + }, { "name": "ENVIRONMENT_INITIALIZER" }, diff --git a/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json b/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json index 090ce6805ab..0ce6f1be273 100644 --- a/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json +++ b/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json @@ -191,6 +191,9 @@ { "name": "EMPTY_SUBSCRIPTION" }, + { + "name": "ENABLE_ROOT_COMPONENT_BOOTSTRAP" + }, { "name": "ENVIRONMENT_INITIALIZER" }, diff --git a/packages/core/test/bundling/hello_world/bundle.golden_symbols.json b/packages/core/test/bundling/hello_world/bundle.golden_symbols.json index e7957fed712..82f502394d5 100644 --- a/packages/core/test/bundling/hello_world/bundle.golden_symbols.json +++ b/packages/core/test/bundling/hello_world/bundle.golden_symbols.json @@ -86,6 +86,9 @@ { "name": "EMPTY_SUBSCRIPTION" }, + { + "name": "ENABLE_ROOT_COMPONENT_BOOTSTRAP" + }, { "name": "ENVIRONMENT_INITIALIZER" }, diff --git a/packages/core/test/bundling/hydration/bundle.golden_symbols.json b/packages/core/test/bundling/hydration/bundle.golden_symbols.json index a87abb1d3dd..6b5403c5e22 100644 --- a/packages/core/test/bundling/hydration/bundle.golden_symbols.json +++ b/packages/core/test/bundling/hydration/bundle.golden_symbols.json @@ -122,6 +122,9 @@ { "name": "EMPTY_SUBSCRIPTION" }, + { + "name": "ENABLE_ROOT_COMPONENT_BOOTSTRAP" + }, { "name": "ENVIRONMENT_INITIALIZER" }, diff --git a/packages/core/test/bundling/router/bundle.golden_symbols.json b/packages/core/test/bundling/router/bundle.golden_symbols.json index 726dd0c3db0..afef52d0eb9 100644 --- a/packages/core/test/bundling/router/bundle.golden_symbols.json +++ b/packages/core/test/bundling/router/bundle.golden_symbols.json @@ -197,6 +197,9 @@ { "name": "EMPTY_SUBSCRIPTION" }, + { + "name": "ENABLE_ROOT_COMPONENT_BOOTSTRAP" + }, { "name": "ENVIRONMENT_INITIALIZER" }, diff --git a/packages/core/test/bundling/standalone_bootstrap/bundle.golden_symbols.json b/packages/core/test/bundling/standalone_bootstrap/bundle.golden_symbols.json index d454dd92ce7..4ff733e7bc3 100644 --- a/packages/core/test/bundling/standalone_bootstrap/bundle.golden_symbols.json +++ b/packages/core/test/bundling/standalone_bootstrap/bundle.golden_symbols.json @@ -113,6 +113,9 @@ { "name": "EMPTY_SUBSCRIPTION" }, + { + "name": "ENABLE_ROOT_COMPONENT_BOOTSTRAP" + }, { "name": "ENVIRONMENT_INITIALIZER" }, diff --git a/packages/core/test/bundling/todo/bundle.golden_symbols.json b/packages/core/test/bundling/todo/bundle.golden_symbols.json index dd37518a768..9f9e72a5ece 100644 --- a/packages/core/test/bundling/todo/bundle.golden_symbols.json +++ b/packages/core/test/bundling/todo/bundle.golden_symbols.json @@ -137,6 +137,9 @@ { "name": "EMPTY_SUBSCRIPTION" }, + { + "name": "ENABLE_ROOT_COMPONENT_BOOTSTRAP" + }, { "name": "ENVIRONMENT_INITIALIZER" },