Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Angular Express Server with Redis Caching
import 'zone.js/dist/zone-node';
import { APP_BASE_HREF } from '@angular/common';
import { ngExpressEngine } from '@nguniversal/express-engine';
import * as express from 'express';
import { existsSync } from 'fs';
import { join } from 'path';
import * as redis from 'redis';
import { AppServerModule } from './src/main.server';
// The Express app is exported so that it can be used by serverless Functions.
export function app(): express.Application {
const server = express();
const distFolder = join(process.cwd(), 'dist/browser');
const indexHtml = existsSync(join(distFolder, 'index.original.html'))
? 'index.original.html'
: 'index';
// Redis cache client
const redisClient = redis.createClient();
// Creates a cache key using the request URL
const cacheKey: (req: express.Request) => string = (req) =>
`ssr_${req.originalUrl}`;
// Universal express-engine
server.engine(
'html',
ngExpressEngine({
bootstrap: AppServerModule,
})
);
server.set('view engine', 'html');
server.set('views', distFolder);
// Middleware to send a cached response if one exists
const cachedResponse: express.RequestHandler = (req, res, next) =>
redisClient.get(cacheKey(req), (error: Error, reply: string) => {
if (reply?.length) {
// Cache exists. Send the response.
res.send(reply);
} else {
// Use the Universal engine to render a response.
next();
}
});
// Middleware to render a response using the Universal engine
const universalRenderer: express.RequestHandler = (req, res) => {
res.render(
indexHtml,
{
req,
providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }],
},
(error: Error, html: string) => {
if (error) {
return req.next(error);
}
if (res.statusCode === 200) {
// Cache the rendered HTML
redisClient.set(cacheKey(req), html);
}
res.send(html);
}
);
};
// Serve static files from dist/browser
server.get(
'*.*',
express.static(distFolder, {
maxAge: '1y',
})
);
// All regular routes use the Universal engine
server.get('*', cachedResponse, universalRenderer);
return server;
}
function run() {
const port = process.env.PORT || 4000;
// Start up the Node server
const server = app();
server.listen(port, () => {
console.log(`Node Express server listening on http://localhost:${port}`);
});
}
// Webpack will replace 'require' with '__webpack_require__'
// '__non_webpack_require__' is a proxy to Node 'require'
// The below code is to ensure that the server is run only when not requiring the bundle.
declare const __non_webpack_require__: NodeRequire;
const mainModule = __non_webpack_require__.main;
const moduleFilename = mainModule && mainModule.filename || '';
if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
run();
}
export * from './src/main.server';
@mkoert

This comment has been minimized.

Copy link

@mkoert mkoert commented Dec 16, 2020

How are you handling if redis cant be connected to or there is some other issue with redis?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment