Skip to content

Commit

Permalink
[template/angular] [follow-up] Prevent client-side dictionary API cal…
Browse files Browse the repository at this point in the history
…l when SSR data is available
  • Loading branch information
illiakovalenko committed Sep 18, 2024
1 parent cc443e1 commit 8eed993
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 57 deletions.
103 changes: 68 additions & 35 deletions docs/upgrades/unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,43 +47,76 @@
}
```

* Update jss-translation-client-loader service to get the performance improvement during fetching Dictionary Data for SSR
* In `/src/app/i18n/jss-translation-client-loader.service.ts`
* Add import for TranferState and of
```
import { TransferState } from '@angular/core';
import { of } from 'rxjs';
```
* Update `dictionaryStateKey` variable type
```
export const dictionaryStateKey = makeStateKey<{ [key: string]: string }>('jssDictionary');
```
* Add `transferState` variable to constructor
```
constructor(private fallbackLoader: TranslateLoader, private transferState: TransferState) {}
```
* Update the `getTranslation` method
```
getTranslation(lang: string) {
const storedDictionary = this.transferState.get<{ [key: string]: string } | null>(
dictionaryStateKey,
null
);

if (storedDictionary !== null && Object.keys(storedDictionary).length > 0) {
return of(storedDictionary);
}

...
}
```
* Update `/src/templates/angular/src/app/app.module.ts`
```
* Update i18n initialization to gain the performance improvement during fetching Dictionary Data for using SSR:
* Inject _TransferState_ both on the server and client side:
`app.module.ts`:

```ts
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: (transferState: TransferState) =>
new JssTranslationClientLoaderService(new JssTranslationLoaderService(), transferState),
deps: [TransferState],
},
}),
```

`app.server.module.ts`:

```ts
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: (
ssrViewBag: {
[key: string]: unknown;
dictionary: { [key: string]: string };
},
transferState: TransferState
) => new JssTranslationServerLoaderService(ssrViewBag, transferState),
deps: ['JSS_SERVER_VIEWBAG', TransferState],
},
}),
```

* In `app\i18n\jss-translation-server-loader.service.ts`:
* Inject _TransferState_.
* Make sure to set _dictionary_ data in _transferState_.

```ts
export const dictionaryStateKey: StateKey<DictionaryPhrases> = makeStateKey<DictionaryPhrases>(
'dictionary'
);
...
getTranslation(_lang: string) {
const dictionary = this.serverViewBag.dictionary;
this.transferState.set(dictionaryStateKey, dictionary);
...
useFactory: (transferState: TransferState) =>
new JssTranslationClientLoaderService(new JssTranslationLoaderService(), transferState),
}
```

* In `app\i18n\jss-translation-client-loader.service.ts`:
* Inject _TransferState_.
* Make sure to check for _dictionary_ data in _transferState_ and use it if available and provided by the server.

```ts
import { dictionaryStateKey } from './jss-translation-server-loader.service';
...
getTranslation(lang: string): Observable<DictionaryPhrases> {
const dictionary = this.transferState.get(dictionaryStateKey, null);
if (dictionary) {
return of(dictionary);
}
...
```
}
```

# Angular - XMCloud

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { APP_ID, NgModule, TransferState } from '@angular/core';
import { APP_BASE_HREF } from '@angular/common';
import { HttpClientModule, HttpClient } from '@angular/common/http';
import { HttpClientModule } from '@angular/common/http';
import { RoutingModule } from './routing/routing.module';
import { JssLayoutService } from './layout/jss-layout.service';
import { AppComponentsModule } from './components/app-components.module';
Expand All @@ -22,7 +22,7 @@ import { JssContextService } from './jss-context.service';
provide: TranslateLoader,
useFactory: (transferState: TransferState) =>
new JssTranslationClientLoaderService(new JssTranslationLoaderService(), transferState),
deps: [HttpClient, TransferState],
deps: [TransferState],
},
}),
AppComponentsModule,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { NgModule } from '@angular/core';
import { NgModule, TransferState } from '@angular/core';
import { ServerModule } from '@angular/platform-server';
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';

Expand All @@ -18,11 +18,14 @@ import { JssTranslationServerLoaderService } from './i18n/jss-translation-server
// <-- *Important* to get translation values server-side
loader: {
provide: TranslateLoader,
useFactory: (ssrViewBag: {
[key: string]: unknown;
dictionary: { [key: string]: string };
}) => new JssTranslationServerLoaderService(ssrViewBag),
deps: ['JSS_SERVER_VIEWBAG'],
useFactory: (
ssrViewBag: {
[key: string]: unknown;
dictionary: { [key: string]: string };
},
transferState: TransferState
) => new JssTranslationServerLoaderService(ssrViewBag, transferState),
deps: ['JSS_SERVER_VIEWBAG', TransferState],
},
}),
],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
import { makeStateKey, Injectable, TransferState } from '@angular/core';
import { Injectable, TransferState } from '@angular/core';
import { TranslateLoader } from '@ngx-translate/core';
import { EMPTY, of } from 'rxjs';

export const dictionaryStateKey = makeStateKey<{ [key: string]: string }>('jssDictionary');
import { DictionaryPhrases } from '@sitecore-jss/sitecore-jss-angular';
import { EMPTY, Observable, of } from 'rxjs';
import { JssTranslationLoaderService } from './jss-translation-loader.service';
import { dictionaryStateKey } from './jss-translation-server-loader.service';

@Injectable()
export class JssTranslationClientLoaderService implements TranslateLoader {
constructor(private fallbackLoader: TranslateLoader, private transferState: TransferState) {}
constructor(
private fallbackLoader: JssTranslationLoaderService,
private transferState: TransferState
) {}

getTranslation(lang: string) {
const storedDictionary = this.transferState.get<{ [key: string]: string } | null>(
dictionaryStateKey,
null
);
getTranslation(lang: string): Observable<DictionaryPhrases> {
const dictionary = this.transferState.get(dictionaryStateKey, null);

if (storedDictionary !== null && Object.keys(storedDictionary).length > 0) {
return of(storedDictionary);
if (dictionary) {
return of(dictionary);
}

if (!this.fallbackLoader) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,29 @@
import { Inject, Injectable } from '@angular/core';
import { Inject, Injectable, makeStateKey, StateKey, TransferState } from '@angular/core';
import { TranslateLoader } from '@ngx-translate/core';
import { DictionaryPhrases } from '@sitecore-jss/sitecore-jss-angular';
import { of as observableOf, EMPTY } from 'rxjs';

export const dictionaryStateKey: StateKey<DictionaryPhrases> = makeStateKey<DictionaryPhrases>(
'dictionary'
);

@Injectable()
export class JssTranslationServerLoaderService implements TranslateLoader {
constructor(
// this initial state from sitecore is injected by server.bundle for "integrated" mode
@Inject('JSS_SERVER_VIEWBAG')
private serverViewBag: { [key: string]: unknown; dictionary: { [key: string]: string } }
private serverViewBag: { [key: string]: unknown; dictionary: DictionaryPhrases },
private transferState: TransferState
) {}
getTranslation(_lang: string) {
// read initial dictionary from data injected via server.bundle wrapper
const dictionary = this.serverViewBag.dictionary;

// set the dictionary in transfer state for the client
// since for ng-translate there is no obvious way to pass the server side dictionary to the client
// https://github.com/ngx-translate/core/issues/1207#issuecomment-700741671
this.transferState.set(dictionaryStateKey, dictionary);

if (dictionary) {
return observableOf(dictionary);
}
Expand Down
1 change: 1 addition & 0 deletions packages/sitecore-jss-angular/src/public_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export {
DictionaryService,
GraphQLDictionaryService,
RestDictionaryService,
DictionaryPhrases,
} from '@sitecore-jss/sitecore-jss/i18n';
export {
LayoutService,
Expand Down

0 comments on commit 8eed993

Please sign in to comment.