Files
print-calculator/frontend/src/server.ts
Joe Küng b317196217
All checks were successful
Build and Deploy / test-backend (push) Successful in 40s
Build and Deploy / test-frontend (push) Successful in 1m5s
Build and Deploy / build-and-push (push) Successful in 1m19s
Build and Deploy / deploy (push) Successful in 22s
fix(front-end): redirect
2026-03-22 22:41:12 +01:00

127 lines
3.4 KiB
TypeScript

import { APP_BASE_HREF } from '@angular/common';
import { CommonEngine, isMainModule } from '@angular/ssr/node';
import express from 'express';
import { dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import bootstrap from './main.server';
import { resolveRequestOrigin } from './core/request-origin';
import {
parseAcceptLanguage,
resolveInitialLanguage,
} from './app/core/i18n/language-resolution';
import { resolvePublicRedirectTarget } from './server-routing';
const serverDistFolder = dirname(fileURLToPath(import.meta.url));
const browserDistFolder = resolve(serverDistFolder, '../browser');
const indexHtml = join(serverDistFolder, 'index.server.html');
const app = express();
const commonEngine = new CommonEngine();
/**
* Example Express Rest API endpoints can be defined here.
* Uncomment and define endpoints as necessary.
*
* Example:
* ```ts
* app.get('/api/**', (req, res) => {
* // Handle API request
* });
* ```
*/
/**
* Serve static files from /browser
*/
app.get(
'**',
express.static(browserDistFolder, {
maxAge: '1y',
index: false,
}),
);
app.get('/', (req, res) => {
const userAgent = req.get('user-agent');
const preferredLanguages = parseAcceptLanguage(req.get('accept-language'));
const lang = resolveInitialLanguage({
preferredLanguages,
});
const stableRedirect = shouldUseStableRootRedirect(
userAgent,
preferredLanguages,
);
res.setHeader('Vary', 'Accept-Language, User-Agent');
res.setHeader('Cache-Control', 'private, no-store');
res.redirect(
stableRedirect ? 308 : 302,
`/${stableRedirect ? 'it' : lang}${querySuffix(req.originalUrl)}`,
);
});
app.get('**', (req, res, next) => {
const targetPath = resolvePublicRedirectTarget(req.path);
if (!targetPath) {
next();
return;
}
res.redirect(308, `${targetPath}${querySuffix(req.originalUrl)}`);
});
/**
* Handle all other requests by rendering the Angular application.
*/
app.get('**', (req, res, next) => {
const { originalUrl, baseUrl } = req;
const origin = resolveRequestOrigin(req);
commonEngine
.render({
bootstrap,
documentFilePath: indexHtml,
url: `${origin ?? 'http://localhost:4000'}${originalUrl}`,
publicPath: browserDistFolder,
providers: [{ provide: APP_BASE_HREF, useValue: baseUrl }],
})
.then((html) => res.send(html))
.catch((err) => next(err));
});
/**
* Start the server if this module is the main entry point.
* The server listens on the port defined by the `PORT` environment variable, or defaults to 4000.
*/
if (isMainModule(import.meta.url)) {
const port = process.env['PORT'] || 4000;
app.listen(port, () => {
console.log(`Node Express server listening on http://localhost:${port}`);
});
}
export default app;
function querySuffix(url: string): string {
const queryIndex = String(url ?? '').indexOf('?');
return queryIndex >= 0 ? String(url).slice(queryIndex) : '';
}
function shouldUseStableRootRedirect(
userAgent: string | undefined,
preferredLanguages: readonly string[],
): boolean {
return preferredLanguages.length === 0 || isLikelyCrawler(userAgent);
}
function isLikelyCrawler(userAgent: string | undefined): boolean {
const normalized = String(userAgent ?? '').toLowerCase();
if (!normalized) {
return false;
}
return /(bot|crawler|spider|slurp|bingpreview|google-read-aloud)/.test(
normalized,
);
}