From 88cb397dc9dde018741d2a372b72866370db8456 Mon Sep 17 00:00:00 2001 From: Yury Bondarenko Date: Tue, 7 Feb 2023 15:01:01 +0100 Subject: [PATCH] Fix direct CSR By moving from environment.ts to config.yml we made it so the environment is _not_ up to date with the server configuration when main.js is first loaded. Because of this the app behaved as if CSR always happened _after_ SSR, effectively breaking direct CSR. Here the "criterion" for SSR/non-SSR HTML is changed from the related configuration property to the presence of Angular Universal transfer state. This means we can correctly determine when to bootstrap the app for direct CSR, and it's' now "safe" to just send index.html by itself. --- server.ts | 22 +++++----------------- src/index.csr.html | 18 ------------------ src/main.browser.ts | 19 +++++++++++++------ 3 files changed, 18 insertions(+), 41 deletions(-) delete mode 100644 src/index.csr.html diff --git a/server.ts b/server.ts index 81137ad56a..0fecf6bd52 100644 --- a/server.ts +++ b/server.ts @@ -31,7 +31,6 @@ import * as expressStaticGzip from 'express-static-gzip'; import { existsSync, readFileSync } from 'fs'; import { join } from 'path'; -import { APP_BASE_HREF } from '@angular/common'; import { enableProdMode } from '@angular/core'; import { ngExpressEngine } from '@nguniversal/express-engine'; @@ -57,7 +56,7 @@ const DIST_FOLDER = join(process.cwd(), 'dist/browser'); // Set path fir IIIF viewer. const IIIF_VIEWER = join(process.cwd(), 'dist/iiif'); -const indexHtml = existsSync(join(DIST_FOLDER, 'index.html')) ? 'index.html' : 'index'; +const indexHtml = join(DIST_FOLDER, 'index.html'); const cookieParser = require('cookie-parser'); @@ -207,7 +206,6 @@ function ngApp(req, res) { baseUrl: environment.ui.nameSpace, originUrl: environment.ui.baseUrl, requestUrl: req.originalUrl, - providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] }, (err, data) => { if (hasNoValue(err) && hasValue(data)) { res.locals.ssr = true; // mark response as SSR @@ -222,25 +220,15 @@ function ngApp(req, res) { if (hasValue(err)) { console.warn('Error details : ', err); } - res.render(indexHtml, { - req, - providers: [{ - provide: APP_BASE_HREF, - useValue: req.baseUrl - }] - }); + + res.sendFile(indexHtml); } }); } else { // If preboot is disabled, just serve the client console.log('Universal off, serving for direct CSR'); - res.render(indexHtml, { - req, - providers: [{ - provide: APP_BASE_HREF, - useValue: req.baseUrl - }] - }); + + res.sendFile(indexHtml); } } diff --git a/src/index.csr.html b/src/index.csr.html deleted file mode 100644 index b1ef4343b1..0000000000 --- a/src/index.csr.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - DSpace - - - - - - - - - - - diff --git a/src/main.browser.ts b/src/main.browser.ts index d5efe828c3..68debfb355 100644 --- a/src/main.browser.ts +++ b/src/main.browser.ts @@ -2,21 +2,27 @@ import 'zone.js'; import 'reflect-metadata'; import 'core-js/es/reflect'; -import { enableProdMode } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { load as loadWebFont } from 'webfontloader'; -import { hasValue } from './app/shared/empty.util'; - import { BrowserAppModule } from './modules/app/browser-app.module'; import { environment } from './environments/environment'; import { AppConfig } from './config/app-config.interface'; import { extendEnvironmentWithAppConfig } from './config/config.util'; +import { enableProdMode } from '@angular/core'; const bootstrap = () => platformBrowserDynamic() .bootstrapModule(BrowserAppModule, {}); +/** + * We use this to determine have been serven SSR HTML or not. + * + * At this point, {@link environment} may not be in sync with the configuration. + * Therefore, we cannot depend on it to determine how to bootstrap the app. + */ +const hasTransferState = document.querySelector('script#dspace-angular-state') !== null; + const main = () => { // Load fonts async // https://github.com/typekit/webfontloader#configuration @@ -30,22 +36,23 @@ const main = () => { enableProdMode(); } - if (hasValue(environment.universal) && environment.universal.preboot) { + if (hasTransferState) { + // Configuration will be taken from transfer state during initialization return bootstrap(); } else { + // Configuration must be fetched explicitly return fetch('assets/config.json') .then((response) => response.json()) .then((appConfig: AppConfig) => { // extend environment with app config for browser when not prerendered extendEnvironmentWithAppConfig(environment, appConfig); - return bootstrap(); }); } }; // support async tag or hmr -if (document.readyState === 'complete' && hasValue(environment.universal) && !environment.universal.preboot) { +if (document.readyState === 'complete' && !hasTransferState) { main(); } else { document.addEventListener('DOMContentLoaded', main);