diff --git a/server.ts b/server.ts index e959600d28..499fe5c4ff 100644 --- a/server.ts +++ b/server.ts @@ -270,10 +270,8 @@ function serverSideRender(req, res, next, sendToUser: boolean = true) { .then((html) => { if (hasValue(html)) { // Replace REST URL with UI URL - if (environment.ui.replaceRestUrl && REST_BASE_URL !== environment.rest.baseUrl) { - const t0 = Date.now(); + if (environment.ssr.replaceRestUrl && REST_BASE_URL !== environment.rest.baseUrl) { html = html.replace(new RegExp(REST_BASE_URL, 'g'), environment.rest.baseUrl); - console.log(`Replaced all SSR URLs in HTML in ${Date.now() - t0}ms`); // todo: remove this } // save server side rendered page to cache (if any are enabled) diff --git a/src/config/default-app-config.ts b/src/config/default-app-config.ts index e81f77bff5..3c5e0ef0da 100644 --- a/src/config/default-app-config.ts +++ b/src/config/default-app-config.ts @@ -52,9 +52,6 @@ export class DefaultAppConfig implements AppConfig { // Trust X-FORWARDED-* headers from proxies useProxies: true, - - transferState: true, - replaceRestUrl: false, }; // The REST API server settings diff --git a/src/config/ssr-config.interface.ts b/src/config/ssr-config.interface.ts index 4def73962a..c9c5f8882b 100644 --- a/src/config/ssr-config.interface.ts +++ b/src/config/ssr-config.interface.ts @@ -21,6 +21,24 @@ export interface SSRConfig extends Config { */ inlineCriticalCss: boolean; + /** + * Enable state transfer from the server-side application to the client-side application. + * Defaults to true. + * + * Note: When using an external application cache layer, it's recommended not to transfer the state to avoid caching it. + * Disabling it ensures that dynamic state information is not inadvertently cached, which can improve security and + * ensure that users always use the most up-to-date state. + */ + transferState: boolean; + + /** + * When a different REST base URL is used for the server-side application, the generated state contains references to + * REST resources with the internal URL configured, so it is not transferred to the client application, by default. + * Enabling this setting transfers the state to the client application and replaces internal URLs with the public + * URLs used by the client application. + */ + replaceRestUrl: boolean; + /** * Paths to enable SSR for. Defaults to the home page and paths in the sitemap. */ diff --git a/src/config/ui-server-config.interface.ts b/src/config/ui-server-config.interface.ts index 2e58f9d6de..70e2fa3e26 100644 --- a/src/config/ui-server-config.interface.ts +++ b/src/config/ui-server-config.interface.ts @@ -13,7 +13,4 @@ export class UIServerConfig extends ServerConfig { // Trust X-FORWARDED-* headers from proxies useProxies: boolean; - - transferState: boolean; - replaceRestUrl: boolean; } diff --git a/src/environments/environment.production.ts b/src/environments/environment.production.ts index 8159fff2ea..72c49aa370 100644 --- a/src/environments/environment.production.ts +++ b/src/environments/environment.production.ts @@ -8,6 +8,8 @@ export const environment: Partial = { enabled: true, enablePerformanceProfiler: false, inlineCriticalCss: false, + transferState: true, + replaceRestUrl: false, paths: [ '/home', '/items/', '/entities/', '/collections/', '/communities/', '/bitstream/', '/bitstreams/', '/handle/' ], enableSearchComponent: false, enableBrowseComponent: false, diff --git a/src/environments/environment.test.ts b/src/environments/environment.test.ts index 17d4e8ed10..1525b1960b 100644 --- a/src/environments/environment.test.ts +++ b/src/environments/environment.test.ts @@ -12,6 +12,8 @@ export const environment: BuildConfig = { enabled: true, enablePerformanceProfiler: false, inlineCriticalCss: false, + transferState: true, + replaceRestUrl: false, paths: [ '/home', '/items/', '/entities/', '/collections/', '/communities/', '/bitstream/', '/bitstreams/', '/handle/' ], enableSearchComponent: false, enableBrowseComponent: false, diff --git a/src/environments/environment.ts b/src/environments/environment.ts index 4ac586d899..ff0c05e76d 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -13,6 +13,8 @@ export const environment: Partial = { enabled: false, enablePerformanceProfiler: false, inlineCriticalCss: false, + transferState: true, + replaceRestUrl: false, paths: [ '/home', '/items/', '/entities/', '/collections/', '/communities/', '/bitstream/', '/bitstreams/', '/handle/' ], enableSearchComponent: false, enableBrowseComponent: false, diff --git a/src/modules/app/browser-init.service.ts b/src/modules/app/browser-init.service.ts index 9ba103a655..3bbdf12b91 100644 --- a/src/modules/app/browser-init.service.ts +++ b/src/modules/app/browser-init.service.ts @@ -54,6 +54,7 @@ import { APP_CONFIG_STATE, AppConfig, } from '../../config/app-config.interface'; +import { BuildConfig } from '../../config/build-config.interface'; import { extendEnvironmentWithAppConfig } from '../../config/config.util'; import { DefaultAppConfig } from '../../config/default-app-config'; import { environment } from '../../environments/environment'; @@ -70,7 +71,7 @@ export class BrowserInitService extends InitService { protected store: Store, protected correlationIdService: CorrelationIdService, protected transferState: TransferState, - @Inject(APP_CONFIG) protected appConfig: AppConfig, + @Inject(APP_CONFIG) protected appConfig: BuildConfig, protected translate: TranslateService, protected localeService: LocaleService, protected angulartics2DSpace: Angulartics2DSpace, @@ -113,9 +114,7 @@ export class BrowserInitService extends InitService { protected init(): () => Promise { return async () => { - if (this.appConfig.ui.transferState) { - await this.loadAppState(); - } + await this.loadAppState(); this.checkAuthenticationToken(); this.externalAuthCheck(); this.initCorrelationId(); @@ -147,7 +146,7 @@ export class BrowserInitService extends InitService { */ private async loadAppState(): Promise { // The app state can be transferred only when SSR and CSR are using the same base url for the REST API - if (this.appConfig.ui.transferState && (!this.appConfig.rest.hasSsrBaseUrl || this.appConfig.ui.replaceRestUrl)) { + if (this.appConfig.ssr.transferState) { const state = this.transferState.get(InitService.NGRX_STATE, null); this.transferState.remove(InitService.NGRX_STATE); this.store.dispatch(new StoreAction(StoreActionTypes.REHYDRATE, state)); diff --git a/src/modules/app/server-init.service.ts b/src/modules/app/server-init.service.ts index 8e96e3e61d..60c6cbe413 100644 --- a/src/modules/app/server-init.service.ts +++ b/src/modules/app/server-init.service.ts @@ -21,7 +21,10 @@ import { LocaleService } from '../../app/core/locale/locale.service'; import { HeadTagService } from '../../app/core/metadata/head-tag.service'; import { CorrelationIdService } from '../../app/correlation-id/correlation-id.service'; import { InitService } from '../../app/init.service'; -import { isNotEmpty } from '../../app/shared/empty.util'; +import { + isEmpty, + isNotEmpty, +} from '../../app/shared/empty.util'; import { MenuService } from '../../app/shared/menu/menu.service'; import { ThemeService } from '../../app/shared/theme-support/theme.service'; import { Angulartics2DSpace } from '../../app/statistics/angulartics/dspace-provider'; @@ -30,6 +33,7 @@ import { APP_CONFIG_STATE, AppConfig, } from '../../config/app-config.interface'; +import { BuildConfig } from '../../config/build-config.interface'; import { environment } from '../../environments/environment'; /** @@ -41,7 +45,7 @@ export class ServerInitService extends InitService { protected store: Store, protected correlationIdService: CorrelationIdService, protected transferState: TransferState, - @Inject(APP_CONFIG) protected appConfig: AppConfig, + @Inject(APP_CONFIG) protected appConfig: BuildConfig, protected translate: TranslateService, protected localeService: LocaleService, protected angulartics2DSpace: Angulartics2DSpace, @@ -68,9 +72,7 @@ export class ServerInitService extends InitService { return async () => { this.checkAuthenticationToken(); this.saveAppConfigForCSR(); - if (this.appConfig.ui.transferState) { - this.saveAppState(); - } + this.saveAppState(); this.initCorrelationId(); this.checkEnvironment(); @@ -92,14 +94,16 @@ export class ServerInitService extends InitService { * @private */ private saveAppState() { - this.transferState.onSerialize(InitService.NGRX_STATE, () => { - let state; - this.store.pipe(take(1)).subscribe((saveState: any) => { - state = saveState; - }); + if (this.appConfig.ssr.transferState && (isEmpty(this.appConfig.rest.ssrBaseUrl) || this.appConfig.ssr.replaceRestUrl)) { + this.transferState.onSerialize(InitService.NGRX_STATE, () => { + let state; + this.store.pipe(take(1)).subscribe((saveState: any) => { + state = saveState; + }); - return state; - }); + return state; + }); + } } private saveAppConfigForCSR(): void {