-
-
Save jukbot/cf2585dc206fe3005589cc9d6682ac08 to your computer and use it in GitHub Desktop.
Next.js SSR Cache using LRU Cache
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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