mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
[DURACOM-234] WIP fix SSR
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,4 +1,5 @@
|
|||||||
/.angular/cache
|
/.angular/cache
|
||||||
|
/.nx
|
||||||
/__build__
|
/__build__
|
||||||
/__server_build__
|
/__server_build__
|
||||||
/node_modules
|
/node_modules
|
||||||
|
12
angular.json
12
angular.json
@@ -109,15 +109,15 @@
|
|||||||
"serve": {
|
"serve": {
|
||||||
"builder": "@angular-builders/custom-webpack:dev-server",
|
"builder": "@angular-builders/custom-webpack:dev-server",
|
||||||
"options": {
|
"options": {
|
||||||
"browserTarget": "dspace-angular:build",
|
"buildTarget": "dspace-angular:build",
|
||||||
"port": 4000
|
"port": 4000
|
||||||
},
|
},
|
||||||
"configurations": {
|
"configurations": {
|
||||||
"development": {
|
"development": {
|
||||||
"browserTarget": "dspace-angular:build:development"
|
"buildTarget": "dspace-angular:build:development"
|
||||||
},
|
},
|
||||||
"production": {
|
"production": {
|
||||||
"browserTarget": "dspace-angular:build:production"
|
"buildTarget": "dspace-angular:build:production"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -219,13 +219,13 @@
|
|||||||
"serve-ssr": {
|
"serve-ssr": {
|
||||||
"builder": "@angular-devkit/build-angular:ssr-dev-server",
|
"builder": "@angular-devkit/build-angular:ssr-dev-server",
|
||||||
"options": {
|
"options": {
|
||||||
"browserTarget": "dspace-angular:build",
|
"buildTarget": "dspace-angular:build",
|
||||||
"serverTarget": "dspace-angular:server",
|
"serverTarget": "dspace-angular:server",
|
||||||
"port": 4000
|
"port": 4000
|
||||||
},
|
},
|
||||||
"configurations": {
|
"configurations": {
|
||||||
"production": {
|
"production": {
|
||||||
"browserTarget": "dspace-angular:build:production",
|
"buildTarget": "dspace-angular:build:production",
|
||||||
"serverTarget": "dspace-angular:server:production"
|
"serverTarget": "dspace-angular:server:production"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -233,7 +233,7 @@
|
|||||||
"prerender": {
|
"prerender": {
|
||||||
"builder": "@angular-devkit/build-angular:prerender",
|
"builder": "@angular-devkit/build-angular:prerender",
|
||||||
"options": {
|
"options": {
|
||||||
"browserTarget": "dspace-angular:build:production",
|
"buildTarget": "dspace-angular:build:production",
|
||||||
"serverTarget": "dspace-angular:server:production",
|
"serverTarget": "dspace-angular:server:production",
|
||||||
"routes": [
|
"routes": [
|
||||||
"/"
|
"/"
|
||||||
|
@@ -200,7 +200,7 @@
|
|||||||
"sass-loader": "^12.6.0",
|
"sass-loader": "^12.6.0",
|
||||||
"sass-resources-loader": "^2.2.5",
|
"sass-resources-loader": "^2.2.5",
|
||||||
"ts-node": "^8.10.2",
|
"ts-node": "^8.10.2",
|
||||||
"typescript": "~5.4.2",
|
"typescript": "~5.3.3",
|
||||||
"webpack": "5.76.1",
|
"webpack": "5.76.1",
|
||||||
"webpack-bundle-analyzer": "^4.8.0",
|
"webpack-bundle-analyzer": "^4.8.0",
|
||||||
"webpack-cli": "^4.2.0",
|
"webpack-cli": "^4.2.0",
|
||||||
|
62
server.ts
62
server.ts
@@ -39,8 +39,7 @@ import { join } from 'path';
|
|||||||
|
|
||||||
import { enableProdMode } from '@angular/core';
|
import { enableProdMode } from '@angular/core';
|
||||||
|
|
||||||
import { ngExpressEngine } from '@nguniversal/express-engine';
|
|
||||||
import { REQUEST, RESPONSE } from '@nguniversal/express-engine/tokens';
|
|
||||||
|
|
||||||
import { environment } from './src/environments/environment';
|
import { environment } from './src/environments/environment';
|
||||||
import { createProxyMiddleware } from 'http-proxy-middleware';
|
import { createProxyMiddleware } from 'http-proxy-middleware';
|
||||||
@@ -55,6 +54,11 @@ 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 { APP_BASE_HREF } from '@angular/common';
|
||||||
|
import { REQUEST, RESPONSE } from './src/express.tokens';
|
||||||
|
import { dirname, resolve } from 'node:path';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -88,6 +92,9 @@ 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
|
||||||
@@ -128,7 +135,7 @@ export function app() {
|
|||||||
server.use(json());
|
server.use(json());
|
||||||
|
|
||||||
// Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
|
// Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
|
||||||
server.engine('html', (_, options, callback) =>
|
/* server.engine('html', (_, options, callback) =>
|
||||||
ngExpressEngine({
|
ngExpressEngine({
|
||||||
bootstrap,
|
bootstrap,
|
||||||
providers: [
|
providers: [
|
||||||
@@ -146,7 +153,7 @@ export function app() {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
})(_, (options as any), callback),
|
})(_, (options as any), callback),
|
||||||
);
|
);*/
|
||||||
|
|
||||||
server.engine('ejs', ejs.renderFile);
|
server.engine('ejs', ejs.renderFile);
|
||||||
|
|
||||||
@@ -227,7 +234,12 @@ 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;
|
||||||
@@ -236,10 +248,10 @@ export function app() {
|
|||||||
/*
|
/*
|
||||||
* The callback function to serve server side angular
|
* The callback function to serve server side angular
|
||||||
*/
|
*/
|
||||||
function ngApp(req, res) {
|
function ngApp(req, res, next) {
|
||||||
if (environment.universal.preboot) {
|
if (environment.universal.preboot) {
|
||||||
// Render the page to user via SSR (server side rendering)
|
// Render the page to user via SSR (server side rendering)
|
||||||
serverSideRender(req, res);
|
serverSideRender(req, res, next);
|
||||||
} else {
|
} else {
|
||||||
// If preboot is disabled, just serve the client
|
// If preboot is disabled, just serve the client
|
||||||
console.log('Universal off, serving for direct client-side rendering (CSR)');
|
console.log('Universal off, serving for direct client-side rendering (CSR)');
|
||||||
@@ -255,9 +267,37 @@ function ngApp(req, res) {
|
|||||||
* @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, sendToUser: boolean = true) {
|
function serverSideRender(req, res, next, sendToUser: boolean = true) {
|
||||||
|
const { protocol, originalUrl, baseUrl, headers } = req;
|
||||||
|
const commonEngine = new CommonEngine();
|
||||||
// Render the page via SSR (server side rendering)
|
// Render the page via SSR (server side rendering)
|
||||||
res.render(indexHtml, {
|
commonEngine
|
||||||
|
.render({
|
||||||
|
bootstrap,
|
||||||
|
documentFilePath: indexHtml,
|
||||||
|
url: `${protocol}://${headers.host}${originalUrl}`,
|
||||||
|
publicPath: DIST_FOLDER,
|
||||||
|
providers: [
|
||||||
|
{ provide: APP_BASE_HREF, useValue: baseUrl },
|
||||||
|
{
|
||||||
|
provide: REQUEST,
|
||||||
|
useValue: req,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: RESPONSE,
|
||||||
|
useValue: res,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: APP_CONFIG,
|
||||||
|
useValue: environment,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
.then((html) => res.send(html))
|
||||||
|
.catch((err) => next(err));
|
||||||
|
|
||||||
|
|
||||||
|
/* res.render(indexHtml, {
|
||||||
req,
|
req,
|
||||||
res,
|
res,
|
||||||
preboot: environment.universal.preboot,
|
preboot: environment.universal.preboot,
|
||||||
@@ -290,7 +330,7 @@ function serverSideRender(req, res, sendToUser: boolean = true) {
|
|||||||
clientSideRender(req, res);
|
clientSideRender(req, res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -426,7 +466,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, false);
|
serverSideRender(req, res, null, 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.`); }
|
||||||
|
@@ -9,10 +9,6 @@ import {
|
|||||||
select,
|
select,
|
||||||
Store,
|
Store,
|
||||||
} from '@ngrx/store';
|
} from '@ngrx/store';
|
||||||
import {
|
|
||||||
REQUEST,
|
|
||||||
RESPONSE,
|
|
||||||
} from '../../../express.tokens';
|
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { CookieAttributes } from 'js-cookie';
|
import { CookieAttributes } from 'js-cookie';
|
||||||
import {
|
import {
|
||||||
@@ -28,6 +24,10 @@ import {
|
|||||||
} from 'rxjs/operators';
|
} from 'rxjs/operators';
|
||||||
|
|
||||||
import { environment } from '../../../environments/environment';
|
import { environment } from '../../../environments/environment';
|
||||||
|
import {
|
||||||
|
REQUEST,
|
||||||
|
RESPONSE,
|
||||||
|
} from '../../../express.tokens';
|
||||||
import { AppState } from '../../app.reducer';
|
import { AppState } from '../../app.reducer';
|
||||||
import {
|
import {
|
||||||
hasNoValue,
|
hasNoValue,
|
||||||
|
@@ -8,9 +8,10 @@ import {
|
|||||||
Inject,
|
Inject,
|
||||||
Injectable,
|
Injectable,
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { REQUEST } from '../../../express.tokens';
|
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
import { REQUEST } from '../../../express.tokens';
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
/**
|
/**
|
||||||
* Http Interceptor intercepting Http Requests, adding the client's IP to their X-Forwarded-For header
|
* Http Interceptor intercepting Http Requests, adding the client's IP to their X-Forwarded-For header
|
||||||
|
@@ -3,7 +3,6 @@ import {
|
|||||||
Inject,
|
Inject,
|
||||||
Injectable,
|
Injectable,
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { REQUEST } from '../../../express.tokens';
|
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import {
|
import {
|
||||||
combineLatest,
|
combineLatest,
|
||||||
@@ -16,6 +15,7 @@ import {
|
|||||||
take,
|
take,
|
||||||
} from 'rxjs/operators';
|
} from 'rxjs/operators';
|
||||||
|
|
||||||
|
import { REQUEST } from '../../../express.tokens';
|
||||||
import {
|
import {
|
||||||
hasValue,
|
hasValue,
|
||||||
isEmpty,
|
isEmpty,
|
||||||
|
@@ -2,13 +2,14 @@ import {
|
|||||||
Inject,
|
Inject,
|
||||||
Injectable,
|
Injectable,
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { REQUEST } from '../../../express.tokens';
|
|
||||||
import { CookieAttributes } from 'js-cookie';
|
import { CookieAttributes } from 'js-cookie';
|
||||||
import {
|
import {
|
||||||
Observable,
|
Observable,
|
||||||
Subject,
|
Subject,
|
||||||
} from 'rxjs';
|
} from 'rxjs';
|
||||||
|
|
||||||
|
import { REQUEST } from '../../../express.tokens';
|
||||||
|
|
||||||
export interface ICookieService {
|
export interface ICookieService {
|
||||||
readonly cookies$: Observable<{ readonly [key: string]: any }>;
|
readonly cookies$: Observable<{ readonly [key: string]: any }>;
|
||||||
|
|
||||||
|
@@ -2,15 +2,15 @@ import {
|
|||||||
Inject,
|
Inject,
|
||||||
Injectable,
|
Injectable,
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import {
|
|
||||||
REQUEST,
|
|
||||||
RESPONSE,
|
|
||||||
} from '../../../express.tokens';
|
|
||||||
import {
|
import {
|
||||||
Request,
|
Request,
|
||||||
Response,
|
Response,
|
||||||
} from 'express';
|
} from 'express';
|
||||||
|
|
||||||
|
import {
|
||||||
|
REQUEST,
|
||||||
|
RESPONSE,
|
||||||
|
} from '../../../express.tokens';
|
||||||
import { HardRedirectService } from './hard-redirect.service';
|
import { HardRedirectService } from './hard-redirect.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -2,12 +2,12 @@ import {
|
|||||||
Inject,
|
Inject,
|
||||||
Injectable,
|
Injectable,
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { REQUEST } from '../../../express.tokens';
|
|
||||||
import {
|
import {
|
||||||
Observable,
|
Observable,
|
||||||
of as observableOf,
|
of as observableOf,
|
||||||
} from 'rxjs';
|
} from 'rxjs';
|
||||||
|
|
||||||
|
import { REQUEST } from '../../../express.tokens';
|
||||||
import { ReferrerService } from './referrer.service';
|
import { ReferrerService } from './referrer.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
8
src/express.tokens.ts
Normal file
8
src/express.tokens.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { InjectionToken } from '@angular/core';
|
||||||
|
import {
|
||||||
|
Request,
|
||||||
|
Response,
|
||||||
|
} from 'express';
|
||||||
|
|
||||||
|
export const REQUEST: InjectionToken<Request> = new InjectionToken<Request>('REQUEST');
|
||||||
|
export const RESPONSE: InjectionToken<Response> = new InjectionToken<Response>('RESPONSE');
|
@@ -15,5 +15,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 { renderModule } from '@angular/platform-server';
|
||||||
export { ngExpressEngine } from '@angular/ssr';
|
|
||||||
export default bootstrap;
|
export default bootstrap;
|
||||||
|
@@ -19,7 +19,6 @@ import {
|
|||||||
StoreConfig,
|
StoreConfig,
|
||||||
StoreModule,
|
StoreModule,
|
||||||
} from '@ngrx/store';
|
} from '@ngrx/store';
|
||||||
import { REQUEST } from '../../express.tokens';
|
|
||||||
import {
|
import {
|
||||||
MissingTranslationHandler,
|
MissingTranslationHandler,
|
||||||
TranslateLoader,
|
TranslateLoader,
|
||||||
@@ -56,6 +55,7 @@ import { KlaroService } from '../../app/shared/cookies/klaro.service';
|
|||||||
import { MissingTranslationHelper } from '../../app/shared/translate/missing-translation.helper';
|
import { MissingTranslationHelper } from '../../app/shared/translate/missing-translation.helper';
|
||||||
import { GoogleAnalyticsService } from '../../app/statistics/google-analytics.service';
|
import { GoogleAnalyticsService } from '../../app/statistics/google-analytics.service';
|
||||||
import { SubmissionService } from '../../app/submission/submission.service';
|
import { SubmissionService } from '../../app/submission/submission.service';
|
||||||
|
import { REQUEST } from '../../express.tokens';
|
||||||
import { TranslateBrowserLoader } from '../../ngx-translate-loaders/translate-browser.loader';
|
import { TranslateBrowserLoader } from '../../ngx-translate-loaders/translate-browser.loader';
|
||||||
import { BrowserInitService } from './browser-init.service';
|
import { BrowserInitService } from './browser-init.service';
|
||||||
|
|
||||||
|
@@ -11484,10 +11484,10 @@ typescript@^2.5.0:
|
|||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.9.2.tgz#1cbf61d05d6b96269244eb6a3bce4bd914e0f00c"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.9.2.tgz#1cbf61d05d6b96269244eb6a3bce4bd914e0f00c"
|
||||||
integrity sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==
|
integrity sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==
|
||||||
|
|
||||||
typescript@~5.4.2:
|
typescript@~5.3.3:
|
||||||
version "5.4.2"
|
version "5.3.3"
|
||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.2.tgz#0ae9cebcfae970718474fe0da2c090cad6577372"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.3.3.tgz#b3ce6ba258e72e6305ba66f5c9b452aaee3ffe37"
|
||||||
integrity sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==
|
integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==
|
||||||
|
|
||||||
ua-parser-js@^0.7.30:
|
ua-parser-js@^0.7.30:
|
||||||
version "0.7.37"
|
version "0.7.37"
|
||||||
|
Reference in New Issue
Block a user