Skip to content

Commit

Permalink
update docs and add warnings
Browse files Browse the repository at this point in the history
  • Loading branch information
ijjk committed Sep 7, 2023
1 parent ea998cd commit 48eb99e
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 17 deletions.
2 changes: 1 addition & 1 deletion docs/02-app/02-api-reference/04-functions/fetch.mdx
Expand Up @@ -98,7 +98,7 @@ Set the cache lifetime of a resource (in seconds).
fetch(`https://...`, { next: { tags: ['collection'] } })
```

Set the cache tags of a resource. Data can then be revalidated on-demand using [`revalidateTag`](https://nextjs.org/docs/app/api-reference/functions/revalidateTag).
Set the cache tags of a resource. Data can then be revalidated on-demand using [`revalidateTag`](https://nextjs.org/docs/app/api-reference/functions/revalidateTag). The max length for a custom tag is 256 characters.

## Version History

Expand Down
33 changes: 28 additions & 5 deletions docs/02-app/02-api-reference/04-functions/revalidatePath.mdx
Expand Up @@ -8,10 +8,6 @@ description: API Reference for the revalidatePath function.
> **Good to know**:
>
> - `revalidatePath` is available in both [Node.js and Edge runtimes](/docs/app/building-your-application/rendering/edge-and-nodejs-runtimes).
> - `revalidatePath` can invalidate by:
> - URL `revalidatePath('/blog/post-1')` invalidates just this specific URL
> - page path `revalidatePath('/blog/[slug]', 'page')` invalidates the page regardless of exact URL
> - from a layout `revalidatePath('/blog/[slug]', 'layout')` invalidates any paths that include this layout
> - `revalidatePath` only invalidates the cache when the included path is next visited. This means calling `revalidatePath` with a dynamic route segment will not immediately trigger many revalidations at once. The invalidation only happens when the path is next visited.
## Parameters
Expand All @@ -20,7 +16,7 @@ description: API Reference for the revalidatePath function.
revalidatePath(path: string, type?: 'page' | 'layout'): void;
```

- `path`: A string representing the filesystem path associated with the data you want to revalidate. This is the literal route segment (e.g. `/product/123`) not the path on the filesystem `/product/[slug]/page`.
- `path`: A string representing the filesystem path associated with the data you want to revalidate. This is the literal route segment (for example, `/product/123`) not the path on the filesystem `/product/[slug]/page`. Must be less than 1024 characters.
- `type`: An optional string of either 'page' or 'layout' to change behavior of what type of path is being revalidated.

## Returns
Expand All @@ -29,6 +25,33 @@ revalidatePath(path: string, type?: 'page' | 'layout'): void;

## Examples

### Revalidating A Specific URL

```ts
import { revalidatePath } from 'next/cache'
revalidatePath('/blog/post-1')
```

When revalidating with just a path it will only revalidate the specific URL on the next visit for example, `/blog/post-1` will revalidate but `/blog/post-2` would not.

### Revalidating A Page Path

```ts
import { revalidatePath } from 'next/cache'
revalidatePath('/blog/[slug]', 'page')
```

When revalidating with a page path and the "page" argument is provided any URL that matches that specific page will be revalidated on the next visit. This will not invalidate pages beneath the specific page for example, `/blog/[slug]` won't invalidate `/blog/[slug]/[author]`.

### Revalidating A Layout Path

```ts
import { revalidatePath } from 'next/cache'
revalidatePath('/blog/[slug]', 'layout')
```

When revalidating with a page path and the "layout" argument is provided any URL that includes that layout will be revalidated. This will cause pages beneath with the same layout to revalidate on the next visit for example, in the above case `/blog/[slug]/[another]` would also revalidate on the next visit.

### Server Action

```ts filename="app/actions.ts" switcher
Expand Down
Expand Up @@ -16,7 +16,7 @@ description: API Reference for the revalidateTag function.
revalidateTag(tag: string): void;
```

- `tag`: A string representing the cache tag associated with the data you want to revalidate.
- `tag`: A string representing the cache tag associated with the data you want to revalidate. Must be less than or equal to 256 characters.

You can add tags to `fetch` as follows:

Expand Down
2 changes: 2 additions & 0 deletions packages/next/src/lib/constants.ts
Expand Up @@ -12,6 +12,8 @@ export const NEXT_CACHE_REVALIDATED_TAGS_HEADER = 'x-next-revalidated-tags'
export const NEXT_CACHE_REVALIDATE_TAG_TOKEN_HEADER =
'x-next-revalidate-tag-token'

export const NEXT_CACHE_TAG_MAX_LENGTH = 256
export const NEXT_CACHE_SOFT_TAG_MAX_LENGTH = 1024
export const NEXT_CACHE_IMPLICIT_TAG_ID = '_N_T_'

// in seconds
Expand Down
46 changes: 43 additions & 3 deletions packages/next/src/server/lib/patch-fetch.ts
@@ -1,13 +1,50 @@
import type { StaticGenerationAsyncStorage } from '../../client/components/static-generation-async-storage'
import type {
StaticGenerationAsyncStorage,
StaticGenerationStore,
} from '../../client/components/static-generation-async-storage'
import type * as ServerHooks from '../../client/components/hooks-server-context'

import { AppRenderSpan, NextNodeServerSpan } from './trace/constants'
import { getTracer, SpanKind } from './trace/tracer'
import { CACHE_ONE_YEAR, NEXT_CACHE_IMPLICIT_TAG_ID } from '../../lib/constants'
import {
CACHE_ONE_YEAR,
NEXT_CACHE_IMPLICIT_TAG_ID,
NEXT_CACHE_TAG_MAX_LENGTH,
} from '../../lib/constants'
import * as Log from '../../build/output/log'

const isEdgeRuntime = process.env.NEXT_RUNTIME === 'edge'

export function validateTags(tags: any[], description: string) {
const validTags: string[] = []
const invalidTags: Array<{
tag: any
reason: string
}> = []

for (const tag of tags) {
if (typeof tag !== 'string') {
invalidTags.push({ tag, reason: 'invalid type, must be a string' })
} else if (tag.length > NEXT_CACHE_TAG_MAX_LENGTH) {
invalidTags.push({
tag,
reason: `exceeded max length of ${NEXT_CACHE_TAG_MAX_LENGTH}`,
})
} else {
validTags.push(tag)
}
}

if (invalidTags.length > 0) {
console.warn(`Warning: invalid tags passed to ${description}: `)

for (const { tag, reason } of invalidTags) {
console.log(`tag: "${tag}" ${reason}`)
}
}
return validTags
}

const getDerivedTags = (pathname: string): string[] => {
const derivedTags: string[] = [`/layout`]

Expand Down Expand Up @@ -194,7 +231,10 @@ export function patchFetch({
// RequestInit doesn't keep extra fields e.g. next so it's
// only available if init is used separate
let curRevalidate = getNextField('revalidate')
const tags: string[] = getNextField('tags') || []
const tags: string[] = validateTags(
getNextField('tags') || [],
`fetch ${input.toString()}`
)

if (Array.isArray(tags)) {
if (!staticGenerationStore.tags) {
Expand Down
25 changes: 20 additions & 5 deletions packages/next/src/server/web/spec-extension/revalidate-path.ts
@@ -1,11 +1,26 @@
import { revalidateTag } from './revalidate-tag'
import { NEXT_CACHE_IMPLICIT_TAG_ID } from '../../../lib/constants'
import { isDynamicRoute } from '../../../shared/lib/router/utils'
import {
NEXT_CACHE_IMPLICIT_TAG_ID,
NEXT_CACHE_SOFT_TAG_MAX_LENGTH,
} from '../../../lib/constants'

export function revalidatePath(path: string, type?: 'layout' | 'page') {
path = `${NEXT_CACHE_IMPLICIT_TAG_ID}${path}`
export function revalidatePath(originalPath: string, type?: 'layout' | 'page') {
if (originalPath.length > NEXT_CACHE_SOFT_TAG_MAX_LENGTH) {
console.warn(
`Warning: revalidatePath received "${originalPath}" which exceeded max length of ${NEXT_CACHE_SOFT_TAG_MAX_LENGTH}.`
)
return
}

let normalizedPath = `${NEXT_CACHE_IMPLICIT_TAG_ID}${originalPath}`

if (type) {
path += `${path.endsWith('/') ? '' : '/'}${type}`
normalizedPath += `${normalizedPath.endsWith('/') ? '' : '/'}${type}`
} else if (isDynamicRoute(originalPath)) {
console.warn(
`Warning: a dynamic page path "${originalPath}" was passed to "revalidatePath" without the "page" argument. This has no affect by default`
)
}
return revalidateTag(path)
return revalidateTag(normalizedPath)
}
7 changes: 5 additions & 2 deletions packages/next/src/server/web/spec-extension/unstable-cache.ts
Expand Up @@ -4,7 +4,7 @@ import {
StaticGenerationAsyncStorage,
} from '../../../client/components/static-generation-async-storage'
import { CACHE_ONE_YEAR } from '../../../lib/constants'
import { addImplicitTags } from '../../lib/patch-fetch'
import { addImplicitTags, validateTags } from '../../lib/patch-fetch'

type Callback = (...args: any[]) => Promise<any>

Expand Down Expand Up @@ -56,7 +56,10 @@ export function unstable_cache<T extends Callback>(
isStaticGeneration: !!store?.isStaticGeneration,
},
async () => {
const tags = options.tags || []
const tags = validateTags(
options.tags || [],
`unstable_cache ${cb.toString()}`
)

if (Array.isArray(tags) && store) {
if (!store.tags) {
Expand Down

0 comments on commit 48eb99e

Please sign in to comment.