Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions packages/next/src/build/templates/app-page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1389,12 +1389,7 @@ export async function handler(

// In dev, we should not cache pages for any reason.
if (routeModule.isDev) {
res.setHeader(
'Cache-Control',
nextConfig.experimental.devCacheControlNoCache
? 'no-cache, must-revalidate'
: 'no-store, must-revalidate'
)
res.setHeader('Cache-Control', 'no-cache, must-revalidate')
}

if (!cacheEntry) {
Expand Down
7 changes: 1 addition & 6 deletions packages/next/src/server/base-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1803,12 +1803,7 @@ export default abstract class Server<

// In dev, we should not cache pages for any reason.
if (this.dev) {
res.setHeader(
'Cache-Control',
this.nextConfig.experimental.devCacheControlNoCache
? 'no-cache, must-revalidate'
: 'no-store, must-revalidate'
)
res.setHeader('Cache-Control', 'no-cache, must-revalidate')
cacheControl = undefined
}

Expand Down
1 change: 0 additions & 1 deletion packages/next/src/server/config-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,6 @@ export const experimentalSchema = {
hideLogsAfterAbort: z.boolean().optional(),
runtimeServerDeploymentId: z.boolean().optional(),
immutableAssetToken: z.string().optional(),
devCacheControlNoCache: z.boolean().optional(),
deferredEntries: z.array(z.string()).optional(),
onBeforeDeferredEntries: z.function().returns(z.promise(z.void())).optional(),
reportSystemEnvInlining: z.enum(['warn', 'error']).optional(),
Expand Down
15 changes: 0 additions & 15 deletions packages/next/src/server/config-shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1039,18 +1039,6 @@ export interface ExperimentalConfig {
*/
immutableAssetToken?: string

/**
* Use 'no-cache' instead of 'no-store' in the Cache-Control header for development.
* This allows conditional requests to the server, which can help with development
* workflows that benefit from caching validation.
*
* When enabled, the Cache-Control header changes from 'no-store, must-revalidate'
* to 'no-cache, must-revalidate'.
*
* @default false
*/
devCacheControlNoCache?: boolean

/**
* An array of paths in app or pages directories that should wait to be processed
* until all other entries have been processed. This is useful for deferring
Expand Down Expand Up @@ -1812,7 +1800,6 @@ export const defaultConfig = Object.freeze({
turbopackFileSystemCacheForBuild: false,
turbopackInferModuleSideEffects: true,
turbopackPluginRuntimeStrategy: 'childProcesses',
devCacheControlNoCache: false,
},
htmlLimitedBots: undefined,
bundlePagesRouterDependencies: false,
Expand Down Expand Up @@ -1911,7 +1898,6 @@ export interface NextConfigRuntime {
| 'testProxy'
| 'runtimeServerDeploymentId'
| 'maxPostponedStateSize'
| 'devCacheControlNoCache'
| 'cachedNavigations'
| 'partialFallbacks'
| 'exposeTestingApiInProductionBuild'
Expand Down Expand Up @@ -1982,7 +1968,6 @@ export function getNextConfigRuntime(
testProxy: ex.testProxy,
runtimeServerDeploymentId: ex.runtimeServerDeploymentId,
maxPostponedStateSize: ex.maxPostponedStateSize,
devCacheControlNoCache: ex.devCacheControlNoCache,
cachedNavigations: ex.cachedNavigations,
partialFallbacks: ex.partialFallbacks,
exposeTestingApiInProductionBuild: ex.exposeTestingApiInProductionBuild,
Expand Down
7 changes: 1 addition & 6 deletions packages/next/src/server/lib/router-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -507,12 +507,7 @@ export async function initialize(opts: {
matchedOutput.type === 'nextStaticFolder'
) {
if (opts.dev && !isNextFont(parsedUrl.pathname)) {
res.setHeader(
'Cache-Control',
config.experimental.devCacheControlNoCache
? 'no-cache, must-revalidate'
: 'no-store, must-revalidate'
)
res.setHeader('Cache-Control', 'no-cache, must-revalidate')
} else {
res.setHeader(
'Cache-Control',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -706,12 +706,7 @@ export const getHandler = ({

// In dev, we should not cache pages for any reason.
if (routeModule.isDev) {
res.setHeader(
'Cache-Control',
nextConfig.experimental.devCacheControlNoCache
? 'no-cache, must-revalidate'
: 'no-store, must-revalidate'
)
res.setHeader('Cache-Control', 'no-cache, must-revalidate')
}

// Draft mode should never be cached
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
import { nextTestSetup } from 'e2e-utils'

describe('experimental.devCacheControlNoCache', () => {
describe('when enabled', () => {
const { next } = nextTestSetup({
files: __dirname,
})
describe('dev Cache-Control header', () => {
const { next } = nextTestSetup({
files: __dirname,
})

it('should use no-cache instead of no-store for pages router', async () => {
const res = await next.fetch('/pages-route')
expect(res.headers.get('Cache-Control')).toBe('no-cache, must-revalidate')
})
it('should use no-cache for pages router', async () => {
const res = await next.fetch('/pages-route')
expect(res.headers.get('Cache-Control')).toBe('no-cache, must-revalidate')
})

it('should use no-cache instead of no-store for app router', async () => {
const res = await next.fetch('/app-route')
expect(res.headers.get('Cache-Control')).toBe('no-cache, must-revalidate')
})
it('should use no-cache for app router', async () => {
const res = await next.fetch('/app-route')
expect(res.headers.get('Cache-Control')).toBe('no-cache, must-revalidate')
})
})
6 changes: 1 addition & 5 deletions test/development/dev-cache-control-no-cache/next.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,2 @@
/** @type {import('next').NextConfig} */
module.exports = {
experimental: {
devCacheControlNoCache: true,
},
}
module.exports = {}
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ describe('Client Navigation rendering', () => {
responses.forEach((res) => {
try {
expect(res.headers.get('Cache-Control')).toBe(
'no-store, must-revalidate'
'no-cache, must-revalidate'
)
} catch (err) {
err.message = res.url + ' ' + err.message
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ describe('custom-cache-control', () => {
it('should have custom cache-control for app-ssg prerendered', async () => {
const res = await next.fetch('/app-ssg/first')
expect(res.headers.get('cache-control')).toBe(
isNextDev ? 'no-store, must-revalidate' : 's-maxage=30'
isNextDev ? 'no-cache, must-revalidate' : 's-maxage=30'
)
})

it('should have custom cache-control for app-ssg lazy', async () => {
const res = await next.fetch('/app-ssg/lazy')
expect(res.headers.get('cache-control')).toBe(
isNextDev ? 'no-store, must-revalidate' : 's-maxage=31'
isNextDev ? 'no-cache, must-revalidate' : 's-maxage=31'
)
})
;(process.env.__NEXT_CACHE_COMPONENTS ? it.skip : it)(
Expand All @@ -32,7 +32,7 @@ describe('custom-cache-control', () => {
// eslint-disable-next-line jest/no-standalone-expect
expect(res.headers.get('cache-control')).toBe(
isNextDev
? 'no-store, must-revalidate'
? 'no-cache, must-revalidate'
: 's-maxage=120, stale-while-revalidate=31535880'
)
}
Expand All @@ -41,44 +41,44 @@ describe('custom-cache-control', () => {
it('should have custom cache-control for app-ssr', async () => {
const res = await next.fetch('/app-ssr')
expect(res.headers.get('cache-control')).toBe(
isNextDev ? 'no-store, must-revalidate' : 's-maxage=32'
isNextDev ? 'no-cache, must-revalidate' : 's-maxage=32'
)
})

it('should have custom cache-control for auto static page', async () => {
const res = await next.fetch('/pages-auto-static')
expect(res.headers.get('cache-control')).toBe(
isNextDev ? 'no-store, must-revalidate' : 's-maxage=33'
isNextDev ? 'no-cache, must-revalidate' : 's-maxage=33'
)
})

it('should have custom cache-control for pages-ssg prerendered', async () => {
const res = await next.fetch('/pages-ssg/first')
expect(res.headers.get('cache-control')).toBe(
isNextDev ? 'no-store, must-revalidate' : 's-maxage=34'
isNextDev ? 'no-cache, must-revalidate' : 's-maxage=34'
)
})

it('should have custom cache-control for pages-ssg lazy', async () => {
const res = await next.fetch('/pages-ssg/lazy')
expect(res.headers.get('cache-control')).toBe(
isNextDev ? 'no-store, must-revalidate' : 's-maxage=35'
isNextDev ? 'no-cache, must-revalidate' : 's-maxage=35'
)
})

it('should have default cache-control for pages-ssg another', async () => {
const res = await next.fetch('/pages-ssg/another')
expect(res.headers.get('cache-control')).toBe(
isNextDev
? 'no-store, must-revalidate'
? 'no-cache, must-revalidate'
: 's-maxage=120, stale-while-revalidate=31535880'
)
})

it('should have default cache-control for pages-ssr', async () => {
const res = await next.fetch('/pages-ssr')
expect(res.headers.get('cache-control')).toBe(
isNextDev ? 'no-store, must-revalidate' : 's-maxage=36'
isNextDev ? 'no-cache, must-revalidate' : 's-maxage=36'
)
})
})
4 changes: 3 additions & 1 deletion test/e2e/app-dir/fallback-prefetch/fallback-prefetch.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ describe('fallback-prefetch', () => {
const browser = await next.browser('/', {
beforePageLoad: (page) => {
page.on('response', (response) => {
if (!response.ok()) {
// 304 Not Modified is a valid revalidation response (from no-cache),
// not a network error
if (!response.ok() && response.status() !== 304) {
hasNetworkError = true
}
})
Expand Down
6 changes: 3 additions & 3 deletions test/e2e/app-dir/metadata/metadata.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -691,7 +691,7 @@ describe('app dir - metadata', () => {
expect(res.headers.get('content-type')).toBe('image/x-icon')
expect(res.headers.get('cache-control')).toBe(
isNextDev
? 'no-store, must-revalidate'
? 'no-cache, must-revalidate'
: 'public, max-age=0, must-revalidate'
)
})
Expand All @@ -706,14 +706,14 @@ describe('app dir - metadata', () => {
expect(resAppleIcon.headers.get('content-type')).toBe('image/png')
expect(resAppleIcon.headers.get('cache-control')).toBe(
isNextDev
? 'no-store, must-revalidate'
? 'no-cache, must-revalidate'
: 'public, max-age=0, must-revalidate'
)
expect(resIcon.status).toBe(200)
expect(resIcon.headers.get('content-type')).toBe('image/png')
expect(resIcon.headers.get('cache-control')).toBe(
isNextDev
? 'no-store, must-revalidate'
? 'no-cache, must-revalidate'
: 'public, max-age=0, must-revalidate'
)
})
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/app-dir/ppr-full/ppr-full.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ describe.skip('ppr-full', () => {
if (isNextDeploy) {
expect(cacheControl).toEqual('public, max-age=0, must-revalidate')
} else if (isNextDev) {
expect(cacheControl).toEqual('no-store, must-revalidate')
expect(cacheControl).toEqual('no-cache, must-revalidate')
} else if (dynamic === false || dynamic === 'force-static') {
expect(cacheControl).toEqual(
revalidate === undefined
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/prerender.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ describe('Prerender', () => {
}

function isCachingHeader(cacheControl) {
return !cacheControl || !/no-store/.test(cacheControl)
return !cacheControl || !/no-store|no-cache/.test(cacheControl)
}

const allowHeader = [
Expand Down
14 changes: 2 additions & 12 deletions test/rspack-dev-tests-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -1993,20 +1993,10 @@
"flakey": [],
"runtimeError": false
},
"test/development/dev-cache-control-no-cache-disabled/dev-cache-control-no-cache-disabled.test.ts": {
"passed": [
"experimental.devCacheControlNoCache disabled (default) should use no-store for app router by default",
"experimental.devCacheControlNoCache disabled (default) should use no-store for pages router by default"
],
"failed": [],
"pending": [],
"flakey": [],
"runtimeError": false
},
"test/development/dev-cache-control-no-cache/dev-cache-control-no-cache.test.ts": {
"passed": [
"experimental.devCacheControlNoCache when enabled should use no-cache instead of no-store for app router",
"experimental.devCacheControlNoCache when enabled should use no-cache instead of no-store for pages router"
"dev Cache-Control header should use no-cache for app router",
"dev Cache-Control header should use no-cache for pages router"
],
"failed": [],
"pending": [],
Expand Down
Loading