Skip to content

Commit

Permalink
Merge pull request #122 from SpareCores/cache-headers-middleware
Browse files Browse the repository at this point in the history
move cache headers to middleware and fix giscuss.css CORS
  • Loading branch information
daroczig authored Sep 28, 2024
2 parents 32c0f13 + fbfcb7c commit f1dc4ed
Showing 1 changed file with 72 additions and 13 deletions.
85 changes: 72 additions & 13 deletions server.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os from 'os';
import { APP_BASE_HREF } from '@angular/common';
import { CommonEngine } from '@angular/ssr';
import express from 'express';
Expand All @@ -9,11 +10,15 @@ import { REQUEST, RESPONSE } from './src/express.tokens';
// The Express app is exported so that it can be used by serverless Functions.
export function app(): express.Express {
const server = express();
const loggerData: Record<string, any> = {};

// access log
server.use((req, res, next) => {
loggerData.startTime = new Date();
loggerData.resourceUsage = process.resourceUsage();
const { protocol, originalUrl, ip, headers } = req;
const log = {
event: "request",
method: req.method,
path: originalUrl,
userAgent: headers['user-agent'],
Expand All @@ -35,30 +40,84 @@ export function app(): express.Express {
server.set('view engine', 'html');
server.set('views', browserDistFolder);

// Serve static files
server.get('*.*', express.static(browserDistFolder, {
setHeaders: (res, path) => {
const generatedJsPattern = /-[A-Z0-9]+\.(js|css|woff2)$/;
if (generatedJsPattern.test(path)) {
// generated files with hashed filenames can be cached forever
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
} else {
// default to cache for 1 hour
res.setHeader('Cache-Control', 'public, max-age=3600');
}
// return early with stats
server.get('/healthcheck', (req, res) => {
const stats = {
status: 'healthy',
host: os.hostname(),
memory: {
maxRss: loggerData.resourceUsage.maxRSS,
},
cpu: {
user: loggerData.resourceUsage.userCPUTime,
sys: loggerData.resourceUsage.systemCPUTime,
},
uptime: process.uptime().toFixed(2)
};
res.status(200).json(stats);
});

// redirect from www
server.use((req, res, next) => {
const host = req.hostname;
if (host.startsWith('www.')) {
const newHost = host.substring(4);
return res.redirect(301, `${req.protocol}://${newHost}${req.originalUrl}`);
}
}));
next();
});

// cache headers for the static files
server.use((req, res, next) => {
const generatedJsPattern = /-[A-Z0-9]+\.(js|css|woff2)$/;
if (req.path === '/assets/giscus.css') {
// CORS for hosted file referencing external resources
res.setHeader('Access-Control-Allow-Origin', 'https://giscus.app');
res.setHeader('Access-Control-Allow-Methods', 'OPTIONS,GET');
res.setHeader('Cache-Control', 'public, max-age=86400');
} else if (generatedJsPattern.test(req.path)) {
// Generated files with hashed filenames can be cached forever
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
} else {
// Default cache for 1 hour
res.setHeader('Cache-Control', 'public, max-age=3600');
}
next();
});

// Serve static files
server.get('*.*', express.static(browserDistFolder));

// Cache dynamic content for 10 mins
server.use((req, res, next) => {
res.setHeader('Cache-Control', 'public, max-age=600');
next();
});

// log time to generate dynamic content
server.use((req, res, next) => {
res.on("close", () => {
const currentResourceUsage = process.resourceUsage();
const currentTime = new Date();
const elapsedTime = (currentTime.getTime() - loggerData.startTime.getTime()) / 1e3;
const userTime = (currentResourceUsage.userCPUTime - loggerData.resourceUsage.userCPUTime) / 1e6;
const sysTime = (currentResourceUsage.systemCPUTime - loggerData.resourceUsage.systemCPUTime) / 1e6;
const log = {
event: "response",
path: req.originalUrl,
real: elapsedTime.toFixed(2),
user: userTime.toFixed(2),
sys: sysTime.toFixed(2),
wait: (elapsedTime - userTime - sysTime).toFixed(2),
}
console.log(JSON.stringify(log));
})
next()
})

// All regular routes use the Angular engine
server.get('*', (req, res, next) => {
const { protocol, originalUrl, baseUrl, headers } = req;

commonEngine
.render({
bootstrap,
Expand Down

0 comments on commit f1dc4ed

Please sign in to comment.