@angular/ssr 19.0.0-rc.0 → 19.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/node.mjs +13 -43
- package/fesm2022/node.mjs.map +1 -1
- package/fesm2022/ssr.mjs +197 -132
- package/fesm2022/ssr.mjs.map +1 -1
- package/fesm2022/tokens.mjs +48 -5
- package/fesm2022/tokens.mjs.map +1 -1
- package/index.d.ts +144 -64
- package/node/index.d.ts +12 -40
- package/package.json +7 -7
- package/third_party/beasties/index.js.map +1 -1
- package/tokens/index.d.ts +38 -4
package/fesm2022/ssr.mjs
CHANGED
|
@@ -21,22 +21,31 @@ class ServerAssets {
|
|
|
21
21
|
/**
|
|
22
22
|
* Retrieves the content of a server-side asset using its path.
|
|
23
23
|
*
|
|
24
|
-
* @param path - The path to the server asset.
|
|
25
|
-
* @returns
|
|
26
|
-
* @throws Error
|
|
24
|
+
* @param path - The path to the server asset within the manifest.
|
|
25
|
+
* @returns The server asset associated with the provided path, as a `ServerAsset` object.
|
|
26
|
+
* @throws Error - Throws an error if the asset does not exist.
|
|
27
27
|
*/
|
|
28
|
-
|
|
28
|
+
getServerAsset(path) {
|
|
29
29
|
const asset = this.manifest.assets.get(path);
|
|
30
30
|
if (!asset) {
|
|
31
31
|
throw new Error(`Server asset '${path}' does not exist.`);
|
|
32
32
|
}
|
|
33
|
-
return asset
|
|
33
|
+
return asset;
|
|
34
34
|
}
|
|
35
35
|
/**
|
|
36
|
-
*
|
|
36
|
+
* Checks if a specific server-side asset exists.
|
|
37
37
|
*
|
|
38
|
-
* @
|
|
39
|
-
* @
|
|
38
|
+
* @param path - The path to the server asset.
|
|
39
|
+
* @returns A boolean indicating whether the asset exists.
|
|
40
|
+
*/
|
|
41
|
+
hasServerAsset(path) {
|
|
42
|
+
return this.manifest.assets.has(path);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Retrieves the asset for 'index.server.html'.
|
|
46
|
+
*
|
|
47
|
+
* @returns The `ServerAsset` object for 'index.server.html'.
|
|
48
|
+
* @throws Error - Throws an error if 'index.server.html' does not exist.
|
|
40
49
|
*/
|
|
41
50
|
getIndexServerHtml() {
|
|
42
51
|
return this.getServerAsset('index.server.html');
|
|
@@ -300,6 +309,8 @@ function isNgModule(value) {
|
|
|
300
309
|
|
|
301
310
|
/**
|
|
302
311
|
* Different rendering modes for server routes.
|
|
312
|
+
* @see {@link provideServerRoutesConfig}
|
|
313
|
+
* @see {@link ServerRoute}
|
|
303
314
|
* @developerPreview
|
|
304
315
|
*/
|
|
305
316
|
var RenderMode;
|
|
@@ -316,7 +327,7 @@ var RenderMode;
|
|
|
316
327
|
/**
|
|
317
328
|
* Defines the fallback strategies for Static Site Generation (SSG) routes when a pre-rendered path is not available.
|
|
318
329
|
* This is particularly relevant for routes with parameterized URLs where some paths might not be pre-rendered at build time.
|
|
319
|
-
*
|
|
330
|
+
* @see {@link ServerRoutePrerenderWithParams}
|
|
320
331
|
* @developerPreview
|
|
321
332
|
*/
|
|
322
333
|
var PrerenderFallback;
|
|
@@ -347,9 +358,13 @@ const SERVER_ROUTES_CONFIG = new InjectionToken('SERVER_ROUTES_CONFIG');
|
|
|
347
358
|
*
|
|
348
359
|
* @param routes - An array of server routes to be provided.
|
|
349
360
|
* @returns An `EnvironmentProviders` object that contains the server routes configuration.
|
|
361
|
+
* @see {@link ServerRoute}
|
|
350
362
|
* @developerPreview
|
|
351
363
|
*/
|
|
352
364
|
function provideServerRoutesConfig(routes) {
|
|
365
|
+
if (typeof ngServerMode === 'undefined' || !ngServerMode) {
|
|
366
|
+
throw new Error(`The 'provideServerRoutesConfig' function should not be invoked within the browser portion of the application.`);
|
|
367
|
+
}
|
|
353
368
|
return makeEnvironmentProviders([
|
|
354
369
|
{
|
|
355
370
|
provide: SERVER_ROUTES_CONFIG,
|
|
@@ -578,6 +593,7 @@ async function* traverseRoutesConfig(options) {
|
|
|
578
593
|
matchedMetaData.presentInClientRouter = true;
|
|
579
594
|
}
|
|
580
595
|
const metadata = {
|
|
596
|
+
renderMode: RenderMode.Prerender,
|
|
581
597
|
...matchedMetaData,
|
|
582
598
|
route: currentRoutePath,
|
|
583
599
|
};
|
|
@@ -883,7 +899,7 @@ async function getRoutesFromAngularRouterConfig(bootstrap, document, url, invoke
|
|
|
883
899
|
*/
|
|
884
900
|
async function extractRoutesAndCreateRouteTree(url, manifest = getAngularAppManifest(), invokeGetPrerenderParams = false, includePrerenderFallbackRoutes = true) {
|
|
885
901
|
const routeTree = new RouteTree();
|
|
886
|
-
const document = await new ServerAssets(manifest).getIndexServerHtml();
|
|
902
|
+
const document = await new ServerAssets(manifest).getIndexServerHtml().text();
|
|
887
903
|
const bootstrap = await manifest.bootstrap();
|
|
888
904
|
const { baseHref, routes, errors } = await getRoutesFromAngularRouterConfig(bootstrap, document, url, invokeGetPrerenderParams, includePrerenderFallbackRoutes);
|
|
889
905
|
for (const { route, ...metadata } of routes) {
|
|
@@ -1391,11 +1407,29 @@ const SERVER_CONTEXT_VALUE = {
|
|
|
1391
1407
|
* The `AngularServerApp` class handles server-side rendering and asset management for a specific locale.
|
|
1392
1408
|
*/
|
|
1393
1409
|
class AngularServerApp {
|
|
1410
|
+
options;
|
|
1394
1411
|
/**
|
|
1395
|
-
*
|
|
1396
|
-
*
|
|
1412
|
+
* Whether prerendered routes should be rendered on demand or served directly.
|
|
1413
|
+
*
|
|
1414
|
+
* @see {@link AngularServerAppOptions.allowStaticRouteRender} for more details.
|
|
1397
1415
|
*/
|
|
1398
|
-
|
|
1416
|
+
allowStaticRouteRender;
|
|
1417
|
+
/**
|
|
1418
|
+
* Hooks for extending or modifying server behavior.
|
|
1419
|
+
*
|
|
1420
|
+
* @see {@link AngularServerAppOptions.hooks} for more details.
|
|
1421
|
+
*/
|
|
1422
|
+
hooks;
|
|
1423
|
+
/**
|
|
1424
|
+
* Constructs an instance of `AngularServerApp`.
|
|
1425
|
+
*
|
|
1426
|
+
* @param options Optional configuration options for the server application.
|
|
1427
|
+
*/
|
|
1428
|
+
constructor(options = {}) {
|
|
1429
|
+
this.options = options;
|
|
1430
|
+
this.allowStaticRouteRender = this.options.allowStaticRouteRender ?? false;
|
|
1431
|
+
this.hooks = options.hooks ?? new Hooks();
|
|
1432
|
+
}
|
|
1399
1433
|
/**
|
|
1400
1434
|
* The manifest associated with this server application.
|
|
1401
1435
|
*/
|
|
@@ -1425,71 +1459,86 @@ class AngularServerApp {
|
|
|
1425
1459
|
*/
|
|
1426
1460
|
criticalCssLRUCache = new LRUCache(MAX_INLINE_CSS_CACHE_ENTRIES);
|
|
1427
1461
|
/**
|
|
1428
|
-
*
|
|
1462
|
+
* Handles an incoming HTTP request by serving prerendered content, performing server-side rendering,
|
|
1463
|
+
* or delivering a static file for client-side rendered routes based on the `RenderMode` setting.
|
|
1429
1464
|
*
|
|
1430
|
-
*
|
|
1465
|
+
* @param request - The HTTP request to handle.
|
|
1466
|
+
* @param requestContext - Optional context for rendering, such as metadata associated with the request.
|
|
1467
|
+
* @returns A promise that resolves to the resulting HTTP response object, or `null` if no matching Angular route is found.
|
|
1431
1468
|
*
|
|
1432
|
-
* @
|
|
1433
|
-
*
|
|
1434
|
-
*
|
|
1435
|
-
* @returns A promise that resolves to the HTTP response object resulting from the rendering, or null if no match is found.
|
|
1469
|
+
* @remarks A request to `https://www.example.com/page/index.html` will serve or render the Angular route
|
|
1470
|
+
* corresponding to `https://www.example.com/page`.
|
|
1436
1471
|
*/
|
|
1437
|
-
|
|
1472
|
+
async handle(request, requestContext) {
|
|
1473
|
+
const url = new URL(request.url);
|
|
1474
|
+
this.router ??= await ServerRouter.from(this.manifest, url);
|
|
1475
|
+
const matchedRoute = this.router.match(url);
|
|
1476
|
+
if (!matchedRoute) {
|
|
1477
|
+
// Not a known Angular route.
|
|
1478
|
+
return null;
|
|
1479
|
+
}
|
|
1480
|
+
if (matchedRoute.renderMode === RenderMode.Prerender) {
|
|
1481
|
+
const response = await this.handleServe(request, matchedRoute);
|
|
1482
|
+
if (response) {
|
|
1483
|
+
return response;
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1438
1486
|
return Promise.race([
|
|
1439
|
-
this.
|
|
1440
|
-
this.handleRendering(request,
|
|
1487
|
+
this.waitForRequestAbort(request),
|
|
1488
|
+
this.handleRendering(request, matchedRoute, requestContext),
|
|
1441
1489
|
]);
|
|
1442
1490
|
}
|
|
1443
1491
|
/**
|
|
1444
|
-
*
|
|
1445
|
-
* The rendering process can be interrupted by an abort signal, where the first resolved promise (either from the abort
|
|
1446
|
-
* or the render process) will dictate the outcome.
|
|
1492
|
+
* Handles serving a prerendered static asset if available for the matched route.
|
|
1447
1493
|
*
|
|
1448
|
-
*
|
|
1449
|
-
* @param signal - (Optional) An `AbortSignal` object that allows for the cancellation of the rendering process.
|
|
1450
|
-
* @returns A promise that resolves to the generated HTTP response object, or `null` if no matching route is found.
|
|
1451
|
-
*/
|
|
1452
|
-
renderStatic(url, signal) {
|
|
1453
|
-
const request = new Request(url, { signal });
|
|
1454
|
-
return Promise.race([
|
|
1455
|
-
this.createAbortPromise(request),
|
|
1456
|
-
this.handleRendering(request, /** isSsrMode */ false),
|
|
1457
|
-
]);
|
|
1458
|
-
}
|
|
1459
|
-
/**
|
|
1460
|
-
* Creates a promise that rejects when the request is aborted.
|
|
1494
|
+
* This method only supports `GET` and `HEAD` requests.
|
|
1461
1495
|
*
|
|
1462
|
-
* @param request - The HTTP request
|
|
1463
|
-
* @
|
|
1496
|
+
* @param request - The incoming HTTP request for serving a static page.
|
|
1497
|
+
* @param matchedRoute - The metadata of the matched route for rendering.
|
|
1498
|
+
* If not provided, the method attempts to find a matching route based on the request URL.
|
|
1499
|
+
* @returns A promise that resolves to a `Response` object if the prerendered page is found, or `null`.
|
|
1464
1500
|
*/
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1501
|
+
async handleServe(request, matchedRoute) {
|
|
1502
|
+
const { headers, renderMode } = matchedRoute;
|
|
1503
|
+
if (renderMode !== RenderMode.Prerender) {
|
|
1504
|
+
return null;
|
|
1505
|
+
}
|
|
1506
|
+
const { url, method } = request;
|
|
1507
|
+
if (method !== 'GET' && method !== 'HEAD') {
|
|
1508
|
+
return null;
|
|
1509
|
+
}
|
|
1510
|
+
const { pathname } = stripIndexHtmlFromURL(new URL(request.url));
|
|
1511
|
+
const assetPath = stripLeadingSlash(joinUrlParts(pathname, 'index.html'));
|
|
1512
|
+
if (!this.assets.hasServerAsset(assetPath)) {
|
|
1513
|
+
return null;
|
|
1514
|
+
}
|
|
1515
|
+
const { text, hash, size } = this.assets.getServerAsset(assetPath);
|
|
1516
|
+
const etag = `"${hash}"`;
|
|
1517
|
+
return request.headers.get('if-none-match') === etag
|
|
1518
|
+
? new Response(undefined, { status: 304, statusText: 'Not Modified' })
|
|
1519
|
+
: new Response(await text(), {
|
|
1520
|
+
headers: {
|
|
1521
|
+
'Content-Length': size.toString(),
|
|
1522
|
+
'ETag': etag,
|
|
1523
|
+
'Content-Type': 'text/html;charset=UTF-8',
|
|
1524
|
+
...headers,
|
|
1525
|
+
},
|
|
1526
|
+
});
|
|
1473
1527
|
}
|
|
1474
1528
|
/**
|
|
1475
1529
|
* Handles the server-side rendering process for the given HTTP request.
|
|
1476
1530
|
* This method matches the request URL to a route and performs rendering if a matching route is found.
|
|
1477
1531
|
*
|
|
1478
1532
|
* @param request - The incoming HTTP request to be processed.
|
|
1479
|
-
* @param
|
|
1533
|
+
* @param matchedRoute - The metadata of the matched route for rendering.
|
|
1534
|
+
* If not provided, the method attempts to find a matching route based on the request URL.
|
|
1480
1535
|
* @param requestContext - Optional additional context for rendering, such as request metadata.
|
|
1481
1536
|
*
|
|
1482
1537
|
* @returns A promise that resolves to the rendered response, or null if no matching route is found.
|
|
1483
1538
|
*/
|
|
1484
|
-
async handleRendering(request,
|
|
1485
|
-
const url = new URL(request.url);
|
|
1486
|
-
this.router ??= await ServerRouter.from(this.manifest, url);
|
|
1487
|
-
const matchedRoute = this.router.match(url);
|
|
1488
|
-
if (!matchedRoute) {
|
|
1489
|
-
// Not a known Angular route.
|
|
1490
|
-
return null;
|
|
1491
|
-
}
|
|
1539
|
+
async handleRendering(request, matchedRoute, requestContext) {
|
|
1492
1540
|
const { redirectTo, status } = matchedRoute;
|
|
1541
|
+
const url = new URL(request.url);
|
|
1493
1542
|
if (redirectTo !== undefined) {
|
|
1494
1543
|
// Note: The status code is validated during route extraction.
|
|
1495
1544
|
// 302 Found is used by default for redirections
|
|
@@ -1497,35 +1546,36 @@ class AngularServerApp {
|
|
|
1497
1546
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1498
1547
|
return Response.redirect(new URL(redirectTo, url), status ?? 302);
|
|
1499
1548
|
}
|
|
1500
|
-
const { renderMode
|
|
1549
|
+
const { renderMode, headers } = matchedRoute;
|
|
1550
|
+
if (!this.allowStaticRouteRender &&
|
|
1551
|
+
(renderMode === RenderMode.Prerender || renderMode === RenderMode.AppShell)) {
|
|
1552
|
+
return null;
|
|
1553
|
+
}
|
|
1501
1554
|
const platformProviders = [];
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
headers
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
// Serve the client-side rendered version if the route is configured for CSR.
|
|
1527
|
-
return new Response(await this.assets.getServerAsset('index.csr.html'), responseInit);
|
|
1528
|
-
}
|
|
1555
|
+
// Initialize the response with status and headers if available.
|
|
1556
|
+
const responseInit = {
|
|
1557
|
+
status,
|
|
1558
|
+
headers: new Headers({
|
|
1559
|
+
'Content-Type': 'text/html;charset=UTF-8',
|
|
1560
|
+
...headers,
|
|
1561
|
+
}),
|
|
1562
|
+
};
|
|
1563
|
+
if (renderMode === RenderMode.Server) {
|
|
1564
|
+
// Configure platform providers for request and response only for SSR.
|
|
1565
|
+
platformProviders.push({
|
|
1566
|
+
provide: REQUEST,
|
|
1567
|
+
useValue: request,
|
|
1568
|
+
}, {
|
|
1569
|
+
provide: REQUEST_CONTEXT,
|
|
1570
|
+
useValue: requestContext,
|
|
1571
|
+
}, {
|
|
1572
|
+
provide: RESPONSE_INIT,
|
|
1573
|
+
useValue: responseInit,
|
|
1574
|
+
});
|
|
1575
|
+
}
|
|
1576
|
+
else if (renderMode === RenderMode.Client) {
|
|
1577
|
+
// Serve the client-side rendered version if the route is configured for CSR.
|
|
1578
|
+
return new Response(await this.assets.getServerAsset('index.csr.html').text(), responseInit);
|
|
1529
1579
|
}
|
|
1530
1580
|
const { manifest: { bootstrap, inlineCriticalCss, locale }, hooks, assets, } = this;
|
|
1531
1581
|
if (locale !== undefined) {
|
|
@@ -1534,7 +1584,7 @@ class AngularServerApp {
|
|
|
1534
1584
|
useValue: locale,
|
|
1535
1585
|
});
|
|
1536
1586
|
}
|
|
1537
|
-
let html = await assets.getIndexServerHtml();
|
|
1587
|
+
let html = await assets.getIndexServerHtml().text();
|
|
1538
1588
|
// Skip extra microtask if there are no pre hooks.
|
|
1539
1589
|
if (hooks.has('html:transform:pre')) {
|
|
1540
1590
|
html = await hooks.run('html:transform:pre', { html, url });
|
|
@@ -1545,16 +1595,16 @@ class AngularServerApp {
|
|
|
1545
1595
|
// Optionally inline critical CSS.
|
|
1546
1596
|
this.inlineCriticalCssProcessor ??= new InlineCriticalCssProcessor((path) => {
|
|
1547
1597
|
const fileName = path.split('/').pop() ?? path;
|
|
1548
|
-
return this.assets.getServerAsset(fileName);
|
|
1598
|
+
return this.assets.getServerAsset(fileName).text();
|
|
1549
1599
|
});
|
|
1550
1600
|
// TODO(alanagius): remove once Node.js version 18 is no longer supported.
|
|
1551
|
-
if (
|
|
1601
|
+
if (renderMode === RenderMode.Server && typeof crypto === 'undefined') {
|
|
1552
1602
|
// eslint-disable-next-line no-console
|
|
1553
1603
|
console.error(`The global 'crypto' module is unavailable. ` +
|
|
1554
1604
|
`If you are running on Node.js, please ensure you are using version 20 or later, ` +
|
|
1555
1605
|
`which includes built-in support for the Web Crypto module.`);
|
|
1556
1606
|
}
|
|
1557
|
-
if (
|
|
1607
|
+
if (renderMode === RenderMode.Server && typeof crypto !== 'undefined') {
|
|
1558
1608
|
// Only cache if we are running in SSR Mode.
|
|
1559
1609
|
const cacheKey = await sha256(html);
|
|
1560
1610
|
let htmlWithCriticalCss = this.criticalCssLRUCache.get(cacheKey);
|
|
@@ -1570,16 +1620,35 @@ class AngularServerApp {
|
|
|
1570
1620
|
}
|
|
1571
1621
|
return new Response(html, responseInit);
|
|
1572
1622
|
}
|
|
1623
|
+
/**
|
|
1624
|
+
* Returns a promise that rejects if the request is aborted.
|
|
1625
|
+
*
|
|
1626
|
+
* @param request - The HTTP request object being monitored for abortion.
|
|
1627
|
+
* @returns A promise that never resolves and rejects with an `AbortError`
|
|
1628
|
+
* if the request is aborted.
|
|
1629
|
+
*/
|
|
1630
|
+
waitForRequestAbort(request) {
|
|
1631
|
+
return new Promise((_, reject) => {
|
|
1632
|
+
request.signal.addEventListener('abort', () => {
|
|
1633
|
+
const abortError = new Error(`Request for: ${request.url} was aborted.\n${request.signal.reason}`);
|
|
1634
|
+
abortError.name = 'AbortError';
|
|
1635
|
+
reject(abortError);
|
|
1636
|
+
}, { once: true });
|
|
1637
|
+
});
|
|
1638
|
+
}
|
|
1573
1639
|
}
|
|
1574
1640
|
let angularServerApp;
|
|
1575
1641
|
/**
|
|
1576
1642
|
* Retrieves or creates an instance of `AngularServerApp`.
|
|
1577
1643
|
* - If an instance of `AngularServerApp` already exists, it will return the existing one.
|
|
1578
1644
|
* - If no instance exists, it will create a new one with the provided options.
|
|
1645
|
+
*
|
|
1646
|
+
* @param options Optional configuration options for the server application.
|
|
1647
|
+
*
|
|
1579
1648
|
* @returns The existing or newly created instance of `AngularServerApp`.
|
|
1580
1649
|
*/
|
|
1581
|
-
function getOrCreateAngularServerApp() {
|
|
1582
|
-
return (angularServerApp ??= new AngularServerApp());
|
|
1650
|
+
function getOrCreateAngularServerApp(options) {
|
|
1651
|
+
return (angularServerApp ??= new AngularServerApp(options));
|
|
1583
1652
|
}
|
|
1584
1653
|
/**
|
|
1585
1654
|
* Destroys the existing `AngularServerApp` instance, releasing associated resources and resetting the
|
|
@@ -1640,12 +1709,21 @@ function getPotentialLocaleIdFromUrl(url, basePath) {
|
|
|
1640
1709
|
* Manages Angular server applications (including localized ones), handles rendering requests,
|
|
1641
1710
|
* and optionally transforms index HTML before rendering.
|
|
1642
1711
|
*
|
|
1643
|
-
* @
|
|
1712
|
+
* @remarks This class should be instantiated once and used as a singleton across the server-side
|
|
1644
1713
|
* application to ensure consistent handling of rendering requests and resource management.
|
|
1645
1714
|
*
|
|
1646
1715
|
* @developerPreview
|
|
1647
1716
|
*/
|
|
1648
1717
|
class AngularAppEngine {
|
|
1718
|
+
/**
|
|
1719
|
+
* A flag to enable or disable the rendering of prerendered routes.
|
|
1720
|
+
*
|
|
1721
|
+
* Typically used during development to avoid prerendering all routes ahead of time,
|
|
1722
|
+
* allowing them to be rendered on the fly as requested.
|
|
1723
|
+
*
|
|
1724
|
+
* @private
|
|
1725
|
+
*/
|
|
1726
|
+
static ɵallowStaticRouteRender = false;
|
|
1649
1727
|
/**
|
|
1650
1728
|
* Hooks for extending or modifying the behavior of the server application.
|
|
1651
1729
|
* These hooks are used by the Angular CLI when running the development server and
|
|
@@ -1654,15 +1732,6 @@ class AngularAppEngine {
|
|
|
1654
1732
|
* @private
|
|
1655
1733
|
*/
|
|
1656
1734
|
static ɵhooks = /* #__PURE__*/ new Hooks();
|
|
1657
|
-
/**
|
|
1658
|
-
* Provides access to the hooks for extending or modifying the server application's behavior.
|
|
1659
|
-
* This allows attaching custom functionality to various server application lifecycle events.
|
|
1660
|
-
*
|
|
1661
|
-
* @internal
|
|
1662
|
-
*/
|
|
1663
|
-
get hooks() {
|
|
1664
|
-
return AngularAppEngine.ɵhooks;
|
|
1665
|
-
}
|
|
1666
1735
|
/**
|
|
1667
1736
|
* The manifest for the server application.
|
|
1668
1737
|
*/
|
|
@@ -1672,50 +1741,46 @@ class AngularAppEngine {
|
|
|
1672
1741
|
*/
|
|
1673
1742
|
entryPointsCache = new Map();
|
|
1674
1743
|
/**
|
|
1675
|
-
*
|
|
1744
|
+
* Handles an incoming HTTP request by serving prerendered content, performing server-side rendering,
|
|
1745
|
+
* or delivering a static file for client-side rendered routes based on the `RenderMode` setting.
|
|
1676
1746
|
*
|
|
1677
|
-
*
|
|
1678
|
-
*
|
|
1747
|
+
* @param request - The HTTP request to handle.
|
|
1748
|
+
* @param requestContext - Optional context for rendering, such as metadata associated with the request.
|
|
1749
|
+
* @returns A promise that resolves to the resulting HTTP response object, or `null` if no matching Angular route is found.
|
|
1679
1750
|
*
|
|
1680
|
-
*
|
|
1681
|
-
* A request to `https://www.example.com/page/index.html` will render the Angular route
|
|
1751
|
+
* @remarks A request to `https://www.example.com/page/index.html` will serve or render the Angular route
|
|
1682
1752
|
* corresponding to `https://www.example.com/page`.
|
|
1753
|
+
*/
|
|
1754
|
+
async handle(request, requestContext) {
|
|
1755
|
+
const serverApp = await this.getAngularServerAppForRequest(request);
|
|
1756
|
+
return serverApp ? serverApp.handle(request, requestContext) : null;
|
|
1757
|
+
}
|
|
1758
|
+
/**
|
|
1759
|
+
* Retrieves the Angular server application instance for a given request.
|
|
1760
|
+
*
|
|
1761
|
+
* This method checks if the request URL corresponds to an Angular application entry point.
|
|
1762
|
+
* If so, it initializes or retrieves an instance of the Angular server application for that entry point.
|
|
1763
|
+
* Requests that resemble file requests (except for `/index.html`) are skipped.
|
|
1683
1764
|
*
|
|
1684
|
-
* @param request - The incoming HTTP request object
|
|
1685
|
-
* @
|
|
1686
|
-
*
|
|
1687
|
-
* rather than an application route.
|
|
1765
|
+
* @param request - The incoming HTTP request object.
|
|
1766
|
+
* @returns A promise that resolves to an `AngularServerApp` instance if a valid entry point is found,
|
|
1767
|
+
* or `null` if no entry point matches the request URL.
|
|
1688
1768
|
*/
|
|
1689
|
-
async
|
|
1769
|
+
async getAngularServerAppForRequest(request) {
|
|
1690
1770
|
// Skip if the request looks like a file but not `/index.html`.
|
|
1691
1771
|
const url = new URL(request.url);
|
|
1692
1772
|
const entryPoint = await this.getEntryPointExportsForUrl(url);
|
|
1693
1773
|
if (!entryPoint) {
|
|
1694
1774
|
return null;
|
|
1695
1775
|
}
|
|
1696
|
-
const { ɵgetOrCreateAngularServerApp: getOrCreateAngularServerApp } = entryPoint;
|
|
1697
1776
|
// Note: Using `instanceof` is not feasible here because `AngularServerApp` will
|
|
1698
1777
|
// be located in separate bundles, making `instanceof` checks unreliable.
|
|
1699
|
-
|
|
1700
|
-
const serverApp =
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
* Retrieves HTTP headers for a request associated with statically generated (SSG) pages,
|
|
1706
|
-
* based on the URL pathname.
|
|
1707
|
-
*
|
|
1708
|
-
* @param request - The incoming request object.
|
|
1709
|
-
* @returns A `Map` containing the HTTP headers as key-value pairs.
|
|
1710
|
-
* @note This function should be used exclusively for retrieving headers of SSG pages.
|
|
1711
|
-
*/
|
|
1712
|
-
getPrerenderHeaders(request) {
|
|
1713
|
-
if (this.manifest.staticPathsHeaders.size === 0) {
|
|
1714
|
-
return new Map();
|
|
1715
|
-
}
|
|
1716
|
-
const { pathname } = stripIndexHtmlFromURL(new URL(request.url));
|
|
1717
|
-
const headers = this.manifest.staticPathsHeaders.get(stripTrailingSlash(pathname));
|
|
1718
|
-
return new Map(headers);
|
|
1778
|
+
const ɵgetOrCreateAngularServerApp = entryPoint.ɵgetOrCreateAngularServerApp;
|
|
1779
|
+
const serverApp = ɵgetOrCreateAngularServerApp({
|
|
1780
|
+
allowStaticRouteRender: AngularAppEngine.ɵallowStaticRouteRender,
|
|
1781
|
+
hooks: AngularAppEngine.ɵhooks,
|
|
1782
|
+
});
|
|
1783
|
+
return serverApp;
|
|
1719
1784
|
}
|
|
1720
1785
|
/**
|
|
1721
1786
|
* Retrieves the exports for a specific entry point, caching the result.
|