Skip to content

Commit

Permalink
Merge branch 'canary' into use-bun
Browse files Browse the repository at this point in the history
  • Loading branch information
leerob authored Aug 2, 2023
2 parents 3ecdbe1 + 61baae1 commit 444c558
Show file tree
Hide file tree
Showing 52 changed files with 2,141 additions and 1,844 deletions.
27 changes: 26 additions & 1 deletion .github/workflows/build_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,15 @@ jobs:
afterBuild: turbo run rust-check
secrets: inherit

test-experimental-turbopack-dev:
name: test experimental turbopack dev
needs: ['build-native', 'build-next']
uses: ./.github/workflows/build_reusable.yml
with:
skipForDocsOnly: 'yes'
afterBuild: RUST_BACKTRACE=0 NEXT_EXTERNAL_TESTS_FILTERS="$(pwd)/test/turbopack-tests-manifest.js" EXPERIMENTAL_TURBOPACK=1 NEXT_E2E_TEST_TIMEOUT=240000 NEXT_TEST_MODE=dev node run-tests.js --test-pattern '^(test\/development)/.*\.test\.(js|jsx|ts|tsx)$' --timings -c ${TEST_CONCURRENCY}
secrets: inherit

test-turbopack-dev:
name: test turbopack dev
needs: ['build-native', 'build-next']
Expand All @@ -134,6 +143,21 @@ jobs:
afterBuild: RUST_BACKTRACE=0 NEXT_EXTERNAL_TESTS_FILTERS="$(pwd)/packages/next-swc/crates/next-dev-tests/tests-manifest.js" TURBOPACK=1 __INTERNAL_CUSTOM_TURBOPACK_BINDINGS="$(pwd)/packages/next-swc/native/next-swc.linux-x64-gnu.node" NEXT_E2E_TEST_TIMEOUT=240000 NEXT_TEST_MODE=dev node run-tests.js --test-pattern '^(test\/development)/.*\.test\.(js|jsx|ts|tsx)$' --timings -c ${TEST_CONCURRENCY}
secrets: inherit

test-experimental-turbopack-integration:
name: test experimental turbopack integration
needs: ['build-native', 'build-next']
strategy:
fail-fast: false
matrix:
group: [1]

uses: ./.github/workflows/build_reusable.yml
with:
nodeVersion: 16
skipForDocsOnly: 'yes'
afterBuild: RUST_BACKTRACE=0 NEXT_EXTERNAL_TESTS_FILTERS="$(pwd)/test/turbopack-tests-manifest.js" EXPERIMENTAL_TURBOPACK=1 node run-tests.js --timings -g ${{ matrix.group }}/1 -c ${TEST_CONCURRENCY} --type integration
secrets: inherit

test-turbopack-integration:
name: test turbopack integration
needs: ['build-native', 'build-next']
Expand All @@ -148,7 +172,6 @@ jobs:
skipForDocsOnly: 'yes'
afterBuild: RUST_BACKTRACE=0 NEXT_EXTERNAL_TESTS_FILTERS="$(pwd)/packages/next-swc/crates/next-dev-tests/tests-manifest.js" TURBOPACK=1 __INTERNAL_CUSTOM_TURBOPACK_BINDINGS="$(pwd)/packages/next-swc/native/next-swc.linux-x64-gnu.node" node run-tests.js --timings -g ${{ matrix.group }}/5 -c ${TEST_CONCURRENCY} --type integration
secrets: inherit

test-next-swc-wasm:
name: test next-swc wasm
needs: ['build-native', 'build-next']
Expand Down Expand Up @@ -244,7 +267,9 @@ jobs:
'rust-check',
'test-next-swc-wasm',
'test-turbopack-dev',
'test-experimental-turbopack-dev',
'test-turbopack-integration',
'test-experimental-turbopack-integration',
]

if: always()
Expand Down
78 changes: 47 additions & 31 deletions docs/02-app/01-building-your-application/04-caching/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,17 @@ Here's a high-level overview of the different caching mechanisms and their purpo
| [Full Route Cache](#full-route-cache) | HTML and RSC payload | Server | Reduce rendering cost and improve performance | Persistent (can be revalidated) |
| [Router Cache](#router-cache) | RSC Payload | Client | Reduce server requests on navigation | User session or time-based |

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. The diagram below shows the default caching behavior; at build time and when a route is first visited.
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. The diagram below shows the default caching behavior: when a route is statically rendered at build time and when a static route is first visited.

<Image
alt="Diagram showing the default caching behavior in Next.js for the four mechanisms, with HIT, MISS and SET at build time and when a route is first visited."
srcLight="/docs/light/caching-overview.png"
srcDark="/docs/dark/caching-overview.png"
width="1600"
height="1117"
height="1179"
/>

This behavior changes depending on whether the route is statically or dynamically rendered, data is cached or uncached, and whether it's the initial visit or a subsequent navigation. Depending on your use case, you can configure the caching behavior for individual routes and data requests.
Caching behavior changes depending on whether the route is statically or dynamically rendered, data is cached or uncached, and whether a request is part of an initial visit or a subsequent navigation. Depending on your use case, you can configure the caching behavior for individual routes and data requests.

## Request Memoization

Expand All @@ -47,7 +47,8 @@ For example, if you need to use the same data across a route (e.g. in a Layout,

```tsx filename="app/example.tsx" switcher
async function getItem() {
// The `fetch` function is automatically memoized and the result is cached
// The `fetch` function is automatically memoized and the result
// is cached
const res = await fetch('https://.../item/1')
return res.json()
}
Expand All @@ -61,7 +62,8 @@ const item = await getItem() // cache HIT

```jsx filename="app/example.js" switcher
async function getItem() {
// The `fetch` function is automatically memoized and the result is cached
// The `fetch` function is automatically memoized and the result
// is cached
const res = await fetch('https://.../item/1')
return res.json()
}
Expand All @@ -73,6 +75,8 @@ const item = await getItem() // cache MISS
const item = await getItem() // cache HIT
```

**How Request Memoization Works**

<Image
alt="Diagram showing how fetch memoization works during React rendering."
srcLight="/docs/light/request-memoization.png"
Expand All @@ -81,7 +85,10 @@ const item = await getItem() // cache HIT
height="742"
/>

The first time the request is called, it'll be a cache `MISS`, the function will be executed, and the data will be fetched from the Next.js [Data Cache](#data-cache) or your data store and the result will be stored in memory. Subsequent function calls will be a cache `HIT`, and the data will be returned from memory without executing the function.
- While rendering a route, the first time a particular request is called, it's result will not be in memory and it'll be a cache `MISS`.
- Therefore, the function will be executed, and the data will be fetched from the external source, and the result will be stored in memory.
- Subsequent function calls of the request in the same render pass will be a cache `HIT`, and the data will be returned from memory without executing the function.
- Once the route has been rendered and the rendering pass is complete, memory is "reset" and all request memoization entries are cleared.

> **Good to know**:
>
Expand All @@ -90,7 +97,7 @@ The first time the request is called, it'll be a cache `MISS`, the function will
> - Memoization only applies to the React Component tree, this means:
> - It applies to `fetch` requests in `generateMetadata`, `generateStaticParams`, Layouts, Pages, and other Server Components.
> - It doesn't apply to `fetch` requests in Route Handlers as they are not a part of the React component tree.
> - For cases where `fetch` is not suitable (e.g. database clients, CMS clients, or GraphQL), you can use the [React `cache` function](#react-cache-function) to memoize functions.
> - For cases where `fetch` is not suitable (e.g. some database clients, CMS clients, or GraphQL clients), you can use the [React `cache` function](#react-cache-function) to memoize functions.
### Duration

Expand All @@ -111,23 +118,27 @@ fetch(url, { signal })

## Data Cache

Next.js has a built-in Data Cache that **persists** the result of data fetches across incoming **server requests** and **deployments**. This is possible because Next.js extends the native `fetch` API to allow each request on the server to set its own persistent caching semantics. n the browser, the `cache` option of `fetch` indicates how a request will interact with the browser's HTTP cache, with Next.js, the `cache` option indicates how a server-side request will interact with the servers Data Cache.
Next.js has a built-in Data Cache that **persists** the result of data fetches across incoming **server requests** and **deployments**. This is possible because Next.js extends the native `fetch` API to allow each request on the server to set its own persistent caching semantics.

> **Good to know**: In the browser, the `cache` option of `fetch` indicates how a request will interact with the browser's HTTP cache, in Next.js, the `cache` option indicates how a server-side request will interact with the servers Data Cache.
By default, data requests that use `fetch` are **cached**. You can use the [`cache`](#fetch-optionscache) and [`next.revalidate`](#fetch-optionsnextrevalidate) options of `fetch` to configure the caching behavior.

**How the Data Cache Works**

<Image
alt="Diagram showing how cached and uncached fetch requests interact with the Data Cache. Cached requests are stored in the Data Cache, and memoized, uncached requests are fetched from the data source, not stored in the Data Cache, and memoized."
srcLight="/docs/light/data-cache.png"
srcDark="/docs/dark/data-cache.png"
width="1600"
height="679"
height="661"
/>

The first time a `fetch` request is called during rendering, Next.js checks the Data Cache for a cached response. If a cached response is found, it's returned immediately and [memoized](#request-memoization). If not, the request is made to the data source, the result is stored in the Data Cache, and memoized.

For uncached data (e.g. `{ cache: 'no-store' }`), the result is always fetched from the data source, and memoized.

Whether the data is cached or uncached, the requests are always memoized to avoid making duplicate requests for the same data during a React render pass.
- The first time a `fetch` request is called during rendering, Next.js checks the Data Cache for a cached response.
- If a cached response is found, it's returned immediately and [memoized](#request-memoization).
- If a cached response is not found, the request is made to the data source, the result is stored in the Data Cache, and memoized.
- For uncached data (e.g. `{ cache: 'no-store' }`), the result is always fetched from the data source, and memoized.
- Whether the data is cached or uncached, the requests are always memoized to avoid making duplicate requests for the same data during a React render pass.

> **Differences between the Data Cache and Request Memoization**
>
Expand Down Expand Up @@ -157,40 +168,43 @@ fetch('https://...', { next: { revalidate: 3600 } })

Alternatively, you can use [Route Segment Config options](#segment-config-options) to configure all `fetch` requests in a segment or for cases where you're not able to use `fetch`.

**How Time-based Revalidation Works**:
**How Time-based Revalidation Works**

<Image
alt="Diagram showing how time-based revalidation works, after the revalidation period, stale data is returned for the first request, then data is revalidated."
srcLight="/docs/light/time-based-revalidation.png"
srcDark="/docs/dark/time-based-revalidation.png"
width="1600"
height="1192"
height="1252"
/>

1. The first time a fetch request with `revalidate` is called, the data will be fetched from the external data source and stored in the Data Cache.
2. Any requests that are called within the specified timeframe (e.g. 60-seconds) will return the cached data.
3. After the timeframe, the next request will still return the cached (now stale) data.
- Next.js will trigger a revalidation of the data in the background.
- Once the data is fetched successfully, Next.js will update the Data Cache with the fresh data.
- If the background revalidation fails, the previous data will be kept unaltered.
- The first time a fetch request with `revalidate` is called, the data will be fetched from the external data source and stored in the Data Cache.
- Any requests that are called within the specified timeframe (e.g. 60-seconds) will return the cached data.
- After the timeframe, the next request will still return the cached (now stale) data.
- Next.js will trigger a revalidation of the data in the background.
- Once the data is fetched successfully, Next.js will update the Data Cache with the fresh data.
- If the background revalidation fails, the previous data will be kept unaltered.

This is similar to [**stale-while-revalidate**](https://web.dev/stale-while-revalidate/) behavior.

#### On-demand Revalidation

Data can be revalidated on-demand by path ([`revalidatePath`](#revalidatepath)) or by cache tag ([`revalidateTag`](#fetch-optionsnexttag-and-revalidatetag)).

**How On-Demand Revalidation Works**:
**How On-Demand Revalidation Works**

<Image
alt="Diagram showing how on-demand revalidation works, the Data Cache is updated with fresh data after a revalidation request."
srcLight="/docs/light/on-demand-revalidation.png"
srcDark="/docs/dark/on-demand-revalidation.png"
width="1600"
height="956"
height="1082"
/>

On-demand revalidation purges entries from the Data Cache. When the request is executed again, it'll be a cache `MISS`, and the Data Cache will be populated with fresh data. This is different from time-based revalidation, which keeps the stale data in the cache until the fresh data is fetched.
- The first time a `fetch` request is called, the data will be fetched from the external data source and stored in the Data Cache.
- When an on-demand revalidation is triggered, the appropriate cache entries will be purged from the cache.
- This is different from time-based revalidation, which keeps the stale data in the cache until the fresh data is fetched.
- The next time a request is made, it will be a cache `MISS` again, and the data will be fetched from the external data source and stored in the Data Cache.

### Opting out

Expand Down Expand Up @@ -224,7 +238,7 @@ To understand how the Full Route Cache works, it's helpful to look at how React

### 1. React Rendering on the Server

On the server, Next.js uses React's APIs to orchestrate rendering. The rendering work split into chunks, by individual routes segments and Suspense boundaries.
On the server, Next.js uses React's APIs to orchestrate rendering. The rendering work is split into chunks: by individual routes segments and Suspense boundaries.

Each chunk is rendered in two steps:

Expand All @@ -250,7 +264,7 @@ This means we don't have to wait for everything to render before caching the wor
srcLight="/docs/light/full-route-cache.png"
srcDark="/docs/dark/full-route-cache.png"
width="1600"
height="869"
height="888"
/>

The default behavior of Next.js is to cache the rendered result (React Server Component Payload and HTML) of a route on the server. This applies to statically rendered routes at build time, or during revalidation.
Expand Down Expand Up @@ -284,7 +298,7 @@ This diagram shows the difference between statically and dynamically rendered ro
srcLight="/docs/light/static-and-dynamic-routes.png"
srcDark="/docs/dark/static-and-dynamic-routes.png"
width="1600"
height="770"
height="1314"
/>

Learn more about [static and dynamic rendering](/docs/app/building-your-application/rendering/static-and-dynamic).
Expand All @@ -305,7 +319,7 @@ There are two ways you can invalidate the Full Route Cache:
You can opt out of the Full Route Cache, or in other words, dynamically render components for every incoming request, by:

- **Using a [Dynamic Function](#dynamic-functions)**: This will opt the route out from the Full Route Cache and dynamically render it at request time. The Data Cache can still be used.
- **Using the route segment config options `export const dynamic = 'force-dynamic'` or `export const revalidate = 0`**: This will skip the Full Route Cache and the Data Cache. Meaning components will be rendered and data fetched on every incoming request to the server. The Router Cache will still apply as it's a client-side cache.
- **Using the `dynamic = 'force-dynamic'` or `revalidate = 0` route segment config options**: This will skip the Full Route Cache and the Data Cache. Meaning components will be rendered and data fetched on every incoming request to the server. The Router Cache will still apply as it's a client-side cache.
- **Opting out of the [Data Cache](#data-cache)**: If a route has a `fetch` request that is not cached, this will opt the route out of the Full Route Cache. The data for the specific `fetch` request will be fetched for every incoming request. Other `fetch` requests that do not opt out of caching will still be cached in the Data Cache. This allows for a hybrid of cached and uncached data.

## Router Cache
Expand All @@ -317,12 +331,14 @@ You can opt out of the Full Route Cache, or in other words, dynamically render c
Next.js has an in-memory client-side cache that stores the React Server Component Payload, split by individual route segments, for the duration of a user session. This is called the Router Cache.

**How the Router Cache Works**

<Image
alt="How the Router cache works for static and dynamic routes, showing MISS and HIT for initial and subsequent navigations."
srcLight="/docs/light/router-cache.png"
srcDark="/docs/dark/router-cache.png"
width="1600"
height="1332"
height="1375"
/>

As users navigates between routes, Next.js caches visited route segments and [prefetches](/docs/app/building-your-application/routing/linking-and-navigating#1-prefetching) the routes the user is likely to navigate to (based on `<Link>` components in their viewport).
Expand Down Expand Up @@ -540,7 +556,7 @@ See the [`generateStaticParams` API reference](/docs/app/api-reference/functions

The React `cache` function allows you to memoize the return value of a function, allowing you to call the same function multiple times while only executing it once.

Since `fetch` requests are automatically memoized, you do not need to wrap it in React `cache`. However, you can use `cache` to manually memoize data requests for use cases when the `fetch` API is not suitable. For example, database clients, CMS clients, or GraphQL.
Since `fetch` requests are automatically memoized, you do not need to wrap it in React `cache`. However, you can use `cache` to manually memoize data requests for use cases when the `fetch` API is not suitable. For example, some database clients, CMS clients, or GraphQL clients.

```tsx filename="utils/get-item.ts" switcher
import { cache } from 'react'
Expand Down
Loading

0 comments on commit 444c558

Please sign in to comment.