Skip to content

Instantly share code, notes, and snippets.

@leanazulyoro
Last active February 16, 2024 20:49
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save leanazulyoro/23c6581fb4379ec311e3bc8538715687 to your computer and use it in GitHub Desktop.
Save leanazulyoro/23c6581fb4379ec311e3bc8538715687 to your computer and use it in GitHub Desktop.
Next.js SSR Cache using LRU Cache
const express = require('express')
const next = require('next')
const Cache = require('lru-cache');
const compression = require('compression')
const port = parseInt(process.env.PORT, 10) || 3000
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
const ssrCache = new Cache({
max: 20,
maxAge: 1000 * 60 * 60, // 1hour
});
const renderAndCache = (app) => async function(req, res, pagePath, queryParams) {
const { host } = req.headers;
// Define the cache key as you wish here:
const key = host + req.url;
// if page is in cache, server from cache
if (ssrCache.has(key)) {
console.info('SSR Response from cache for ', key);
res.setHeader('x-cache', 'HIT');
res.end(ssrCache.get(key));
return;
}
try {
/**
* Override res.end method before sending it to app.renderToHTML
* to be able to get the payload (renderedHTML) and save it to cache.
*/
const _resEnd = res.end.bind(res);
res.end = function (payload) {
// Add here custom logic for when you do not want to cache the page, for example when
// the status is not 200
if (res.statusCode !== 200) {
console.warn('Oops, something is wrong, will skip the cache');
} else {
ssrCache.set(key, payload);
}
return _resEnd(payload);
};
// if not in cache, render the page into HTML
res.setHeader('x-cache', 'MISS');
console.info('SSR rendering without cache and try caching for ', key);
await app.renderToHTML(req, res, pagePath, queryParams);
} catch (err) {
app.renderError(err, req, res, pagePath, queryParams);
}
};
app.prepare().then(() => {
const server = express()
server.get('/', (req, res) => {
// since we don't use next's requestHandler, we lose compression, so we manually add it
server.use(compression());
renderAndCache(app)(req, res, '/');
});
server.get('*', (req, res) => handle(req, res))
server.listen(port, err => {
if (err) throw err
console.log(`> Ready on http://localhost:${port}`)
})
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment