Skip to content

Commit cbd6460

Browse files
committed
feat: initial boilerplate and tooling to start matching server.ts to known variants
1 parent 66b9ccc commit cbd6460

File tree

6 files changed

+184
-1
lines changed

6 files changed

+184
-1
lines changed

.prettierignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,5 @@ node_modules
1717

1818
# Tests
1919
test
20-
tests/fixtures
20+
tests/fixtures
21+
tools/known-server-ts-signatures
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"5678601ed12556305074503967b44ae42c45c268579db057c25cbf4b21a7212e": "CommonEngine",
3+
"76419eb94b4b8672ba3bd79d34c5a66c7c30ff173995ecc6e0adc5808b86822d": "AppEngine"
4+
}

src/helpers/serverTsSignature.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
const { createHash } = require('node:crypto')
2+
3+
const knownSignatures = require('./knownServerTsSignatures.json')
4+
5+
/**
6+
* Takes a string and generates a signature for it
7+
* @param {string} content Text of module to generate signature for
8+
* @returns {string} Signature
9+
*/
10+
const generateServerTsSignature = (content) => createHash('sha256').update(content).digest('hex')
11+
12+
module.exports.generateServerTsSignature = generateServerTsSignature
13+
14+
/**
15+
* Tries to compare current content of server.ts with known signatures to decide which engine to use
16+
* @param {string} content Current content of server.ts
17+
* @returns {'AppEngine' | 'CommonEngine' | undefined}
18+
*/
19+
const getEngineBasedOnKnownSignatures = (content) => {
20+
const signature = generateServerTsSignature(content)
21+
return knownSignatures[signature]
22+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { readdir, readFile, writeFile } from 'node:fs/promises'
2+
import { join } from 'node:path'
3+
import { fileURLToPath } from 'node:url'
4+
5+
import { generateServerTsSignature } from '../src/helpers/serverTsSignature.js'
6+
7+
const hashToEngine = {}
8+
9+
for (const engine of ['CommonEngine', 'AppEngine']) {
10+
const knownFilesUsingEngineDirectory = fileURLToPath(
11+
new URL(join('known-server-ts-signatures', engine), import.meta.url),
12+
)
13+
const files = await readdir(knownFilesUsingEngineDirectory)
14+
for (const file of files) {
15+
const content = await readFile(join(knownFilesUsingEngineDirectory, file), 'utf-8')
16+
const signature = generateServerTsSignature(content)
17+
hashToEngine[signature] = engine
18+
}
19+
}
20+
21+
// write out source file matching current formatting rules
22+
await writeFile(
23+
fileURLToPath(new URL('../src/helpers/knownServerTsSignatures.json', import.meta.url)),
24+
`${JSON.stringify(hashToEngine, null, 2)}\n`,
25+
)
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import {
2+
AngularNodeAppEngine,
3+
createNodeRequestHandler,
4+
isMainModule,
5+
writeResponseToNodeResponse,
6+
} from '@angular/ssr/node';
7+
import express from 'express';
8+
import { dirname, resolve } from 'node:path';
9+
import { fileURLToPath } from 'node:url';
10+
11+
const serverDistFolder = dirname(fileURLToPath(import.meta.url));
12+
const browserDistFolder = resolve(serverDistFolder, '../browser');
13+
14+
const app = express();
15+
const angularApp = new AngularNodeAppEngine();
16+
17+
/**
18+
* Example Express Rest API endpoints can be defined here.
19+
* Uncomment and define endpoints as necessary.
20+
*
21+
* Example:
22+
* ```ts
23+
* app.get('/api/**', (req, res) => {
24+
* // Handle API request
25+
* });
26+
* ```
27+
*/
28+
29+
/**
30+
* Serve static files from /browser
31+
*/
32+
app.use(
33+
express.static(browserDistFolder, {
34+
maxAge: '1y',
35+
index: false,
36+
redirect: false,
37+
}),
38+
);
39+
40+
/**
41+
* Handle all other requests by rendering the Angular application.
42+
*/
43+
app.use('/**', (req, res, next) => {
44+
angularApp
45+
.handle(req)
46+
.then((response) =>
47+
response ? writeResponseToNodeResponse(response, res) : next(),
48+
)
49+
.catch(next);
50+
});
51+
52+
/**
53+
* Start the server if this module is the main entry point.
54+
* The server listens on the port defined by the `PORT` environment variable, or defaults to 4000.
55+
*/
56+
if (isMainModule(import.meta.url)) {
57+
const port = process.env['PORT'] || 4000;
58+
app.listen(port, () => {
59+
console.log(`Node Express server listening on http://localhost:${port}`);
60+
});
61+
}
62+
63+
/**
64+
* The request handler used by the Angular CLI (dev-server and during build).
65+
*/
66+
export const reqHandler = createNodeRequestHandler(app);
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { APP_BASE_HREF } from '@angular/common';
2+
import { CommonEngine, isMainModule } from '@angular/ssr/node';
3+
import express from 'express';
4+
import { dirname, join, resolve } from 'node:path';
5+
import { fileURLToPath } from 'node:url';
6+
import bootstrap from './main.server';
7+
8+
const serverDistFolder = dirname(fileURLToPath(import.meta.url));
9+
const browserDistFolder = resolve(serverDistFolder, '../browser');
10+
const indexHtml = join(serverDistFolder, 'index.server.html');
11+
12+
const app = express();
13+
const commonEngine = new CommonEngine();
14+
15+
/**
16+
* Example Express Rest API endpoints can be defined here.
17+
* Uncomment and define endpoints as necessary.
18+
*
19+
* Example:
20+
* ```ts
21+
* app.get('/api/**', (req, res) => {
22+
* // Handle API request
23+
* });
24+
* ```
25+
*/
26+
27+
/**
28+
* Serve static files from /browser
29+
*/
30+
app.get(
31+
'**',
32+
express.static(browserDistFolder, {
33+
maxAge: '1y',
34+
index: 'index.html'
35+
}),
36+
);
37+
38+
/**
39+
* Handle all other requests by rendering the Angular application.
40+
*/
41+
app.get('**', (req, res, next) => {
42+
const { protocol, originalUrl, baseUrl, headers } = req;
43+
44+
commonEngine
45+
.render({
46+
bootstrap,
47+
documentFilePath: indexHtml,
48+
url: `${protocol}://${headers.host}${originalUrl}`,
49+
publicPath: browserDistFolder,
50+
providers: [{ provide: APP_BASE_HREF, useValue: baseUrl }],
51+
})
52+
.then((html) => res.send(html))
53+
.catch((err) => next(err));
54+
});
55+
56+
/**
57+
* Start the server if this module is the main entry point.
58+
* The server listens on the port defined by the `PORT` environment variable, or defaults to 4000.
59+
*/
60+
if (isMainModule(import.meta.url)) {
61+
const port = process.env['PORT'] || 4000;
62+
app.listen(port, () => {
63+
console.log(`Node Express server listening on http://localhost:${port}`);
64+
});
65+
}

0 commit comments

Comments
 (0)