Skip to content

Commit a02d0bc

Browse files
authored
[ENG-10032] SSR: Main resources page (#852)
- Ticket: [ENG-10032] - Feature flag: n/a ## Summary of Changes 1. Added SSR setup. 2. Added new routes for SSR. 3. Fixed issues with SSR.
1 parent 28c37b3 commit a02d0bc

66 files changed

Lines changed: 1380 additions & 398 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

angular.json

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,39 @@
6363
"node_modules/ngx-markdown-editor/assets/highlight.js/highlight.min.js",
6464
"node_modules/ngx-markdown-editor/assets/marked.min.js",
6565
"src/assets/js/ace/snippetsMarkdown.js"
66-
]
66+
],
67+
"server": "src/main.server.ts",
68+
"outputMode": "server",
69+
"ssr": {
70+
"entry": "src/server.ts"
71+
}
6772
},
6873
"configurations": {
6974
"production": {
75+
"outputMode": "static",
76+
"server": false,
77+
"ssr": false,
78+
"budgets": [
79+
{
80+
"type": "initial",
81+
"maximumWarning": "9MB",
82+
"maximumError": "10MB"
83+
},
84+
{
85+
"type": "anyComponentStyle",
86+
"maximumWarning": "20KB",
87+
"maximumError": "25kB"
88+
}
89+
],
90+
"outputHashing": "all",
91+
"optimization": true
92+
},
93+
"ssr": {
94+
"outputMode": "server",
95+
"server": "src/main.server.ts",
96+
"ssr": {
97+
"entry": "src/server.ts"
98+
},
7099
"budgets": [
71100
{
72101
"type": "initial",
@@ -119,28 +148,6 @@
119148
"with": "src/environments/environment.staging.ts"
120149
}
121150
]
122-
},
123-
"test": {
124-
"optimization": true,
125-
"extractLicenses": false,
126-
"sourceMap": false,
127-
"fileReplacements": [
128-
{
129-
"replace": "src/environments/environment.ts",
130-
"with": "src/environments/environment.test.ts"
131-
}
132-
]
133-
},
134-
"test-osf": {
135-
"optimization": true,
136-
"extractLicenses": false,
137-
"sourceMap": false,
138-
"fileReplacements": [
139-
{
140-
"replace": "src/environments/environment.ts",
141-
"with": "src/environments/environment.test-osf.ts"
142-
}
143-
]
144151
}
145152
},
146153
"defaultConfiguration": "production"

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"ng": "ng",
66
"analyze-bundle": "ng build --configuration=analyze-bundle && source-map-explorer dist/**/*.js --no-border-checks",
77
"build": "ng build",
8+
"build:ssr": "ng build --configuration=ssr",
89
"check:config": "node ./docker/check-config.js",
910
"ci:test": "jest",
1011
"ci:test:coverage": "jest --coverage",
@@ -21,8 +22,6 @@
2122
"start": "ng serve",
2223
"start:docker": "npm run check:config && ng serve --host 0.0.0.0 --port 4200 --poll 2000 --configuration development",
2324
"start:docker:local": "npm run check:config && ng serve --host 0.0.0.0 --port 4200 --poll 2000 --configuration docker",
24-
"start:test": "ng serve --configuration test-osf",
25-
"start:test:future": "ng serve --configuration test",
2625
"test": "jest",
2726
"test:watch": "jest --watch",
2827
"test:coverage": "jest --coverage && npm run test:display",

src/app/app.config.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { ConfirmationService, MessageService } from 'primeng/api';
66
import { providePrimeNG } from 'primeng/config';
77
import { DialogService } from 'primeng/dynamicdialog';
88

9-
import { provideHttpClient, withInterceptors } from '@angular/common/http';
9+
import { provideHttpClient, withFetch, withInterceptors } from '@angular/common/http';
1010
import { ApplicationConfig, ErrorHandler, importProvidersFrom, provideZoneChangeDetection } from '@angular/core';
1111
import { provideClientHydration, withEventReplay } from '@angular/platform-browser';
1212
import { provideAnimations } from '@angular/platform-browser/animations';
@@ -49,7 +49,7 @@ export const appConfig: ApplicationConfig = {
4949
},
5050
},
5151
}),
52-
provideHttpClient(withInterceptors([authInterceptor, viewOnlyInterceptor, errorInterceptor])),
52+
provideHttpClient(withInterceptors([authInterceptor, viewOnlyInterceptor, errorInterceptor]), withFetch()),
5353
provideRouter(routes, withInMemoryScrolling({ scrollPositionRestoration: 'top', anchorScrolling: 'enabled' })),
5454
provideStore(STATES),
5555
provideZoneChangeDetection({ eventCoalescing: true }),

src/app/app.routes.server.ts

Lines changed: 121 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,27 @@ import { RenderMode, ServerRoute } from '@angular/ssr';
33
export const serverRoutes: ServerRoute[] = [
44
{
55
path: 'terms-of-use',
6-
renderMode: RenderMode.Server,
6+
renderMode: RenderMode.Prerender,
77
},
88
{
99
path: 'privacy-policy',
10-
renderMode: RenderMode.Server,
10+
renderMode: RenderMode.Prerender,
1111
},
1212
{
1313
path: 'forbidden',
14-
renderMode: RenderMode.Server,
14+
renderMode: RenderMode.Prerender,
1515
},
1616
{
17-
path: 'request-access/:id',
18-
renderMode: RenderMode.Server,
17+
path: 'not-found',
18+
renderMode: RenderMode.Prerender,
1919
},
2020
{
21-
path: 'not-found',
22-
renderMode: RenderMode.Server,
21+
path: 'forgotpassword',
22+
renderMode: RenderMode.Prerender,
2323
},
2424
{
25-
path: 'preprints/:providerId/:id',
26-
renderMode: RenderMode.Server,
25+
path: '',
26+
renderMode: RenderMode.Prerender,
2727
},
2828
{
2929
path: 'dashboard',
@@ -41,18 +41,130 @@ export const serverRoutes: ServerRoute[] = [
4141
path: 'my-preprints',
4242
renderMode: RenderMode.Client,
4343
},
44+
{
45+
path: 'register',
46+
renderMode: RenderMode.Client,
47+
},
4448
{
4549
path: 'profile',
4650
renderMode: RenderMode.Client,
4751
},
52+
{
53+
path: 'registries/drafts/**',
54+
renderMode: RenderMode.Client,
55+
},
56+
{
57+
path: 'registries/revisions/**',
58+
renderMode: RenderMode.Client,
59+
},
4860
{
4961
path: 'settings/**',
5062
renderMode: RenderMode.Client,
5163
},
64+
{
65+
path: 'request-access/:id',
66+
renderMode: RenderMode.Server,
67+
},
68+
{
69+
path: 'resetpassword/:userId/:token',
70+
renderMode: RenderMode.Server,
71+
},
72+
{
73+
path: 'search',
74+
renderMode: RenderMode.Server,
75+
},
76+
{
77+
path: 'preprints/discover',
78+
renderMode: RenderMode.Server,
79+
},
80+
{
81+
path: 'preprints/:providerId/:id/pending-moderation',
82+
renderMode: RenderMode.Server,
83+
},
84+
{
85+
path: 'preprints/:providerId/discover',
86+
renderMode: RenderMode.Server,
87+
},
88+
{
89+
path: 'preprints/:providerId/:id',
90+
renderMode: RenderMode.Server,
91+
},
92+
{
93+
path: 'preprints/:providerId',
94+
renderMode: RenderMode.Server,
95+
},
96+
{
97+
path: 'registries/discover',
98+
renderMode: RenderMode.Server,
99+
},
100+
{
101+
path: 'registries/:providerId',
102+
renderMode: RenderMode.Server,
103+
},
104+
{
105+
path: 'institutions',
106+
renderMode: RenderMode.Server,
107+
},
108+
{
109+
path: 'institutions/:institutionId',
110+
renderMode: RenderMode.Server,
111+
},
112+
{
113+
path: 'collections/:providerId/discover',
114+
renderMode: RenderMode.Server,
115+
},
116+
{
117+
path: 'meetings/**',
118+
renderMode: RenderMode.Server,
119+
},
120+
{
121+
path: 'user/:id',
122+
renderMode: RenderMode.Server,
123+
},
124+
{
125+
path: 'project/:id/node/:nodeId/files/:provider/:fileId',
126+
renderMode: RenderMode.Server,
127+
},
128+
{
129+
path: 'project/:id/files/:provider/:fileId',
130+
renderMode: RenderMode.Server,
131+
},
132+
{
133+
path: ':id/files/:provider/:fileId',
134+
renderMode: RenderMode.Server,
135+
},
52136
{
53137
path: ':id/overview',
54138
renderMode: RenderMode.Server,
55139
},
140+
{
141+
path: ':id/files/**',
142+
renderMode: RenderMode.Server,
143+
},
144+
{
145+
path: ':id/registrations',
146+
renderMode: RenderMode.Server,
147+
},
148+
{
149+
path: ':id/analytics',
150+
renderMode: RenderMode.Server,
151+
},
152+
{
153+
path: ':id/links',
154+
renderMode: RenderMode.Server,
155+
},
156+
{
157+
path: ':id/resources',
158+
renderMode: RenderMode.Server,
159+
},
160+
{
161+
path: ':id/components',
162+
renderMode: RenderMode.Server,
163+
},
164+
{
165+
path: ':id/recent-activity',
166+
renderMode: RenderMode.Server,
167+
},
56168
{
57169
path: ':id',
58170
renderMode: RenderMode.Server,

src/app/app.routes.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,13 @@ export const routes: Routes = [
100100
path: 'preprints',
101101
loadChildren: () => import('./features/preprints/preprints.routes').then((mod) => mod.preprintsRoutes),
102102
},
103+
{
104+
path: 'preprints/:providerId/:id/pending-moderation',
105+
loadComponent: () =>
106+
import(
107+
'@osf/features/preprints/pages/preprint-pending-moderation/preprint-pending-moderation.component'
108+
).then((mod) => mod.PreprintPendingModerationComponent),
109+
},
103110
{
104111
path: 'preprints/:providerId/:id',
105112
loadComponent: () =>
@@ -156,13 +163,6 @@ export const routes: Routes = [
156163
import('./core/components/forbidden-page/forbidden-page.component').then((mod) => mod.ForbiddenPageComponent),
157164
data: { skipBreadcrumbs: true },
158165
},
159-
{
160-
path: 'preprints/:providerId/:id/pending-moderation',
161-
loadComponent: () =>
162-
import(
163-
'@osf/features/preprints/pages/preprint-pending-moderation/preprint-pending-moderation.component'
164-
).then((mod) => mod.PreprintPendingModerationComponent),
165-
},
166166
{
167167
path: 'request-access/:id',
168168
loadComponent: () =>
@@ -176,7 +176,7 @@ export const routes: Routes = [
176176
data: { skipBreadcrumbs: true },
177177
},
178178
{
179-
path: ':id/files/:provider/:fileId',
179+
path: 'project/:id/node/:nodeId/files/:provider/:fileId',
180180
loadComponent: () =>
181181
import('./features/files/pages/file-redirect/file-redirect.component').then((m) => m.FileRedirectComponent),
182182
},
@@ -186,7 +186,7 @@ export const routes: Routes = [
186186
import('./features/files/pages/file-redirect/file-redirect.component').then((m) => m.FileRedirectComponent),
187187
},
188188
{
189-
path: 'project/:id/node/:nodeId/files/:provider/:fileId',
189+
path: ':id/files/:provider/:fileId',
190190
loadComponent: () =>
191191
import('./features/files/pages/file-redirect/file-redirect.component').then((m) => m.FileRedirectComponent),
192192
},
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { ParamMap, UrlSegment } from '@angular/router';
2+
3+
import { FileProvider } from '@osf/features/files/constants';
4+
5+
import { isFileProvider } from './is-file-provider.guard';
6+
7+
describe('isFileProvider', () => {
8+
const createMockParamMap = (): ParamMap => ({
9+
get: () => null,
10+
getAll: () => [],
11+
has: () => false,
12+
keys: [],
13+
});
14+
15+
const createMockSegment = (path: string): UrlSegment => ({
16+
path,
17+
parameters: {},
18+
parameterMap: createMockParamMap(),
19+
});
20+
21+
const createMockSegments = (path: string) => [createMockSegment(path)];
22+
23+
it('should return true when id matches a FileProvider value', () => {
24+
Object.values(FileProvider).forEach((provider) => {
25+
const result = isFileProvider({} as any, createMockSegments(provider));
26+
expect(result).toBe(true);
27+
});
28+
});
29+
30+
it('should return false when id does not match any FileProvider value', () => {
31+
const result = isFileProvider({} as any, createMockSegments('invalid-provider'));
32+
expect(result).toBe(false);
33+
});
34+
35+
it('should return false when segments array is empty', () => {
36+
const result = isFileProvider({} as any, []);
37+
expect(result).toBe(false);
38+
});
39+
40+
it('should return false when first segment has no path', () => {
41+
const result = isFileProvider({} as any, [createMockSegment('')]);
42+
expect(result).toBe(false);
43+
});
44+
45+
it('should return false when first segment is undefined', () => {
46+
const result = isFileProvider({} as any, [undefined as any]);
47+
expect(result).toBe(false);
48+
});
49+
});

0 commit comments

Comments
 (0)