/** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.dev/license */ import { DOCUMENT, PlatformLocation, ViewportScroller, ɵgetDOM as getDOM, ɵNullViewportScroller as NullViewportScroller, ɵPLATFORM_SERVER_ID as PLATFORM_SERVER_ID, } from '@angular/common'; import { createPlatformFactory, Injector, NgModule, PLATFORM_ID, PLATFORM_INITIALIZER, platformCore, PlatformRef, Provider, Testability, ɵsetDocument, ɵTESTABILITY as TESTABILITY, inject, StaticProvider, } from '@angular/core'; import { BrowserModule, EVENT_MANAGER_PLUGINS, ɵBrowserDomAdapter as BrowserDomAdapter, } from '@angular/platform-browser'; import {DominoAdapter, parseDocument} from './domino_adapter'; import {SERVER_HTTP_PROVIDERS} from './http'; import {ServerPlatformLocation} from './location'; import {enableDomEmulation, PlatformState} from './platform_state'; import {ServerEventManagerPlugin} from './server_events'; import {INITIAL_CONFIG, PlatformConfig} from './tokens'; import {TRANSFER_STATE_SERIALIZATION_PROVIDERS} from './transfer_state'; export const INTERNAL_SERVER_PLATFORM_PROVIDERS: StaticProvider[] = [ {provide: DOCUMENT, useFactory: _document}, {provide: PLATFORM_ID, useValue: PLATFORM_SERVER_ID}, {provide: PLATFORM_INITIALIZER, useFactory: initDominoAdapter, multi: true}, { provide: PlatformLocation, useClass: ServerPlatformLocation, deps: [], }, {provide: PlatformState, deps: [DOCUMENT]}, ]; function initDominoAdapter() { const injector = inject(Injector); const _enableDomEmulation = enableDomEmulation(injector); return () => { if (_enableDomEmulation) { DominoAdapter.makeCurrent(); } else { BrowserDomAdapter.makeCurrent(); } }; } export const SERVER_RENDER_PROVIDERS: Provider[] = [ {provide: EVENT_MANAGER_PLUGINS, multi: true, useClass: ServerEventManagerPlugin}, ]; export const PLATFORM_SERVER_PROVIDERS: Provider[] = [ TRANSFER_STATE_SERIALIZATION_PROVIDERS, SERVER_RENDER_PROVIDERS, SERVER_HTTP_PROVIDERS, {provide: Testability, useValue: null}, // Keep for backwards-compatibility. {provide: TESTABILITY, useValue: null}, {provide: ViewportScroller, useClass: NullViewportScroller}, ]; /** * The ng module for the server. * * @publicApi */ @NgModule({ exports: [BrowserModule], providers: PLATFORM_SERVER_PROVIDERS, }) export class ServerModule {} function _document() { const injector = inject(Injector); const config: PlatformConfig | null = injector.get(INITIAL_CONFIG, null); const _enableDomEmulation = enableDomEmulation(injector); let document: Document; if (config && config.document) { document = typeof config.document === 'string' ? _enableDomEmulation ? parseDocument(config.document, config.url) : window.document : config.document; } else { document = getDOM().createHtmlDocument(); } // Tell ivy about the global document ɵsetDocument(document); return document; } /** * Creates a server-side instance of an Angular platform. * * This platform should be used when performing server-side rendering of an Angular application. * Standalone applications can be bootstrapped on the server using the `bootstrapApplication` * function from `@angular/platform-browser`. When using `bootstrapApplication`, the `platformServer` * should be created first and passed to the bootstrap function using the `BootstrapContext`. * * @publicApi */ export function platformServer(extraProviders?: StaticProvider[] | undefined): PlatformRef { const noServerModeSet = typeof ngServerMode === 'undefined'; if (noServerModeSet) { globalThis['ngServerMode'] = true; } const platform = createPlatformFactory( platformCore, 'server', INTERNAL_SERVER_PLATFORM_PROVIDERS, )(extraProviders); if (noServerModeSet) { platform.onDestroy(() => { globalThis['ngServerMode'] = undefined; }); } return platform; }