diff --git a/examples/ssr-caching/README.md b/examples/ssr-caching/README.md index 8c1d3691a0b40..e8d4360399392 100644 --- a/examples/ssr-caching/README.md +++ b/examples/ssr-caching/README.md @@ -1,9 +1,24 @@ -# Example app where it caches SSR'ed pages in the memory +# Server-Side Rendering Caching Headers -React Server Side rendering is very costly and takes a lot of server's CPU power for that. One of the best solutions for this problem is cache already rendered pages. -That's what this example demonstrate. +This example uses [`stale-while-revalidate`](https://web.dev/stale-while-revalidate/) [cache-control headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control) in combination with `getServerSideProps` for server-rendering. -This app uses Next's [custom server and routing](https://nextjs.org/docs/advanced-features/custom-server) mode. It also uses [express](https://expressjs.com/) to handle routing and page serving. +`pages/index.js` uses `getServerSideProps` to forward the request header to the React component, as well as setting a response header. This `cache-control` header uses `stale-while-revalidate` to cache the server response. + +`pages/index.js` is considered fresh for ten seconds (`s-maxage=10`). If a request is repeated within the next 10 seconds, the previously cached value will still be fresh. If the request is repeated before 59 seconds, the cached value will be stale but still render (`stale-while-revalidate=59`). + +In the background, a revalidation request will be made to populate the cache with a fresh value. If you refresh the page, you will see the new value shown. + +## Preview + +Preview the example live on [StackBlitz](http://stackblitz.com/): + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/vercel/next.js/tree/canary/examples/ssr-caching) + +## Deploy your own + +Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example): + +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https://github.com/vercel/next.js/tree/canary/examples/ssr-caching&project-name=ssr-caching&repository-name=ssr-caching) ## How to use diff --git a/examples/ssr-caching/package.json b/examples/ssr-caching/package.json index 078aa1a4c7052..2ea0416f1e50c 100644 --- a/examples/ssr-caching/package.json +++ b/examples/ssr-caching/package.json @@ -2,14 +2,11 @@ "name": "ssr-caching", "version": "1.0.0", "scripts": { - "dev": "node server.js", + "dev": "next", "build": "next build", - "start": "cross-env NODE_ENV=production node server.js" + "start": "next start" }, "dependencies": { - "cacheable-response": "^2.1.6", - "cross-env": "^7.0.2", - "express": "^4.17.1", "next": "latest", "react": "^17.0.2", "react-dom": "^17.0.2" diff --git a/examples/ssr-caching/pages/blog/[id].js b/examples/ssr-caching/pages/blog/[id].js deleted file mode 100644 index 77927c6e8f3f3..0000000000000 --- a/examples/ssr-caching/pages/blog/[id].js +++ /dev/null @@ -1,26 +0,0 @@ -export default function Post(props) { - return ( -
-

My {props.id} blog post

-

- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod - tempor incididunt ut labore et dolore magna aliqua. -

-
- ) -} - -export async function getStaticProps({ params: { id } }) { - return { props: { id } } -} - -export async function getStaticPaths() { - return { - paths: [ - { params: { id: 'first' } }, - { params: { id: 'second' } }, - { params: { id: 'last' } }, - ], - fallback: true, - } -} diff --git a/examples/ssr-caching/pages/index.js b/examples/ssr-caching/pages/index.js index abcc88ed33d93..46c8ff60f41ec 100644 --- a/examples/ssr-caching/pages/index.js +++ b/examples/ssr-caching/pages/index.js @@ -1,23 +1,21 @@ -import Link from 'next/link' - -export default function Home() { +export default function Index({ time }) { return ( - +
+

SSR Caching with Next.js

+ +
) } + +export async function getServerSideProps({ req, res }) { + res.setHeader( + 'Cache-Control', + 'public, s-maxage=10, stale-while-revalidate=59' + ) + + return { + props: { + time: new Date().toISOString(), + }, + } +} diff --git a/examples/ssr-caching/server.js b/examples/ssr-caching/server.js deleted file mode 100644 index 8d0a0927ab8be..0000000000000 --- a/examples/ssr-caching/server.js +++ /dev/null @@ -1,43 +0,0 @@ -const cacheableResponse = require('cacheable-response') -const express = require('express') -const next = require('next') - -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 = cacheableResponse({ - ttl: 1000 * 60 * 60, // 1hour - get: async ({ req, res }) => { - const rawResEnd = res.end - const data = await new Promise((resolve) => { - res.end = (payload) => { - resolve(res.statusCode === 200 && payload) - } - app.render(req, res, req.path, { - ...req.query, - ...req.params, - }) - }) - res.end = rawResEnd - return { data } - }, - send: ({ data, res }) => res.send(data), -}) - -app.prepare().then(() => { - const server = express() - - server.get('/', (req, res) => ssrCache({ req, res })) - - server.get('/blog/:id', (req, res) => ssrCache({ req, res })) - - server.get('*', (req, res) => handle(req, res)) - - server.listen(port, (err) => { - if (err) throw err - console.log(`> Ready on http://localhost:${port}`) - }) -})