mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
[DURACOM-247] Refactoring SSR configuration in order to align it with new nomenclature
This commit is contained in:
101
server.ts
101
server.ts
@@ -17,7 +17,6 @@
|
|||||||
|
|
||||||
import 'zone.js/node';
|
import 'zone.js/node';
|
||||||
import 'reflect-metadata';
|
import 'reflect-metadata';
|
||||||
import 'rxjs';
|
|
||||||
|
|
||||||
/* eslint-disable import/no-namespace */
|
/* eslint-disable import/no-namespace */
|
||||||
import * as morgan from 'morgan';
|
import * as morgan from 'morgan';
|
||||||
@@ -40,26 +39,25 @@ import { join } from 'path';
|
|||||||
import { enableProdMode } from '@angular/core';
|
import { enableProdMode } from '@angular/core';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import { environment } from './src/environments/environment';
|
import { environment } from './src/environments/environment';
|
||||||
import { createProxyMiddleware } from 'http-proxy-middleware';
|
import { createProxyMiddleware } from 'http-proxy-middleware';
|
||||||
import { hasNoValue, hasValue } from './src/app/shared/empty.util';
|
import { hasValue } from './src/app/shared/empty.util';
|
||||||
|
|
||||||
import { UIServerConfig } from './src/config/ui-server-config.interface';
|
import { UIServerConfig } from './src/config/ui-server-config.interface';
|
||||||
|
|
||||||
import bootstrap from './src/main.server';
|
import bootstrap from './src/main.server';
|
||||||
|
|
||||||
import { buildAppConfig } from './src/config/config.server';
|
import { buildAppConfig } from './src/config/config.server';
|
||||||
import { APP_CONFIG, AppConfig } from './src/config/app-config.interface';
|
import {
|
||||||
|
APP_CONFIG,
|
||||||
|
AppConfig,
|
||||||
|
} from './src/config/app-config.interface';
|
||||||
import { extendEnvironmentWithAppConfig } from './src/config/config.util';
|
import { extendEnvironmentWithAppConfig } from './src/config/config.util';
|
||||||
import { logStartupMessage } from './startup-message';
|
import { logStartupMessage } from './startup-message';
|
||||||
import { TOKENITEM } from './src/app/core/auth/models/auth-token-info.model';
|
import { TOKENITEM } from './src/app/core/auth/models/auth-token-info.model';
|
||||||
import { CommonEngine } from '@angular/ssr';
|
import { CommonEngine } from '@angular/ssr';
|
||||||
import { APP_BASE_HREF } from '@angular/common';
|
import { APP_BASE_HREF } from '@angular/common';
|
||||||
import { REQUEST, RESPONSE } from './src/express.tokens';
|
import {
|
||||||
import { dirname, resolve } from 'node:path';
|
REQUEST,
|
||||||
import { fileURLToPath } from 'node:url';
|
RESPONSE,
|
||||||
|
} from './src/express.tokens';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set path for the browser application's dist folder
|
* Set path for the browser application's dist folder
|
||||||
@@ -92,9 +90,6 @@ export function app() {
|
|||||||
* Create a new express application
|
* Create a new express application
|
||||||
*/
|
*/
|
||||||
const server = express();
|
const server = express();
|
||||||
const serverDistFolder = dirname(fileURLToPath(import.meta.url));
|
|
||||||
const browserDistFolder = resolve(serverDistFolder, '../browser');
|
|
||||||
const commonEngine = new CommonEngine();
|
|
||||||
|
|
||||||
// Tell Express to trust X-FORWARDED-* headers from proxies
|
// Tell Express to trust X-FORWARDED-* headers from proxies
|
||||||
// See https://expressjs.com/en/guide/behind-proxies.html
|
// See https://expressjs.com/en/guide/behind-proxies.html
|
||||||
@@ -134,27 +129,6 @@ export function app() {
|
|||||||
*/
|
*/
|
||||||
server.use(json());
|
server.use(json());
|
||||||
|
|
||||||
// Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
|
|
||||||
/* server.engine('html', (_, options, callback) =>
|
|
||||||
ngExpressEngine({
|
|
||||||
bootstrap,
|
|
||||||
providers: [
|
|
||||||
{
|
|
||||||
provide: REQUEST,
|
|
||||||
useValue: (options as any).req,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: RESPONSE,
|
|
||||||
useValue: (options as any).req.res,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: APP_CONFIG,
|
|
||||||
useValue: environment,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})(_, (options as any), callback),
|
|
||||||
);*/
|
|
||||||
|
|
||||||
server.engine('ejs', ejs.renderFile);
|
server.engine('ejs', ejs.renderFile);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -234,12 +208,7 @@ export function app() {
|
|||||||
* copy of the page (see cacheCheck())
|
* copy of the page (see cacheCheck())
|
||||||
*/
|
*/
|
||||||
router.get('*', cacheCheck, ngApp);
|
router.get('*', cacheCheck, ngApp);
|
||||||
// All regular routes use the Angular engine
|
|
||||||
// server.get('*', (req, res, next) => {
|
|
||||||
// const { protocol, originalUrl, baseUrl, headers } = req;
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// });
|
|
||||||
server.use(environment.ui.nameSpace, router);
|
server.use(environment.ui.nameSpace, router);
|
||||||
|
|
||||||
return server;
|
return server;
|
||||||
@@ -249,7 +218,7 @@ export function app() {
|
|||||||
* The callback function to serve server side angular
|
* The callback function to serve server side angular
|
||||||
*/
|
*/
|
||||||
function ngApp(req, res, next) {
|
function ngApp(req, res, next) {
|
||||||
if (environment.universal.preboot) {
|
if (environment.ssr.enabled) {
|
||||||
// Render the page to user via SSR (server side rendering)
|
// Render the page to user via SSR (server side rendering)
|
||||||
serverSideRender(req, res, next);
|
serverSideRender(req, res, next);
|
||||||
} else {
|
} else {
|
||||||
@@ -264,17 +233,19 @@ function ngApp(req, res, next) {
|
|||||||
* returned to the user.
|
* returned to the user.
|
||||||
* @param req current request
|
* @param req current request
|
||||||
* @param res current response
|
* @param res current response
|
||||||
|
* @param next the next function
|
||||||
* @param sendToUser if true (default), send the rendered content to the user.
|
* @param sendToUser if true (default), send the rendered content to the user.
|
||||||
* If false, then only save this rendered content to the in-memory cache (to refresh cache).
|
* If false, then only save this rendered content to the in-memory cache (to refresh cache).
|
||||||
*/
|
*/
|
||||||
function serverSideRender(req, res, next, sendToUser: boolean = true) {
|
function serverSideRender(req, res, next, sendToUser: boolean = true) {
|
||||||
const { protocol, originalUrl, baseUrl, headers } = req;
|
const { protocol, originalUrl, baseUrl, headers } = req;
|
||||||
const commonEngine = new CommonEngine();
|
const commonEngine = new CommonEngine({ enablePerformanceProfiler: environment.ssr.enablePerformanceProfiler });
|
||||||
// Render the page via SSR (server side rendering)
|
// Render the page via SSR (server side rendering)
|
||||||
commonEngine
|
commonEngine
|
||||||
.render({
|
.render({
|
||||||
bootstrap,
|
bootstrap,
|
||||||
documentFilePath: indexHtml,
|
documentFilePath: indexHtml,
|
||||||
|
inlineCriticalCss: environment.ssr.inlineCriticalCss,
|
||||||
url: `${protocol}://${headers.host}${originalUrl}`,
|
url: `${protocol}://${headers.host}${originalUrl}`,
|
||||||
publicPath: DIST_FOLDER,
|
publicPath: DIST_FOLDER,
|
||||||
providers: [
|
providers: [
|
||||||
@@ -293,29 +264,19 @@ function serverSideRender(req, res, next, sendToUser: boolean = true) {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
.then((html) => res.send(html))
|
.then((html) => {
|
||||||
.catch((err) => next(err));
|
if (hasValue(html)) {
|
||||||
|
|
||||||
|
|
||||||
/* res.render(indexHtml, {
|
|
||||||
req,
|
|
||||||
res,
|
|
||||||
preboot: environment.universal.preboot,
|
|
||||||
async: environment.universal.async,
|
|
||||||
time: environment.universal.time,
|
|
||||||
baseUrl: environment.ui.nameSpace,
|
|
||||||
originUrl: environment.ui.baseUrl,
|
|
||||||
requestUrl: req.originalUrl,
|
|
||||||
}, (err, data) => {
|
|
||||||
if (hasNoValue(err) && hasValue(data)) {
|
|
||||||
// save server side rendered page to cache (if any are enabled)
|
// save server side rendered page to cache (if any are enabled)
|
||||||
saveToCache(req, data);
|
saveToCache(req, html);
|
||||||
if (sendToUser) {
|
if (sendToUser) {
|
||||||
res.locals.ssr = true; // mark response as SSR (enables text compression)
|
res.locals.ssr = true; // mark response as SSR (enables text compression)
|
||||||
// send rendered page to user
|
// send rendered page to user
|
||||||
res.send(data);
|
res.send(html);
|
||||||
}
|
}
|
||||||
} else if (hasValue(err) && err.code === 'ERR_HTTP_HEADERS_SENT') {
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
if (hasValue(err) && err.code === 'ERR_HTTP_HEADERS_SENT') {
|
||||||
// When this error occurs we can't fall back to CSR because the response has already been
|
// When this error occurs we can't fall back to CSR because the response has already been
|
||||||
// sent. These errors occur for various reasons in universal, not all of which are in our
|
// sent. These errors occur for various reasons in universal, not all of which are in our
|
||||||
// control to solve.
|
// control to solve.
|
||||||
@@ -330,7 +291,8 @@ function serverSideRender(req, res, next, sendToUser: boolean = true) {
|
|||||||
clientSideRender(req, res);
|
clientSideRender(req, res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});*/
|
next(err);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -388,7 +350,7 @@ function initCache() {
|
|||||||
function botCacheEnabled(): boolean {
|
function botCacheEnabled(): boolean {
|
||||||
// Caching is only enabled if SSR is enabled AND
|
// Caching is only enabled if SSR is enabled AND
|
||||||
// "max" pages to cache is greater than zero
|
// "max" pages to cache is greater than zero
|
||||||
return environment.universal.preboot && environment.cache.serverSide.botCache.max && (environment.cache.serverSide.botCache.max > 0);
|
return environment.ssr.enabled && environment.cache.serverSide.botCache.max && (environment.cache.serverSide.botCache.max > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -397,7 +359,7 @@ function botCacheEnabled(): boolean {
|
|||||||
function anonymousCacheEnabled(): boolean {
|
function anonymousCacheEnabled(): boolean {
|
||||||
// Caching is only enabled if SSR is enabled AND
|
// Caching is only enabled if SSR is enabled AND
|
||||||
// "max" pages to cache is greater than zero
|
// "max" pages to cache is greater than zero
|
||||||
return environment.universal.preboot && environment.cache.serverSide.anonymousCache.max && (environment.cache.serverSide.anonymousCache.max > 0);
|
return environment.ssr.enabled && environment.cache.serverSide.anonymousCache.max && (environment.cache.serverSide.anonymousCache.max > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -410,9 +372,9 @@ function cacheCheck(req, res, next) {
|
|||||||
|
|
||||||
// If the bot cache is enabled and this request looks like a bot, check the bot cache for a cached page.
|
// If the bot cache is enabled and this request looks like a bot, check the bot cache for a cached page.
|
||||||
if (botCacheEnabled() && isbot(req.get('user-agent'))) {
|
if (botCacheEnabled() && isbot(req.get('user-agent'))) {
|
||||||
cachedCopy = checkCacheForRequest('bot', botCache, req, res);
|
cachedCopy = checkCacheForRequest('bot', botCache, req, res, next);
|
||||||
} else if (anonymousCacheEnabled() && !isUserAuthenticated(req)) {
|
} else if (anonymousCacheEnabled() && !isUserAuthenticated(req)) {
|
||||||
cachedCopy = checkCacheForRequest('anonymous', anonymousCache, req, res);
|
cachedCopy = checkCacheForRequest('anonymous', anonymousCache, req, res, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If cached copy exists, return it to the user.
|
// If cached copy exists, return it to the user.
|
||||||
@@ -448,9 +410,10 @@ function cacheCheck(req, res, next) {
|
|||||||
* @param cache LRU cache to check
|
* @param cache LRU cache to check
|
||||||
* @param req current request to look for in the cache
|
* @param req current request to look for in the cache
|
||||||
* @param res current response
|
* @param res current response
|
||||||
|
* @param next the next function
|
||||||
* @returns cached copy (if found) or undefined (if not found)
|
* @returns cached copy (if found) or undefined (if not found)
|
||||||
*/
|
*/
|
||||||
function checkCacheForRequest(cacheName: string, cache: LRU<string, any>, req, res): any {
|
function checkCacheForRequest(cacheName: string, cache: LRU<string, any>, req, res, next): any {
|
||||||
// Get the cache key for this request
|
// Get the cache key for this request
|
||||||
const key = getCacheKey(req);
|
const key = getCacheKey(req);
|
||||||
|
|
||||||
@@ -466,7 +429,7 @@ function checkCacheForRequest(cacheName: string, cache: LRU<string, any>, req, r
|
|||||||
// Update cached copy by rerendering server-side
|
// Update cached copy by rerendering server-side
|
||||||
// NOTE: In this scenario the currently cached copy will be returned to the current user.
|
// NOTE: In this scenario the currently cached copy will be returned to the current user.
|
||||||
// This re-render is peformed behind the scenes to update cached copy for next user.
|
// This re-render is peformed behind the scenes to update cached copy for next user.
|
||||||
serverSideRender(req, res, null, false);
|
serverSideRender(req, res, next, false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (environment.cache.serverSide.debug) { console.log(`CACHE MISS FOR ${key} in ${cacheName} cache.`); }
|
if (environment.cache.serverSide.debug) { console.log(`CACHE MISS FOR ${key} in ${cacheName} cache.`); }
|
||||||
@@ -570,7 +533,7 @@ function createHttpsServer(keys) {
|
|||||||
const listener = createServer({
|
const listener = createServer({
|
||||||
key: keys.serviceKey,
|
key: keys.serviceKey,
|
||||||
cert: keys.certificate,
|
cert: keys.certificate,
|
||||||
}, app).listen(environment.ui.port, environment.ui.host, () => {
|
}, app()).listen(environment.ui.port, environment.ui.host, () => {
|
||||||
serverStarted();
|
serverStarted();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import { AppConfig } from './app-config.interface';
|
import { AppConfig } from './app-config.interface';
|
||||||
import { UniversalConfig } from './universal-config.interface';
|
import { SSRConfig } from './ssr-config.interface';
|
||||||
|
|
||||||
export interface BuildConfig extends AppConfig {
|
export interface BuildConfig extends AppConfig {
|
||||||
universal: UniversalConfig;
|
ssr: SSRConfig;
|
||||||
}
|
}
|
||||||
|
@@ -34,7 +34,7 @@ export class DefaultAppConfig implements AppConfig {
|
|||||||
// NOTE: will log all redux actions and transfers in console
|
// NOTE: will log all redux actions and transfers in console
|
||||||
debug = false;
|
debug = false;
|
||||||
|
|
||||||
// Angular Universal server settings
|
// Angular express server settings
|
||||||
// NOTE: these must be 'synced' with the 'dspace.ui.url' setting in your backend's local.cfg.
|
// NOTE: these must be 'synced' with the 'dspace.ui.url' setting in your backend's local.cfg.
|
||||||
ui: UIServerConfig = {
|
ui: UIServerConfig = {
|
||||||
ssl: false,
|
ssl: false,
|
||||||
|
21
src/config/ssr-config.interface.ts
Normal file
21
src/config/ssr-config.interface.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { Config } from './config.interface';
|
||||||
|
|
||||||
|
export interface SSRConfig extends Config {
|
||||||
|
/**
|
||||||
|
* A boolean flag indicating whether the SSR configuration is enabled
|
||||||
|
* Defaults to true.
|
||||||
|
*/
|
||||||
|
enabled: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable request performance profiling data collection and printing the results in the server console.
|
||||||
|
* Defaults to false.
|
||||||
|
*/
|
||||||
|
enablePerformanceProfiler: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reduce render blocking requests by inlining critical CSS.
|
||||||
|
* Defaults to true.
|
||||||
|
*/
|
||||||
|
inlineCriticalCss: boolean;
|
||||||
|
}
|
@@ -6,5 +6,5 @@ export const StoreDevModules = [
|
|||||||
StoreDevtoolsModule.instrument({
|
StoreDevtoolsModule.instrument({
|
||||||
maxAge: 1000,
|
maxAge: 1000,
|
||||||
logOnly: false,
|
logOnly: false,
|
||||||
connectInZone: true}),
|
connectInZone: true }),
|
||||||
];
|
];
|
||||||
|
@@ -1,7 +0,0 @@
|
|||||||
import { Config } from './config.interface';
|
|
||||||
|
|
||||||
export interface UniversalConfig extends Config {
|
|
||||||
preboot: boolean;
|
|
||||||
async: boolean;
|
|
||||||
time: boolean;
|
|
||||||
}
|
|
@@ -3,10 +3,10 @@ import { BuildConfig } from '../config/build-config.interface';
|
|||||||
export const environment: Partial<BuildConfig> = {
|
export const environment: Partial<BuildConfig> = {
|
||||||
production: true,
|
production: true,
|
||||||
|
|
||||||
// Angular Universal settings
|
// Angular SSR settings
|
||||||
universal: {
|
ssr: {
|
||||||
preboot: true,
|
enabled: true,
|
||||||
async: true,
|
enablePerformanceProfiler: false,
|
||||||
time: false,
|
inlineCriticalCss: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@@ -7,14 +7,14 @@ import { NotificationAnimationsType } from '../app/shared/notifications/models/n
|
|||||||
export const environment: BuildConfig = {
|
export const environment: BuildConfig = {
|
||||||
production: false,
|
production: false,
|
||||||
|
|
||||||
// Angular Universal settings
|
// Angular SSR settings
|
||||||
universal: {
|
ssr: {
|
||||||
preboot: true,
|
enabled: true,
|
||||||
async: true,
|
enablePerformanceProfiler: false,
|
||||||
time: false,
|
inlineCriticalCss: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Angular Universal server settings.
|
// Angular express server settings.
|
||||||
ui: {
|
ui: {
|
||||||
ssl: false,
|
ssl: false,
|
||||||
host: 'dspace.com',
|
host: 'dspace.com',
|
||||||
|
@@ -8,11 +8,11 @@ import { BuildConfig } from '../config/build-config.interface';
|
|||||||
export const environment: Partial<BuildConfig> = {
|
export const environment: Partial<BuildConfig> = {
|
||||||
production: false,
|
production: false,
|
||||||
|
|
||||||
// Angular Universal settings
|
// Angular SSR settings
|
||||||
universal: {
|
ssr: {
|
||||||
preboot: false,
|
enabled: false,
|
||||||
async: true,
|
enablePerformanceProfiler: false,
|
||||||
time: false,
|
inlineCriticalCss: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -14,5 +14,4 @@ import { serverAppConfig } from './modules/app/server-app.config';
|
|||||||
|
|
||||||
const bootstrap = () => bootstrapApplication(AppComponent, serverAppConfig);
|
const bootstrap = () => bootstrapApplication(AppComponent, serverAppConfig);
|
||||||
|
|
||||||
export { renderModule } from '@angular/platform-server';
|
|
||||||
export default bootstrap;
|
export default bootstrap;
|
||||||
|
Reference in New Issue
Block a user