Skip to content

Commit 585d7da

Browse files
committed
docs: revise and consolidate server rendering guides
This commit updates the server rendering documentation and merges the prerendering, hybrid, and SSR sections for better clarity and organization. Closes angular#52884 and angular#60079.
1 parent d79c57d commit 585d7da

File tree

13 files changed

+394
-533
lines changed

13 files changed

+394
-533
lines changed

adev/src/app/routes.ts

+8
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,14 @@ const REDIRECT_ROUTES: Route[] = [
214214
path: 'guide/components/anatomy-of-components',
215215
redirectTo: '/guide/components',
216216
},
217+
{
218+
path: 'guide/hybrid-rendering',
219+
redirectTo: '/guide/ssr',
220+
},
221+
{
222+
path: 'guide/prerendering',
223+
redirectTo: '/guide/ssr',
224+
},
217225
{
218226
path: 'guide',
219227
children: [

adev/src/app/sub-navigation-data.ts

+1-11
Original file line numberDiff line numberDiff line change
@@ -427,20 +427,10 @@ const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [
427427
contentPath: 'guide/performance/overview',
428428
},
429429
{
430-
label: 'Server-side rendering',
430+
label: 'Server-side and hybrid-rendering',
431431
path: 'guide/ssr',
432432
contentPath: 'guide/ssr',
433433
},
434-
{
435-
label: 'Build-time prerendering',
436-
path: 'guide/prerendering',
437-
contentPath: 'guide/prerendering',
438-
},
439-
{
440-
label: 'Hybrid rendering with server routing',
441-
path: 'guide/hybrid-rendering',
442-
contentPath: 'guide/hybrid-rendering',
443-
},
444434
{
445435
label: 'Hydration',
446436
path: 'guide/hydration',

adev/src/content/ecosystem/service-workers/app-shell.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Do this with the following Angular CLI command:
1111

1212
<docs-code language="shell">
1313

14-
ng new my-app --routing
14+
ng new my-app
1515

1616
</docs-code>
1717

+50-53
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,60 @@
11
// #docplaster
22

3-
import {APP_BASE_HREF} from '@angular/common';
4-
import {CommonEngine} from '@angular/ssr/node';
3+
import {
4+
AngularNodeAppEngine,
5+
createNodeRequestHandler,
6+
isMainModule,
7+
writeResponseToNodeResponse,
8+
} from '@angular/ssr/node';
59
import express from 'express';
10+
import {dirname, resolve} from 'node:path';
611
import {fileURLToPath} from 'node:url';
7-
import {dirname, join, resolve} from 'node:path';
8-
import bootstrap from './src/main.server';
9-
10-
// The Express app is exported so that it can be used by serverless Functions.
11-
export function app(): express.Express {
12-
const server = express();
13-
const serverDistFolder = dirname(fileURLToPath(import.meta.url));
14-
const browserDistFolder = resolve(serverDistFolder, '../browser');
15-
const indexHtml = join(serverDistFolder, 'index.server.html');
16-
const commonEngine = new CommonEngine();
17-
18-
server.set('view engine', 'html');
19-
server.set('views', browserDistFolder);
20-
21-
// TODO: implement data requests securely
22-
// Serve data from URLS that begin "/api/"
23-
server.get('/api/**', (req, res) => {
24-
res.status(404).send('data requests are not yet supported');
25-
});
26-
// Serve static files from /browser
27-
server.get(
28-
'*.*',
29-
express.static(browserDistFolder, {
30-
maxAge: '1y',
31-
}),
32-
);
33-
34-
// All regular routes use the Angular engine
35-
server.get('*', (req, res, next) => {
36-
const {protocol, originalUrl, baseUrl, headers} = req;
37-
38-
commonEngine
39-
.render({
40-
bootstrap,
41-
documentFilePath: indexHtml,
42-
url: `${protocol}://${headers.host}${originalUrl}`,
43-
publicPath: browserDistFolder,
44-
providers: [{provide: APP_BASE_HREF, useValue: req.baseUrl}],
45-
})
46-
.then((html) => res.send(html))
47-
.catch((err) => next(err));
48-
});
4912

50-
return server;
51-
}
52-
53-
function run(): void {
13+
const serverDistFolder = dirname(fileURLToPath(import.meta.url));
14+
const browserDistFolder = resolve(serverDistFolder, '../browser');
15+
16+
const app = express();
17+
const angularApp = new AngularNodeAppEngine();
18+
19+
/**
20+
* Serve static files from /browser
21+
*/
22+
app.use(
23+
express.static(browserDistFolder, {
24+
maxAge: '1y',
25+
index: false,
26+
redirect: false,
27+
}),
28+
);
29+
30+
// TODO: implement data requests securely
31+
// Serve data from URLS that begin "/api/"
32+
app.get('/api/**', (req, res) => {
33+
res.status(404).send('data requests are not yet supported');
34+
});
35+
36+
/**
37+
* Handle all other requests by rendering the Angular application.
38+
*/
39+
app.use('/**', (req, res, next) => {
40+
angularApp
41+
.handle(req)
42+
.then((response) => (response ? writeResponseToNodeResponse(response, res) : next()))
43+
.catch(next);
44+
});
45+
46+
/**
47+
* Start the server if this module is the main entry point.
48+
* The server listens on the port defined by the `PORT` environment variable, or defaults to 4000.
49+
*/
50+
if (isMainModule(import.meta.url)) {
5451
const port = process.env['PORT'] || 4000;
55-
56-
// Start up the Node server
57-
const server = app();
58-
server.listen(port, () => {
52+
app.listen(port, () => {
5953
console.log(`Node Express server listening on http://localhost:${port}`);
6054
});
6155
}
6256

63-
run();
57+
/**
58+
* Request handler used by the Angular CLI (for dev-server and during build) or Firebase Cloud Functions.
59+
*/
60+
export const reqHandler = createNodeRequestHandler(app);
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import {mergeApplicationConfig, ApplicationConfig} from '@angular/core';
22
import {provideServerRendering} from '@angular/platform-server';
3+
import {provideServerRouting} from '@angular/ssr';
34
import {appConfig} from './app.config';
5+
import {serverRoutes} from './app.routes.server';
46

57
const serverConfig: ApplicationConfig = {
6-
providers: [provideServerRendering()],
8+
providers: [provideServerRendering(), provideServerRouting(serverRoutes)],
79
};
810

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

adev/src/content/examples/ssr/src/app/app.config.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// #docplaster
22
import {importProvidersFrom} from '@angular/core';
3-
import {provideProtractorTestingSupport} from '@angular/platform-browser';
3+
import {provideProtractorTestingSupport, withEventReplay} from '@angular/platform-browser';
44
import {provideClientHydration} from '@angular/platform-browser';
55
import {ApplicationConfig} from '@angular/core';
66
import {provideRouter} from '@angular/router';
@@ -15,7 +15,7 @@ export const appConfig: ApplicationConfig = {
1515
providers: [
1616
provideRouter(routes),
1717
provideHttpClient(withFetch()),
18-
provideClientHydration(),
18+
provideClientHydration(withEventReplay()),
1919
provideProtractorTestingSupport(), // essential for e2e testing
2020

2121
// TODO: Remove from production apps
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import {RenderMode, ServerRoute} from '@angular/ssr';
2+
3+
export const serverRoutes: ServerRoute[] = [
4+
{
5+
path: '**',
6+
renderMode: RenderMode.Prerender,
7+
},
8+
];

0 commit comments

Comments
 (0)