diff --git a/.gitignore b/.gitignore index 7d065aca061..ce44f6b3fbe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /.angular/cache +/.nx /__build__ /__server_build__ /node_modules diff --git a/angular.json b/angular.json index df004364b1a..98463fa732e 100644 --- a/angular.json +++ b/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": [ "/" diff --git a/package.json b/package.json index 740645bc3b5..5152458ae0c 100644 --- a/package.json +++ b/package.json @@ -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" } -} \ No newline at end of file +} diff --git a/server.ts b/server.ts index 1731f9d10ec..34be71837ff 100644 --- a/server.ts +++ b/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, 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.`); } diff --git a/src/app/core/auth/auth.service.ts b/src/app/core/auth/auth.service.ts index 4266e78fb6a..cd773b68cfa 100644 --- a/src/app/core/auth/auth.service.ts +++ b/src/app/core/auth/auth.service.ts @@ -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, diff --git a/src/app/core/forward-client-ip/forward-client-ip.interceptor.ts b/src/app/core/forward-client-ip/forward-client-ip.interceptor.ts index f2897786501..037f690057f 100644 --- a/src/app/core/forward-client-ip/forward-client-ip.interceptor.ts +++ b/src/app/core/forward-client-ip/forward-client-ip.interceptor.ts @@ -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 diff --git a/src/app/core/locale/server-locale.service.ts b/src/app/core/locale/server-locale.service.ts index bc714126968..12358595d1a 100644 --- a/src/app/core/locale/server-locale.service.ts +++ b/src/app/core/locale/server-locale.service.ts @@ -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, diff --git a/src/app/core/services/cookie.service.ts b/src/app/core/services/cookie.service.ts index d3630484bd9..074cfbf02b3 100644 --- a/src/app/core/services/cookie.service.ts +++ b/src/app/core/services/cookie.service.ts @@ -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 }>; diff --git a/src/app/core/services/server-hard-redirect.service.ts b/src/app/core/services/server-hard-redirect.service.ts index de0eef81225..e1ded1568cc 100644 --- a/src/app/core/services/server-hard-redirect.service.ts +++ b/src/app/core/services/server-hard-redirect.service.ts @@ -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'; /** diff --git a/src/app/core/services/server.referrer.service.ts b/src/app/core/services/server.referrer.service.ts index 4a9fc1dcab1..70b0e806c8e 100644 --- a/src/app/core/services/server.referrer.service.ts +++ b/src/app/core/services/server.referrer.service.ts @@ -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'; /** diff --git a/src/express.tokens.ts b/src/express.tokens.ts new file mode 100644 index 00000000000..07e205e73bb --- /dev/null +++ b/src/express.tokens.ts @@ -0,0 +1,8 @@ +import { InjectionToken } from '@angular/core'; +import { + Request, + Response, +} from 'express'; + +export const REQUEST: InjectionToken = new InjectionToken('REQUEST'); +export const RESPONSE: InjectionToken = new InjectionToken('RESPONSE'); diff --git a/src/main.server.ts b/src/main.server.ts index 7d12edb9806..d699d1e4843 100644 --- a/src/main.server.ts +++ b/src/main.server.ts @@ -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; diff --git a/src/modules/app/browser-app.config.ts b/src/modules/app/browser-app.config.ts index 3892ba903c7..aa37804cb1a 100644 --- a/src/modules/app/browser-app.config.ts +++ b/src/modules/app/browser-app.config.ts @@ -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'; diff --git a/yarn.lock b/yarn.lock index 69a5bb47d64..8b75429cb8d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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"