-
Notifications
You must be signed in to change notification settings - Fork 2
/
server.ts
85 lines (75 loc) · 2.6 KB
/
server.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
/* eslint-disable unicorn/prevent-abbreviations */
/* eslint-disable @typescript-eslint/no-explicit-any */
import { APP_BASE_HREF } from '@angular/common';
import { CommonEngine } from '@angular/ssr';
import express from 'express';
import compression from 'express-compression';
import { fileURLToPath } from 'node:url';
import { dirname, join, resolve } from 'node:path';
import bootstrap from './src/main.server';
import { TtlCache } from './src/app/server/ttl-cache';
import { onRequest } from 'firebase-functions/v2/https';
import { ArticlesLoader } from './src/app/shared/loaders/articles-loader';
import { TagsLoader } from './src/app/shared/loaders/tags-loader';
import { CacheLoader } from './src/app/server/cache-loader';
/**
* Express app. to serve Angular as well as cached data resources
* @returns Express app (exported for serverless function hosting)
*/
export function createApp() {
const server = express();
const serverDistributionFolder = dirname(fileURLToPath(import.meta.url));
const browserDistributionFolder = resolve(serverDistributionFolder, '../browser');
const indexHtml = join(serverDistributionFolder, 'index.server.html');
const commonEngine = new CommonEngine();
server.use(compression({ brotli: { enabled: true, zlib: {} } }));
server.set('view engine', 'html');
server.set('views', browserDistributionFolder);
const loaders: CacheLoader[] = [new ArticlesLoader(), new TagsLoader()];
/**
* Data cache
*/
const dataCache = new TtlCache(20, loaders);
// Serve static files from browser dist. folder
server.get(
'*.*',
express.static(browserDistributionFolder, {
maxAge: '1y',
}),
);
// Other routes use SSR or failing that, Angular engine
server.get(
'*',
async (request: any, res: any, next: any) => {
const path = request.url as string;
const pathLoader = loaders.find(loader => loader.matches(path));
if (pathLoader?.cacheable(path)) {
const cached = await dataCache.get(path, pathLoader);
res.send(cached);
} else if (pathLoader) {
const resource = await pathLoader.load(path);
res.send(resource);
} else {
next();
}
},
(request: any, res: any, next: any) => {
const { protocol, originalUrl, baseUrl, headers } = request;
commonEngine
.render({
bootstrap,
documentFilePath: indexHtml,
url: `${protocol}://${headers.host}${originalUrl}`,
publicPath: browserDistributionFolder,
providers: [{ provide: APP_BASE_HREF, useValue: baseUrl }],
})
.then(html => res.send(html))
.catch(error => next(error));
},
);
return onRequest(server);
}
/**
* Express app.
*/
export const app = createApp();