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
Original file line number Diff line number Diff line change
Expand Up @@ -805,10 +805,10 @@ impl ReactServerComponentValidator {
return;
}
static RE: Lazy<Regex> =
Lazy::new(|| Regex::new(r"[\\/](page|layout)\.(ts|js)x?$").unwrap());
let is_layout_or_page = RE.is_match(&self.filepath);
Lazy::new(|| Regex::new(r"[\\/](page|layout|route)\.(ts|js)x?$").unwrap());
let is_app_entry = RE.is_match(&self.filepath);

if is_layout_or_page {
if is_app_entry {
let mut possibly_invalid_exports: FxIndexMap<Atom, (InvalidExportKind, Span)> =
FxIndexMap::default();

Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -161,13 +161,6 @@ describe('async imports in cacheComponents', () => {
// indirectly tests the behavior of middleware by rendering a page which the middleware matches
await testPage('/not-instrumented/middleware')
})

it('edge route handler', async () => {
Copy link
Member Author

@ztanner ztanner Sep 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this test should never have been possible to begin with, as specifying edge runtime with cache components should have errored.

const result = await next
.fetch('/not-instrumented/edge-route-handler')
.then((res) => res.text())
expect(result).toBe('hello')
})
})
})

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const dynamic = 'force-static'

export async function GET(request: Request) {
return new Response('route GET')
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const fetchCache = 'force-cache'

export async function GET(request: Request) {
return new Response('route GET with fetchCache')
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const revalidate = 60

export async function GET(request: Request) {
return new Response('route GET with revalidate')
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { nextTestSetup } from 'e2e-utils'
import {
assertHasRedbox,
getRedboxDescription,
getRedboxSource,
} from 'next-test-utils'

describe('cache-components-route-handler-errors', () => {
const { next, skipped, isNextDev, isTurbopack } = nextTestSetup({
files: __dirname,
skipStart: true,
skipDeployment: true,
})

if (skipped) {
return
}

it("should error when route handlers use segment configs that aren't supported by cacheComponents", async () => {
try {
await next.start()
} catch {
// we expect the build to fail
}

if (isNextDev) {
// Test the first route handler with "dynamic" config
const browser = await next.browser('/route-with-dynamic')
await assertHasRedbox(browser)
const redbox = {
description: await getRedboxDescription(browser),
source: await getRedboxSource(browser),
}

if (isTurbopack) {
expect(redbox.description).toMatchInlineSnapshot(
`"Ecmascript file had an error"`
)
} else {
expect(redbox.description).toMatchInlineSnapshot(
`" x Route segment config "dynamic" is not compatible with \`nextConfig.experimental.cacheComponents\`. Please remove it."`
)
}
expect(redbox.source).toContain(
'"dynamic" is not compatible with `nextConfig.experimental.cacheComponents`. Please remove it.'
)
} else {
// In build mode, check for all three errors in the output
expect(next.cliOutput).toContain('./app/route-with-dynamic/route.ts')
expect(next.cliOutput).toContain(
'"dynamic" is not compatible with `nextConfig.experimental.cacheComponents`. Please remove it.'
)

expect(next.cliOutput).toContain('./app/route-with-revalidate/route.ts')
expect(next.cliOutput).toContain(
'"revalidate" is not compatible with `nextConfig.experimental.cacheComponents`. Please remove it.'
)

expect(next.cliOutput).toContain('./app/route-with-fetchcache/route.ts')
expect(next.cliOutput).toContain(
'"fetchCache" is not compatible with `nextConfig.experimental.cacheComponents`. Please remove it.'
)
}
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* @type {import('next').NextConfig}
*/
const nextConfig = {
experimental: {
cacheComponents: true,
},
}

module.exports = nextConfig
2 changes: 2 additions & 0 deletions test/experimental-tests-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@
"test/e2e/app-dir/app/standalone-gsp.test.ts",
"test/e2e/app-dir/app/standalone.test.ts",
"test/e2e/app-dir/app/useReportWebVitals.test.ts",
"test/e2e/app-dir/bun-externals/bun-externals.test.ts",
"test/e2e/app-dir/async-component-preload/async-component-preload.test.ts",
"test/e2e/app-dir/autoscroll-with-css-modules/index.test.ts",
"test/e2e/app-dir/back-forward-cache/back-forward-cache.test.ts",
Expand Down Expand Up @@ -268,6 +269,7 @@
"test/e2e/app-dir/static-shell-debugging/static-shell-debugging.test.ts",
"test/e2e/app-dir/taint/process-taint.test.ts",
"test/e2e/app-dir/temporary-references/temporary-references.test.ts",
"test/e2e/app-dir/typed-routes-validator/typed-routes-validator.test.ts",
"test/e2e/app-dir/unauthorized/basic/unauthorized-basic.test.ts",
"test/e2e/app-dir/unauthorized/default/unauthorized-default.test.ts",
"test/e2e/app-dir/unstable-rethrow/unstable-rethrow.test.ts",
Expand Down
Loading