mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
[DURACOM-234] WIP fix SSR
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
/.angular/cache
|
||||
/.nx
|
||||
/__build__
|
||||
/__server_build__
|
||||
/node_modules
|
||||
|
12
angular.json
12
angular.json
@@ -109,15 +109,15 @@
|
||||
"serve": {
|
||||
"builder": "@angular-builders/custom-webpack:dev-server",
|
||||
"options": {
|
||||
"browserTarget": "dspace-angular:build",
|
||||
"buildTarget": "dspace-angular:build",
|
||||
"port": 4000
|
||||
},
|
||||
"configurations": {
|
||||
"development": {
|
||||
"browserTarget": "dspace-angular:build:development"
|
||||
"buildTarget": "dspace-angular:build:development"
|
||||
},
|
||||
"production": {
|
||||
"browserTarget": "dspace-angular:build:production"
|
||||
"buildTarget": "dspace-angular:build:production"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -219,13 +219,13 @@
|
||||
"serve-ssr": {
|
||||
"builder": "@angular-devkit/build-angular:ssr-dev-server",
|
||||
"options": {
|
||||
"browserTarget": "dspace-angular:build",
|
||||
"buildTarget": "dspace-angular:build",
|
||||
"serverTarget": "dspace-angular:server",
|
||||
"port": 4000
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "dspace-angular:build:production",
|
||||
"buildTarget": "dspace-angular:build:production",
|
||||
"serverTarget": "dspace-angular:server:production"
|
||||
}
|
||||
}
|
||||
@@ -233,7 +233,7 @@
|
||||
"prerender": {
|
||||
"builder": "@angular-devkit/build-angular:prerender",
|
||||
"options": {
|
||||
"browserTarget": "dspace-angular:build:production",
|
||||
"buildTarget": "dspace-angular:build:production",
|
||||
"serverTarget": "dspace-angular:server:production",
|
||||
"routes": [
|
||||
"/"
|
||||
|
@@ -200,10 +200,10 @@
|
||||
"sass-loader": "^12.6.0",
|
||||
"sass-resources-loader": "^2.2.5",
|
||||
"ts-node": "^8.10.2",
|
||||
"typescript": "~5.4.2",
|
||||
"typescript": "~5.3.3",
|
||||
"webpack": "5.76.1",
|
||||
"webpack-bundle-analyzer": "^4.8.0",
|
||||
"webpack-cli": "^4.2.0",
|
||||
"webpack-dev-server": "^4.13.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
62
server.ts
62
server.ts
@@ -39,8 +39,7 @@ import { join } from 'path';
|
||||
|
||||
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 { 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 { logStartupMessage } from './startup-message';
|
||||
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
|
||||
*/
|
||||
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
|
||||
// See https://expressjs.com/en/guide/behind-proxies.html
|
||||
@@ -128,7 +135,7 @@ export function app() {
|
||||
server.use(json());
|
||||
|
||||
// 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({
|
||||
bootstrap,
|
||||
providers: [
|
||||
@@ -146,7 +153,7 @@ export function app() {
|
||||
},
|
||||
],
|
||||
})(_, (options as any), callback),
|
||||
);
|
||||
);*/
|
||||
|
||||
server.engine('ejs', ejs.renderFile);
|
||||
|
||||
@@ -227,7 +234,12 @@ export function app() {
|
||||
* copy of the page (see cacheCheck())
|
||||
*/
|
||||
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);
|
||||
|
||||
return server;
|
||||
@@ -236,10 +248,10 @@ export function app() {
|
||||
/*
|
||||
* The callback function to serve server side angular
|
||||
*/
|
||||
function ngApp(req, res) {
|
||||
function ngApp(req, res, next) {
|
||||
if (environment.universal.preboot) {
|
||||
// Render the page to user via SSR (server side rendering)
|
||||
serverSideRender(req, res);
|
||||
serverSideRender(req, res, next);
|
||||
} else {
|
||||
// If preboot is disabled, just serve the client
|
||||
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.
|
||||
* 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)
|
||||
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,
|
||||
res,
|
||||
preboot: environment.universal.preboot,
|
||||
@@ -290,7 +330,7 @@ function serverSideRender(req, res, sendToUser: boolean = true) {
|
||||
clientSideRender(req, res);
|
||||
}
|
||||
}
|
||||
});
|
||||
});*/
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -426,7 +466,7 @@ function checkCacheForRequest(cacheName: string, cache: LRU<string, any>, req, r
|
||||
// Update cached copy by rerendering server-side
|
||||
// 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.
|
||||
serverSideRender(req, res, false);
|
||||
serverSideRender(req, res, null, false);
|
||||
}
|
||||
} else {
|
||||
if (environment.cache.serverSide.debug) { console.log(`CACHE MISS FOR ${key} in ${cacheName} cache.`); }
|
||||
|
@@ -9,10 +9,6 @@ import {
|
||||
select,
|
||||
Store,
|
||||
} from '@ngrx/store';
|
||||
import {
|
||||
REQUEST,
|
||||
RESPONSE,
|
||||
} from '../../../express.tokens';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { CookieAttributes } from 'js-cookie';
|
||||
import {
|
||||
@@ -28,6 +24,10 @@ import {
|
||||
} from 'rxjs/operators';
|
||||
|
||||
import { environment } from '../../../environments/environment';
|
||||
import {
|
||||
REQUEST,
|
||||
RESPONSE,
|
||||
} from '../../../express.tokens';
|
||||
import { AppState } from '../../app.reducer';
|
||||
import {
|
||||
hasNoValue,
|
||||
|
@@ -8,9 +8,10 @@ import {
|
||||
Inject,
|
||||
Injectable,
|
||||
} from '@angular/core';
|
||||
import { REQUEST } from '../../../express.tokens';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { REQUEST } from '../../../express.tokens';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
/**
|
||||
* Http Interceptor intercepting Http Requests, adding the client's IP to their X-Forwarded-For header
|
||||
|
@@ -3,7 +3,6 @@ import {
|
||||
Inject,
|
||||
Injectable,
|
||||
} from '@angular/core';
|
||||
import { REQUEST } from '../../../express.tokens';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import {
|
||||
combineLatest,
|
||||
@@ -16,6 +15,7 @@ import {
|
||||
take,
|
||||
} from 'rxjs/operators';
|
||||
|
||||
import { REQUEST } from '../../../express.tokens';
|
||||
import {
|
||||
hasValue,
|
||||
isEmpty,
|
||||
|
@@ -2,13 +2,14 @@ import {
|
||||
Inject,
|
||||
Injectable,
|
||||
} from '@angular/core';
|
||||
import { REQUEST } from '../../../express.tokens';
|
||||
import { CookieAttributes } from 'js-cookie';
|
||||
import {
|
||||
Observable,
|
||||
Subject,
|
||||
} from 'rxjs';
|
||||
|
||||
import { REQUEST } from '../../../express.tokens';
|
||||
|
||||
export interface ICookieService {
|
||||
readonly cookies$: Observable<{ readonly [key: string]: any }>;
|
||||
|
||||
|
@@ -2,15 +2,15 @@ import {
|
||||
Inject,
|
||||
Injectable,
|
||||
} from '@angular/core';
|
||||
import {
|
||||
REQUEST,
|
||||
RESPONSE,
|
||||
} from '../../../express.tokens';
|
||||
import {
|
||||
Request,
|
||||
Response,
|
||||
} from 'express';
|
||||
|
||||
import {
|
||||
REQUEST,
|
||||
RESPONSE,
|
||||
} from '../../../express.tokens';
|
||||
import { HardRedirectService } from './hard-redirect.service';
|
||||
|
||||
/**
|
||||
|
@@ -2,12 +2,12 @@ import {
|
||||
Inject,
|
||||
Injectable,
|
||||
} from '@angular/core';
|
||||
import { REQUEST } from '../../../express.tokens';
|
||||
import {
|
||||
Observable,
|
||||
of as observableOf,
|
||||
} from 'rxjs';
|
||||
|
||||
import { REQUEST } from '../../../express.tokens';
|
||||
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);
|
||||
|
||||
export { renderModule } from '@angular/platform-server';
|
||||
export { ngExpressEngine } from '@angular/ssr';
|
||||
export default bootstrap;
|
||||
|
@@ -19,7 +19,6 @@ import {
|
||||
StoreConfig,
|
||||
StoreModule,
|
||||
} from '@ngrx/store';
|
||||
import { REQUEST } from '../../express.tokens';
|
||||
import {
|
||||
MissingTranslationHandler,
|
||||
TranslateLoader,
|
||||
@@ -56,6 +55,7 @@ import { KlaroService } from '../../app/shared/cookies/klaro.service';
|
||||
import { MissingTranslationHelper } from '../../app/shared/translate/missing-translation.helper';
|
||||
import { GoogleAnalyticsService } from '../../app/statistics/google-analytics.service';
|
||||
import { SubmissionService } from '../../app/submission/submission.service';
|
||||
import { REQUEST } from '../../express.tokens';
|
||||
import { TranslateBrowserLoader } from '../../ngx-translate-loaders/translate-browser.loader';
|
||||
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"
|
||||
integrity sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==
|
||||
|
||||
typescript@~5.4.2:
|
||||
version "5.4.2"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.2.tgz#0ae9cebcfae970718474fe0da2c090cad6577372"
|
||||
integrity sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==
|
||||
typescript@~5.3.3:
|
||||
version "5.3.3"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.3.3.tgz#b3ce6ba258e72e6305ba66f5c9b452aaee3ffe37"
|
||||
integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==
|
||||
|
||||
ua-parser-js@^0.7.30:
|
||||
version "0.7.37"
|
||||
|
Reference in New Issue
Block a user