Skip to content

Commit dd3934b

Browse files
committed
Merge branch 'develop' into feature/orcid-integration
2 parents 3e0b111 + 3666b51 commit dd3934b

22 files changed

Lines changed: 290 additions & 166 deletions

CHANGELOG

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,16 @@
22

33
We follow the CalVer (https://calver.org/) versioning scheme: YY.MINOR.MICRO.
44

5+
26.5.1 (2026-03-18)
6+
===================
7+
8+
* Hotfix for Angular SSR
9+
10+
26.5.0 (2026-02-26)
11+
===================
12+
13+
* Config updates to enable Angular SSR
14+
515
26.4.0 (2026-02-26)
616
===================
717

Dockerfile

Lines changed: 19 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,37 @@
1-
# Build
2-
FROM node:22-alpine AS build
3-
1+
# Dependencies stage
2+
FROM node:22-alpine AS deps
43
WORKDIR /app
5-
64
COPY package*.json ./
7-
RUN npm install
5+
RUN npm ci --no-audit --no-fund
86

7+
# Build stage (SSR build output)
8+
FROM deps AS build
99
COPY . .
10+
RUN NG_BUILD_OPTIMIZE_CHUNKS=1 npx ng build --configuration=ssr --verbose
1011

11-
RUN npm link @angular/cli
12-
RUN NG_BUILD_OPTIMIZE_CHUNKS=1 ng build --verbose
12+
# SSR runtime stage
13+
FROM build AS ssr
14+
WORKDIR /app
15+
RUN npm prune --omit=dev --no-audit --no-fund
16+
EXPOSE 4000
17+
ENV PORT=4000
18+
CMD ["node", "--enable-source-maps", "dist/osf/server/server.mjs"]
1319

14-
# Dist
20+
# Static dist artifact stage
1521
FROM node:22-alpine AS dist
16-
1722
WORKDIR /code
18-
1923
COPY --from=build /app/dist /code/dist
2024

21-
# SSR
22-
FROM node:22-alpine AS ssr
23-
24-
WORKDIR /app
25-
26-
COPY package*.json ./
27-
RUN npm install
28-
25+
# Dev server stage
26+
FROM deps AS dev
2927
COPY . .
30-
31-
RUN npm link @angular/cli
32-
RUN NG_BUILD_OPTIMIZE_CHUNKS=1 ng build --configuration=ssr --verbose
33-
34-
RUN npm ci --omit=dev --ignore-scripts --no-audit --no-fund
35-
36-
EXPOSE 4000
37-
38-
ENV PORT=4000
39-
40-
CMD ["node", "dist/osf/server/server.mjs"]
41-
42-
# Dev - run only
43-
FROM build AS dev
44-
4528
EXPOSE 4200
29+
CMD ["npx", "ng", "serve", "--host", "0.0.0.0"]
4630

47-
CMD ["ng", "serve"]
48-
49-
# Local Development - coding
31+
# Local development stage
5032
FROM node:22-alpine AS local-dev
5133
WORKDIR /app
52-
53-
# Install deps in the image (kept in container)
5434
COPY package*.json ./
55-
# COPY package-lock.docker.json ./package-lock.json
5635
RUN npm ci --no-audit --no-fund
57-
58-
# Expose Angular dev server
5936
EXPOSE 4200
37+
CMD ["npx", "ng", "serve", "--host", "0.0.0.0"]

angular.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@
9696
"ssr": {
9797
"entry": "src/server.ts"
9898
},
99+
"sourceMap": true,
99100
"budgets": [
100101
{
101102
"type": "initial",
@@ -117,6 +118,20 @@
117118
"namedChunks": true
118119
},
119120
"development": {
121+
"outputMode": "static",
122+
"server": false,
123+
"ssr": false,
124+
"optimization": false,
125+
"extractLicenses": false,
126+
"sourceMap": true,
127+
"fileReplacements": [
128+
{
129+
"replace": "src/environments/environment.ts",
130+
"with": "src/environments/environment.development.ts"
131+
}
132+
]
133+
},
134+
"dev-ssr": {
120135
"optimization": false,
121136
"extractLicenses": false,
122137
"sourceMap": true,
@@ -164,6 +179,9 @@
164179
"development": {
165180
"buildTarget": "osf:build:development"
166181
},
182+
"dev-ssr": {
183+
"buildTarget": "osf:build:dev-ssr"
184+
},
167185
"docker": {
168186
"buildTarget": "osf:build:docker"
169187
},

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "osf",
3-
"version": "26.4.0",
3+
"version": "26.5.1",
44
"scripts": {
55
"ng": "ng",
66
"analyze-bundle": "ng build --configuration=analyze-bundle && source-map-explorer dist/**/*.js --no-border-checks",
@@ -20,6 +20,7 @@
2020
"ngxs:store": "ng generate @ngxs/store:store --name --path",
2121
"prepare": "husky",
2222
"start": "ng serve",
23+
"start:ssr": "ng serve --configuration dev-ssr",
2324
"start:docker": "npm run check:config && ng serve --host 0.0.0.0 --port 4200 --poll 2000 --configuration development",
2425
"start:docker:local": "npm run check:config && ng serve --host 0.0.0.0 --port 4200 --poll 2000 --configuration docker",
2526
"test": "jest",
@@ -28,7 +29,7 @@
2829
"test:check-coverage-thresholds": "node .github/scripts/check-coverage-thresholds.js",
2930
"test:display": "node .github/counter/counter.test.display.js",
3031
"watch": "ng build --watch --configuration development",
31-
"serve:ssr:osf": "node dist/osf/server/server.mjs"
32+
"serve:ssr:osf": "node --enable-source-maps dist/osf/server/server.mjs"
3233
},
3334
"private": true,
3435
"dependencies": {

src/@types/ace-builds.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
declare module 'ace-builds/src-noconflict/ext-language_tools';

src/app/app.config.server.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,42 @@ import { ApplicationConfig, mergeApplicationConfig } from '@angular/core';
22
import { provideServerRendering } from '@angular/platform-server';
33
import { provideServerRouting } from '@angular/ssr';
44

5+
import { SSR_CONFIG } from '@core/constants/ssr-config.token';
6+
import { ConfigModel } from '@core/models/config.model';
7+
58
import { appConfig } from './app.config';
69
import { serverRoutes } from './app.routes.server';
710

11+
import { existsSync, readFileSync } from 'node:fs';
12+
import { dirname, resolve } from 'node:path';
13+
import { fileURLToPath } from 'node:url';
14+
15+
function loadSsrConfig(): ConfigModel {
16+
const serverDistFolder = dirname(fileURLToPath(import.meta.url));
17+
const configPath = resolve(serverDistFolder, '../browser/assets/config/config.json');
18+
19+
let config = {} as ConfigModel;
20+
21+
if (existsSync(configPath)) {
22+
try {
23+
config = JSON.parse(readFileSync(configPath, 'utf-8'));
24+
} catch {
25+
config = {} as ConfigModel;
26+
}
27+
}
28+
29+
return {
30+
...config,
31+
throttleToken: process.env['THROTTLE_TOKEN'] || '',
32+
} as ConfigModel;
33+
}
34+
835
const serverConfig: ApplicationConfig = {
9-
providers: [provideServerRendering(), provideServerRouting(serverRoutes)],
36+
providers: [
37+
provideServerRendering(),
38+
provideServerRouting(serverRoutes),
39+
{ provide: SSR_CONFIG, useFactory: loadSsrConfig },
40+
],
1041
};
1142

1243
export const config = mergeApplicationConfig(appConfig, serverConfig);

src/app/app.routes.server.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,10 @@ export const serverRoutes: ServerRoute[] = [
141141
path: ':id/metadata/:recordId',
142142
renderMode: RenderMode.Server,
143143
},
144+
{
145+
path: ':id/wiki',
146+
renderMode: RenderMode.Server,
147+
},
144148
{
145149
path: ':id/files/**',
146150
renderMode: RenderMode.Server,
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { InjectionToken } from '@angular/core';
2+
3+
import { ConfigModel } from '@core/models/config.model';
4+
5+
export const SSR_CONFIG = new InjectionToken<ConfigModel>('SSR_CONFIG');

src/app/core/helpers/i18n.helper.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
11
import { TranslateLoader, TranslateModuleConfig } from '@ngx-translate/core';
22
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
33

4+
import { isPlatformServer } from '@angular/common';
45
import { HttpClient } from '@angular/common/http';
6+
import { inject, PLATFORM_ID } from '@angular/core';
7+
8+
import { ENVIRONMENT } from '@core/provider/environment.provider';
59

610
function httpLoaderFactory(http: HttpClient): TranslateHttpLoader {
7-
return new TranslateHttpLoader(http, './assets/i18n/', '.json');
11+
const platformId = inject(PLATFORM_ID);
12+
const environment = inject(ENVIRONMENT);
13+
const basePrefix = '/assets/i18n/';
14+
const webUrl = environment.webUrl?.replace(/\/+$/, '') ?? '';
15+
const prefix = isPlatformServer(platformId) && webUrl ? `${webUrl}${basePrefix}` : basePrefix;
16+
17+
return new TranslateHttpLoader(http, prefix, '.json');
818
}
919

1020
export const provideTranslation = (): TranslateModuleConfig => ({

0 commit comments

Comments
 (0)