/
main.ts
88 lines (78 loc) · 2.62 KB
/
main.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import type { StaticProvider } from '@angular/core';
import { CommonEngine, RenderOptions as CommonRenderOptions } from '@nguniversal/common/engine';
import { REQUEST, RESPONSE } from '@nguniversal/express-engine/tokens';
import type { Request, Response } from 'express';
/**
* These are the allowed options for the engine
*/
export interface NgSetupOptions
extends Pick<CommonRenderOptions, 'providers' | 'publicPath' | 'inlineCriticalCss'> {
bootstrap: NonNullable<CommonRenderOptions['bootstrap']>;
}
/**
* These are the allowed options for the render
*/
export interface RenderOptions extends CommonRenderOptions {
req: Request;
res?: Response;
}
/**
* This is an express engine for handling Angular Applications
*/
export function ngExpressEngine(setupOptions: Readonly<NgSetupOptions>) {
const engine = new CommonEngine(setupOptions.bootstrap, setupOptions.providers);
return function (
filePath: string,
options: object,
callback: (err?: Error | null, html?: string) => void,
) {
try {
const renderOptions = { ...options } as RenderOptions;
if (!setupOptions.bootstrap && !renderOptions.bootstrap) {
throw new Error('You must pass in a NgModule to be bootstrapped');
}
const { req } = renderOptions;
const res = renderOptions.res ?? req.res;
renderOptions.url =
renderOptions.url ?? `${req.protocol}://${req.get('host') || ''}${req.baseUrl}${req.url}`;
renderOptions.documentFilePath = renderOptions.documentFilePath ?? filePath;
renderOptions.providers = [...(renderOptions.providers ?? []), getReqResProviders(req, res)];
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
renderOptions.publicPath =
renderOptions.publicPath ?? setupOptions.publicPath ?? (options as any).settings?.views;
renderOptions.inlineCriticalCss =
renderOptions.inlineCriticalCss ?? setupOptions.inlineCriticalCss;
engine
.render(renderOptions)
.then((html) => callback(null, html))
.catch(callback);
} catch (err) {
callback(err);
}
};
}
/**
* Get providers of the request and response
*/
function getReqResProviders(req: Request, res?: Response): StaticProvider[] {
const providers: StaticProvider[] = [
{
provide: REQUEST,
useValue: req,
},
];
if (res) {
providers.push({
provide: RESPONSE,
useValue: res,
});
}
return providers;
}