Skip to content

Commit 25e220a

Browse files
AndrewKushniralxhub
authored andcommitted
fix(platform-server): avoid duplicate TransferState info after renderApplication call (#49094)
This commit updates the `renderApplication` function to avoid duplicate serialization of the data from the `TransferState` class. The `renderApplication` function imports providers from the `ServerModule`, which already include the `TransferState` serialization providers, but the same providers were also included inside the `renderApplication` as well, which led to the duplication. PR Close #49094
1 parent c95766e commit 25e220a

File tree

2 files changed

+46
-3
lines changed

2 files changed

+46
-3
lines changed

packages/platform-server/src/utils.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,6 @@ export function renderApplication<T>(rootComponent: Type<T>, options: {
198198
const appProviders = [
199199
importProvidersFrom(BrowserModule.withServerTransition({appId})),
200200
importProvidersFrom(ServerModule),
201-
...TRANSFER_STATE_SERIALIZATION_PROVIDERS,
202201
...(options.providers ?? []),
203202
];
204203
return _render(platform, internalCreateApplication({rootComponent, appProviders}));

packages/platform-server/test/integration_spec.ts

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ import {animate, AnimationBuilder, state, style, transition, trigger} from '@ang
1010
import {DOCUMENT, isPlatformServer, PlatformLocation, ɵgetDOM as getDOM} from '@angular/common';
1111
import {HTTP_INTERCEPTORS, HttpClient, HttpClientModule, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http';
1212
import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
13-
import {ApplicationRef, CompilerFactory, Component, destroyPlatform, getPlatform, HostListener, Inject, Injectable, Input, NgModule, NgZone, PLATFORM_ID, PlatformRef, ViewEncapsulation} from '@angular/core';
13+
import {ApplicationRef, CompilerFactory, Component, destroyPlatform, getPlatform, HostListener, Inject, inject as coreInject, Injectable, Input, NgModule, NgZone, PLATFORM_ID, PlatformRef, ViewEncapsulation} from '@angular/core';
1414
import {inject, TestBed, waitForAsync} from '@angular/core/testing';
15-
import {BrowserModule, Title} from '@angular/platform-browser';
15+
import {BrowserModule, makeStateKey, Title, TransferState} from '@angular/platform-browser';
1616
import {BEFORE_APP_SERIALIZED, INITIAL_CONFIG, platformDynamicServer, PlatformState, renderModule, renderModuleFactory, ServerModule} from '@angular/platform-server';
1717
import {Observable} from 'rxjs';
1818
import {first} from 'rxjs/operators';
@@ -298,6 +298,33 @@ const MyStylesAppStandalone = createMyStylesApp(true);
298298
class ExampleStylesModule {
299299
}
300300

301+
function createMyTransferStateApp(standalone: boolean) {
302+
@Component({
303+
standalone,
304+
selector: 'app',
305+
template: `<div>Works!</div>`,
306+
})
307+
class MyStylesApp {
308+
state = coreInject(TransferState);
309+
constructor() {
310+
this.state.set(makeStateKey<string>('some-key'), 'some-value');
311+
}
312+
}
313+
return MyStylesApp;
314+
}
315+
316+
const MyTransferStateApp = createMyTransferStateApp(false);
317+
const MyTransferStateAppStandalone = createMyTransferStateApp(true);
318+
319+
320+
@NgModule({
321+
declarations: [MyTransferStateApp],
322+
imports: [BrowserModule.withServerTransition({appId: 'transfer-state-app'}), ServerModule],
323+
bootstrap: [MyTransferStateApp]
324+
})
325+
class MyTransferStateModule {
326+
}
327+
301328
@NgModule({
302329
bootstrap: [MyServerApp],
303330
imports: [MyServerAppModule, ServerModule, HttpClientModule, HttpClientTestingModule],
@@ -828,6 +855,23 @@ describe('platform-server integration', () => {
828855
});
829856
}));
830857

858+
it(`using ${isStandalone ? 'renderApplication' : 'renderModule'} ` +
859+
`should serialize transfer state only once`,
860+
waitForAsync(() => {
861+
const options = {document: doc};
862+
const bootstrap = isStandalone ?
863+
renderApplication(
864+
MyTransferStateAppStandalone, {...options, appId: 'transfer-state-app'}) :
865+
renderModule(MyTransferStateModule, {...options});
866+
bootstrap.then(output => {
867+
const expectedOutput =
868+
'<html><head></head><body><app ng-version="0.0.0-PLACEHOLDER" ng-server-context="other"><div>Works!</div></app>' +
869+
'<script id="transfer-state-app-state" type="application/json">{&q;some-key&q;:&q;some-value&q;}</script></body></html>';
870+
expect(output).toEqual(expectedOutput);
871+
called = true;
872+
});
873+
}));
874+
831875
it('uses `other` as the `serverContext` value when all symbols are removed after sanitization',
832876
waitForAsync(() => {
833877
const options = {

0 commit comments

Comments
 (0)