mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
feat(platform-server): support document reference in render functions (#47032)
This commit updates the `renderModule` and `renderApplication` functions to also accept a document reference (in addition to the serialized document contents as a string). This should provide the necessary flexibility to NgUniversal (and other API consumers) to structure the logic to avoid serializing and parsing document multiple times during the SSR request. PR Close #47032
This commit is contained in:
committed by
Dylan Hunn
parent
de1e28006b
commit
2b4d7f6733
@@ -81,9 +81,14 @@ export class ServerModule {
|
||||
}
|
||||
|
||||
function _document(injector: Injector) {
|
||||
let config: PlatformConfig|null = injector.get(INITIAL_CONFIG, null);
|
||||
const document = config && config.document ? parseDocument(config.document, config.url) :
|
||||
getDOM().createHtmlDocument();
|
||||
const config: PlatformConfig|null = injector.get(INITIAL_CONFIG, null);
|
||||
let document: Document;
|
||||
if (config && config.document) {
|
||||
document = typeof config.document === 'string' ? parseDocument(config.document, config.url) :
|
||||
config.document;
|
||||
} else {
|
||||
document = getDOM().createHtmlDocument();
|
||||
}
|
||||
// Tell ivy about the global document
|
||||
ɵsetDocument(document);
|
||||
return document;
|
||||
|
||||
@@ -16,7 +16,7 @@ import {BEFORE_APP_SERIALIZED, INITIAL_CONFIG} from './tokens';
|
||||
import {TRANSFER_STATE_SERIALIZATION_PROVIDERS} from './transfer_state';
|
||||
|
||||
interface PlatformOptions {
|
||||
document?: string;
|
||||
document?: string|Document;
|
||||
url?: string;
|
||||
platformProviders?: Provider[];
|
||||
}
|
||||
@@ -95,14 +95,16 @@ the server-rendered app can be properly bootstrapped into a client app.`);
|
||||
/**
|
||||
* Renders a Module to string.
|
||||
*
|
||||
* `document` is the full document HTML of the page to render, as a string.
|
||||
* `document` is the document of the page to render, either as an HTML string or
|
||||
* as a reference to the `document` instance.
|
||||
* `url` is the URL for the current render request.
|
||||
* `extraProviders` are the platform level providers for the current render request.
|
||||
*
|
||||
* @publicApi
|
||||
*/
|
||||
export function renderModule<T>(
|
||||
module: Type<T>, options: {document?: string, url?: string, extraProviders?: StaticProvider[]}):
|
||||
module: Type<T>,
|
||||
options: {document?: string|Document, url?: string, extraProviders?: StaticProvider[]}):
|
||||
Promise<string> {
|
||||
const {document, url, extraProviders: platformProviders} = options;
|
||||
const platform = _getPlatform(platformDynamicServer, {document, url, platformProviders});
|
||||
@@ -130,7 +132,8 @@ export function renderModule<T>(
|
||||
* - `appId` - a string identifier of this application. The appId is used to prefix all
|
||||
* server-generated stylings and state keys of the application in TransferState
|
||||
* use-cases.
|
||||
* - `document` - the full document HTML of the page to render, as a string.
|
||||
* - `document` - the document of the page to render, either as an HTML string or
|
||||
* as a reference to the `document` instance.
|
||||
* - `url` - the URL for the current render request.
|
||||
* - `providers` - set of application level providers for the current render request.
|
||||
* - `platformProviders` - the platform level providers for the current render request.
|
||||
@@ -141,7 +144,7 @@ export function renderModule<T>(
|
||||
*/
|
||||
export function renderApplication<T>(rootComponent: Type<T>, options: {
|
||||
appId: string,
|
||||
document?: string,
|
||||
document?: string|Document,
|
||||
url?: string,
|
||||
providers?: Array<Provider|ImportedNgModuleProviders>,
|
||||
platformProviders?: Provider[],
|
||||
|
||||
@@ -11,7 +11,7 @@ import {DOCUMENT, isPlatformServer, PlatformLocation, ɵgetDOM as getDOM} from '
|
||||
import {HTTP_INTERCEPTORS, HttpClient, HttpClientModule, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http';
|
||||
import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
|
||||
import {ApplicationRef, CompilerFactory, Component, destroyPlatform, getPlatform, HostBinding, HostListener, importProvidersFrom, Inject, Injectable, Input, NgModule, NgZone, OnInit, PLATFORM_ID, PlatformRef, Type, ViewEncapsulation} from '@angular/core';
|
||||
import {inject, waitForAsync} from '@angular/core/testing';
|
||||
import {inject, TestBed, waitForAsync} from '@angular/core/testing';
|
||||
import {BrowserModule, makeStateKey, Title, TransferState} from '@angular/platform-browser';
|
||||
import {BEFORE_APP_SERIALIZED, INITIAL_CONFIG, platformDynamicServer, PlatformState, renderModule, renderModuleFactory, ServerModule, ServerTransferStateModule} from '@angular/platform-server';
|
||||
import {Observable} from 'rxjs';
|
||||
@@ -750,6 +750,38 @@ describe('platform-server integration', () => {
|
||||
});
|
||||
}));
|
||||
|
||||
it(`using ${isStandalone ? 'renderApplication' : 'renderModule'} ` +
|
||||
`should allow passing a document reference`,
|
||||
waitForAsync(() => {
|
||||
const document = TestBed.inject(DOCUMENT);
|
||||
|
||||
// Append root element based on the app selector.
|
||||
const rootEl = document.createElement('app');
|
||||
document.body.appendChild(rootEl);
|
||||
|
||||
// Append a special marker to verify that we use a correct instance
|
||||
// of the document for rendering.
|
||||
const markerEl = document.createComment('test marker');
|
||||
document.body.appendChild(markerEl);
|
||||
|
||||
const options = {document};
|
||||
const bootstrap = isStandalone ?
|
||||
renderApplication(MyAsyncServerAppStandalone, {document, appId: 'simple-cmp'}) :
|
||||
renderModule(AsyncServerModule, options);
|
||||
bootstrap
|
||||
.then(output => {
|
||||
expect(output).toBe(
|
||||
'<html><head><title>fakeTitle</title></head>' +
|
||||
'<body><app ng-version="0.0.0-PLACEHOLDER">Works!<h1 textcontent="fine">fine</h1></app>' +
|
||||
'<!--test marker--></body></html>');
|
||||
called = true;
|
||||
})
|
||||
.finally(() => {
|
||||
rootEl.remove();
|
||||
markerEl.remove();
|
||||
});
|
||||
}));
|
||||
|
||||
it('works with SVG elements', waitForAsync(() => {
|
||||
const options = {document: doc};
|
||||
const bootstrap = isStandalone ?
|
||||
|
||||
Reference in New Issue
Block a user