@@ -11,8 +11,11 @@ import {
11
11
InjectionToken ,
12
12
Provider ,
13
13
Type ,
14
+ inject ,
14
15
makeEnvironmentProviders ,
16
+ provideEnvironmentInitializer ,
15
17
} from '@angular/core' ;
18
+ import { provideServerRendering as provideServerRenderingPlatformServer } from '@angular/platform-server' ;
16
19
import { type DefaultExport , ROUTES , type Route } from '@angular/router' ;
17
20
18
21
/**
@@ -22,25 +25,26 @@ import { type DefaultExport, ROUTES, type Route } from '@angular/router';
22
25
const APP_SHELL_ROUTE = 'ng-app-shell' ;
23
26
24
27
/**
25
- * Identifies a particular kind of `ServerRoutesFeatureKind `.
26
- * @see {@link ServerRoutesFeature }
28
+ * Identifies a particular kind of `ServerRenderingFeatureKind `.
29
+ * @see {@link ServerRenderingFeature }
27
30
*/
28
- enum ServerRoutesFeatureKind {
31
+ enum ServerRenderingFeatureKind {
29
32
AppShell ,
33
+ ServerRoutes ,
30
34
}
31
35
32
36
/**
33
37
* Helper type to represent a server routes feature.
34
- * @see {@link ServerRoutesFeatureKind }
38
+ * @see {@link ServerRenderingFeatureKind }
35
39
*/
36
- interface ServerRoutesFeature < FeatureKind extends ServerRoutesFeatureKind > {
40
+ interface ServerRenderingFeature < FeatureKind extends ServerRenderingFeatureKind > {
37
41
ɵkind : FeatureKind ;
38
- ɵproviders : Provider [ ] ;
42
+ ɵproviders : ( Provider | EnvironmentProviders ) [ ] ;
39
43
}
40
44
41
45
/**
42
46
* Different rendering modes for server routes.
43
- * @see {@link provideServerRouting }
47
+ * @see {@link withRoutes }
44
48
* @see {@link ServerRoute }
45
49
*/
46
50
export enum RenderMode {
@@ -171,7 +175,7 @@ export interface ServerRouteServer extends ServerRouteCommon {
171
175
172
176
/**
173
177
* Server route configuration.
174
- * @see {@link provideServerRouting }
178
+ * @see {@link withRoutes }
175
179
*/
176
180
export type ServerRoute =
177
181
| ServerRouteClient
@@ -200,62 +204,103 @@ export interface ServerRoutesConfig {
200
204
export const SERVER_ROUTES_CONFIG = new InjectionToken < ServerRoutesConfig > ( 'SERVER_ROUTES_CONFIG' ) ;
201
205
202
206
/**
203
- * Sets up the necessary providers for configuring server routes.
204
- * This function accepts an array of server routes and optional configuration
205
- * options, returning an `EnvironmentProviders` object that encapsulates
206
- * the server routes and configuration settings.
207
+ * Configures server-side routing for the application.
207
208
*
208
- * @param routes - An array of server routes to be provided.
209
- * @param features - (Optional) server routes features.
210
- * @returns An `EnvironmentProviders` instance with the server routes configuration .
209
+ * This function registers an array of `ServerRoute` definitions, enabling server-side rendering
210
+ * for specific URL paths. These routes are used to pre-render content on the server, improving
211
+ * initial load performance and SEO .
211
212
*
213
+ * @param routes - An array of `ServerRoute` objects, each defining a server-rendered route.
214
+ * @returns A `ServerRenderingFeature` object configuring server-side routes.
215
+ *
216
+ * @example
217
+ * ```ts
218
+ * import { provideServerRendering, withRoutes, ServerRoute, RenderMode } from '@angular/ssr';
219
+ *
220
+ * const serverRoutes: ServerRoute[] = [
221
+ * {
222
+ * route: '', // This renders the "/" route on the client (CSR)
223
+ * renderMode: RenderMode.Client,
224
+ * },
225
+ * {
226
+ * route: 'about', // This page is static, so we prerender it (SSG)
227
+ * renderMode: RenderMode.Prerender,
228
+ * },
229
+ * {
230
+ * route: 'profile', // This page requires user-specific data, so we use SSR
231
+ * renderMode: RenderMode.Server,
232
+ * },
233
+ * {
234
+ * route: '**', // All other routes will be rendered on the server (SSR)
235
+ * renderMode: RenderMode.Server,
236
+ * },
237
+ * ];
238
+ *
239
+ * provideServerRendering(withRoutes(serverRoutes));
240
+ * ```
241
+ *
242
+ * @see {@link provideServerRendering }
212
243
* @see {@link ServerRoute }
213
- * @see {@link withAppShell }
214
244
*/
215
- export function provideServerRouting (
245
+ export function withRoutes (
216
246
routes : ServerRoute [ ] ,
217
- ...features : ServerRoutesFeature < ServerRoutesFeatureKind > [ ]
218
- ) : EnvironmentProviders {
247
+ ) : ServerRenderingFeature < ServerRenderingFeatureKind . ServerRoutes > {
219
248
const config : ServerRoutesConfig = { routes } ;
220
- const hasAppShell = features . some ( ( f ) => f . ɵkind === ServerRoutesFeatureKind . AppShell ) ;
221
- if ( hasAppShell ) {
222
- config . appShellRoute = APP_SHELL_ROUTE ;
223
- }
224
-
225
- const providers : Provider [ ] = [
226
- {
227
- provide : SERVER_ROUTES_CONFIG ,
228
- useValue : config ,
229
- } ,
230
- ] ;
231
-
232
- for ( const feature of features ) {
233
- providers . push ( ...feature . ɵproviders ) ;
234
- }
235
249
236
- return makeEnvironmentProviders ( providers ) ;
250
+ return {
251
+ ɵkind : ServerRenderingFeatureKind . ServerRoutes ,
252
+ ɵproviders : [
253
+ {
254
+ provide : SERVER_ROUTES_CONFIG ,
255
+ useValue : config ,
256
+ } ,
257
+ ] ,
258
+ } ;
237
259
}
238
260
239
261
/**
240
- * Configures the app shell route with the provided component.
262
+ * Configures the shell of the application.
263
+ *
264
+ * The app shell is a minimal, static HTML page that is served immediately, while the
265
+ * full Angular application loads in the background. This improves perceived performance
266
+ * by providing instant feedback to the user.
267
+ *
268
+ * This function configures the app shell route, which serves the provided component for
269
+ * requests that do not match any defined server routes.
241
270
*
242
- * The app shell serves as the main entry point for the application and is commonly used
243
- * to enable server-side rendering (SSR) of the application shell. It handles requests
244
- * that do not match any specific server route, providing a fallback mechanism and improving
245
- * perceived performance during navigation.
271
+ * @param component - The Angular component to render for the app shell. Can be a direct
272
+ * component type or a dynamic import function.
273
+ * @returns A `ServerRenderingFeature` object configuring the app shell.
246
274
*
247
- * This configuration is particularly useful in applications leveraging Progressive Web App (PWA)
248
- * patterns, such as service workers, to deliver a seamless user experience.
275
+ * @example
276
+ * ```ts
277
+ * import { provideServerRendering, withAppShell, withRoutes } from '@angular/ssr';
278
+ * import { AppShellComponent } from './app-shell.component';
249
279
*
250
- * @param component The Angular component to render for the app shell route.
251
- * @returns A server routes feature configuration for the app shell.
280
+ * provideServerRendering(
281
+ * withRoutes(serverRoutes),
282
+ * withAppShell(AppShellComponent)
283
+ * );
284
+ * ```
252
285
*
253
- * @see {@link provideServerRouting }
286
+ * @example
287
+ * ```ts
288
+ * import { provideServerRendering, withAppShell, withRoutes } from '@angular/ssr';
289
+ *
290
+ * provideServerRendering(
291
+ * withRoutes(serverRoutes),
292
+ * withAppShell(() =>
293
+ * import('./app-shell.component').then((m) => m.AppShellComponent)
294
+ * )
295
+ * );
296
+ * ```
297
+ *
298
+ * @see {@link provideServerRendering }
254
299
* @see {@link https://angular.dev/ecosystem/service-workers/app-shell | App shell pattern on Angular.dev }
255
300
*/
256
301
export function withAppShell (
257
302
component : Type < unknown > | ( ( ) => Promise < Type < unknown > | DefaultExport < Type < unknown > > > ) ,
258
- ) : ServerRoutesFeature < ServerRoutesFeatureKind . AppShell > {
303
+ ) : ServerRenderingFeature < ServerRenderingFeatureKind . AppShell > {
259
304
const routeConfig : Route = {
260
305
path : APP_SHELL_ROUTE ,
261
306
} ;
@@ -267,13 +312,73 @@ export function withAppShell(
267
312
}
268
313
269
314
return {
270
- ɵkind : ServerRoutesFeatureKind . AppShell ,
315
+ ɵkind : ServerRenderingFeatureKind . AppShell ,
271
316
ɵproviders : [
272
317
{
273
318
provide : ROUTES ,
274
319
useValue : routeConfig ,
275
320
multi : true ,
276
321
} ,
322
+ provideEnvironmentInitializer ( ( ) => {
323
+ const config = inject ( SERVER_ROUTES_CONFIG ) ;
324
+ config . appShellRoute = APP_SHELL_ROUTE ;
325
+ } ) ,
277
326
] ,
278
327
} ;
279
328
}
329
+
330
+ /**
331
+ * Configures server-side rendering for an Angular application.
332
+ *
333
+ * This function sets up the necessary providers for server-side rendering, including
334
+ * support for server routes and app shell. It combines features configured using
335
+ * `withRoutes` and `withAppShell` to provide a comprehensive server-side rendering setup.
336
+ *
337
+ * @param features - Optional features to configure additional server rendering behaviors.
338
+ * @returns An `EnvironmentProviders` instance with the server-side rendering configuration.
339
+ *
340
+ * @example
341
+ * Basic example of how you can enable server-side rendering in your application
342
+ * when using the `bootstrapApplication` function:
343
+ *
344
+ * ```ts
345
+ * import { bootstrapApplication } from '@angular/platform-browser';
346
+ * import { provideServerRendering, withRoutes, withAppShell } from '@angular/ssr';
347
+ * import { AppComponent } from './app/app.component';
348
+ * import { SERVER_ROUTES } from './app/app.server.routes';
349
+ * import { AppShellComponent } from './app/app-shell.component';
350
+ *
351
+ * bootstrapApplication(AppComponent, {
352
+ * providers: [
353
+ * provideServerRendering(
354
+ * withRoutes(SERVER_ROUTES),
355
+ * withAppShell(AppShellComponent)
356
+ * )
357
+ * ]
358
+ * });
359
+ * ```
360
+ * @see {@link withRoutes } configures server-side routing
361
+ * @see {@link withAppShell } configures the application shell
362
+ */
363
+ export function provideServerRendering (
364
+ ...features : ServerRenderingFeature < ServerRenderingFeatureKind > [ ]
365
+ ) : EnvironmentProviders {
366
+ let hasAppShell = false ;
367
+ let hasServerRoutes = false ;
368
+ const providers : ( Provider | EnvironmentProviders ) [ ] = [ provideServerRenderingPlatformServer ( ) ] ;
369
+
370
+ for ( const { ɵkind, ɵproviders } of features ) {
371
+ hasAppShell ||= ɵkind === ServerRenderingFeatureKind . AppShell ;
372
+ hasServerRoutes ||= ɵkind === ServerRenderingFeatureKind . ServerRoutes ;
373
+ providers . push ( ...ɵproviders ) ;
374
+ }
375
+
376
+ if ( ! hasServerRoutes && hasAppShell ) {
377
+ throw new Error (
378
+ `Configuration error: found 'withAppShell()' without 'withRoutes()' in the same call to 'provideServerRendering()'.` +
379
+ `The 'withAppShell()' function requires 'withRoutes()' to be used.` ,
380
+ ) ;
381
+ }
382
+
383
+ return makeEnvironmentProviders ( providers ) ;
384
+ }
0 commit comments