diff --git a/examples/ssr-caching/README.md b/examples/ssr-caching/README.md index b04b35356032f..3f421222bbfde 100644 --- a/examples/ssr-caching/README.md +++ b/examples/ssr-caching/README.md @@ -1,12 +1,10 @@ # Server-Side Rendering Caching Headers -This example uses [`stale-while-revalidate`](https://web.dev/stale-while-revalidate/) [cache-control headers](https://developer.mozilla.org/docs/Web/HTTP/Headers/Cache-Control) in combination with `getServerSideProps` for server-rendering. +By default, Next.js will cache as much as possible to improve performance and reduce cost. This means routes are statically rendered and data requests are cached unless you opt out. -`pages/index.tsx` 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. +This example uses the [`revalidate`](https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#revalidate) route segment config option to override the route segment defaults. -`pages/index.tsx` 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. +Calling the Index Page (`/`) within the specified timeframe (e.g., 10 seconds) will return the cached Page ([Full Route Cache](https://nextjs.org/docs/app/building-your-application/caching#full-route-cache) in this example). ## Deploy your own diff --git a/examples/ssr-caching/app/layout.tsx b/examples/ssr-caching/app/layout.tsx new file mode 100644 index 0000000000000..112756e6bfcdc --- /dev/null +++ b/examples/ssr-caching/app/layout.tsx @@ -0,0 +1,18 @@ +import type { Metadata } from "next"; + +export const metadata: Metadata = { + title: "Create Next App", + description: "Generated by create next app", +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + {children} + + ); +} diff --git a/examples/ssr-caching/app/page.tsx b/examples/ssr-caching/app/page.tsx new file mode 100644 index 0000000000000..e06752526ca64 --- /dev/null +++ b/examples/ssr-caching/app/page.tsx @@ -0,0 +1,16 @@ +export const dynamic = "force-dynamic"; + +async function getData() { + return new Date().toISOString(); +} + +export default async function Page() { + const time = await getData(); + + return ( +
+

SSR Caching with Next.js

+ +
+ ); +} diff --git a/examples/ssr-caching/next-env.d.ts b/examples/ssr-caching/next-env.d.ts index a4a7b3f5cfa2f..40c3d68096c27 100644 --- a/examples/ssr-caching/next-env.d.ts +++ b/examples/ssr-caching/next-env.d.ts @@ -2,4 +2,4 @@ /// // NOTE: This file should not be edited -// see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information. +// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information. diff --git a/examples/ssr-caching/next.config.mjs b/examples/ssr-caching/next.config.mjs new file mode 100644 index 0000000000000..f699d448bc8f4 --- /dev/null +++ b/examples/ssr-caching/next.config.mjs @@ -0,0 +1,22 @@ +// @ts-check + +/** + * @type {import('next').NextConfig} + */ +const nextConfig = { + async headers() { + return [ + { + source: "/", + headers: [ + { + key: "Cache-Control", + value: "public, s-maxage=10, stale-while-revalidate=59", + }, + ], + }, + ]; + }, +}; + +export default nextConfig; diff --git a/examples/ssr-caching/package.json b/examples/ssr-caching/package.json index be18b903df87a..3c4766aa610da 100644 --- a/examples/ssr-caching/package.json +++ b/examples/ssr-caching/package.json @@ -1,19 +1,19 @@ { "private": true, "scripts": { - "dev": "next", + "dev": "next dev", "build": "next build", "start": "next start" }, "dependencies": { "next": "latest", - "react": "^18.2.0", - "react-dom": "^18.2.0" + "react": "^18.3.1", + "react-dom": "^18.3.1" }, "devDependencies": { - "@types/node": "^18.11.5", - "@types/react": "^18.0.23", - "@types/react-dom": "^18.0.7", - "typescript": "^4.8.4" + "@types/node": "^22.6.1", + "@types/react": "^18.3.9", + "@types/react-dom": "^18.3.0", + "typescript": "^5.6.2" } } diff --git a/examples/ssr-caching/pages/index.tsx b/examples/ssr-caching/pages/index.tsx deleted file mode 100644 index 5a732d9887460..0000000000000 --- a/examples/ssr-caching/pages/index.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { GetServerSideProps, InferGetServerSidePropsType } from "next"; - -export default function Index({ - time, -}: InferGetServerSidePropsType) { - return ( -
-

SSR Caching with Next.js

- -
- ); -} - -export const getServerSideProps: GetServerSideProps<{ time: string }> = async ({ - 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/tsconfig.json b/examples/ssr-caching/tsconfig.json index 99710e857874f..bcbb3c230fb79 100644 --- a/examples/ssr-caching/tsconfig.json +++ b/examples/ssr-caching/tsconfig.json @@ -1,20 +1,33 @@ { "compilerOptions": { - "target": "es5", + "target": "ES2017", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "strict": true, - "forceConsistentCasingInFileNames": true, "noEmit": true, "esModuleInterop": true, "module": "esnext", - "moduleResolution": "node", + "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, "jsx": "preserve", - "incremental": true + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./*"] + } }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + "next.config.mjs" + ], "exclude": ["node_modules"] }