Skip to content

Commit 4f6232b

Browse files
committed
feat: allow next middleware to use edge cache
1 parent 77dec56 commit 4f6232b

File tree

10 files changed

+147
-1
lines changed

10 files changed

+147
-1
lines changed

src/build/functions/edge.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,10 @@ const buildHandlerDefinition = (
172172
const functionName = name.endsWith('middleware')
173173
? 'Next.js Middleware Handler'
174174
: `Next.js Edge Handler: ${page}`
175-
const cache = name.endsWith('middleware') ? undefined : ('manual' as const)
175+
const cache =
176+
!process.env.NEXT_MIDDLEWARE_CACHE && name.endsWith('middleware')
177+
? undefined
178+
: ('manual' as const)
176179
const generator = `${ctx.pluginName}@${ctx.pluginVersion}`
177180

178181
return augmentMatchers(matchers, ctx).map((matcher) => ({
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
export const metadata = {
2+
title: 'Simple Next App',
3+
description: 'Description for Simple Next App',
4+
}
5+
6+
export default function RootLayout({ children }) {
7+
return (
8+
<html lang="en">
9+
<body>{children}</body>
10+
</html>
11+
)
12+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export default function Home() {
2+
return (
3+
<main>
4+
<h1>Home</h1>
5+
</main>
6+
)
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export default function EdgeCached() {
2+
return (
3+
<main>
4+
<h1>If middleware works, we shoudn't get here</h1>
5+
</main>
6+
)
7+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { headers } from 'next/headers'
2+
3+
export default function Page() {
4+
const headersList = headers()
5+
const message = headersList.get('x-hello-from-middleware-req')
6+
7+
return (
8+
<main>
9+
<h1>Message from middleware: {message}</h1>
10+
</main>
11+
)
12+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export default function EdgeUncached() {
2+
return (
3+
<main>
4+
<h1>If middleware works, we shoudn't get here</h1>
5+
</main>
6+
)
7+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import type { NextRequest } from 'next/server'
2+
import { NextResponse } from 'next/server'
3+
4+
export function middleware(request: NextRequest) {
5+
const response = getResponse(request)
6+
7+
response.headers.append('Deno' in globalThis ? 'x-deno' : 'x-node', Date.now().toString())
8+
response.headers.set('x-hello-from-middleware-res', 'hello')
9+
10+
return response
11+
}
12+
13+
const getResponse = (request: NextRequest) => {
14+
const requestHeaders = new Headers(request.headers)
15+
16+
requestHeaders.set('x-hello-from-middleware-req', 'hello')
17+
18+
if (request.nextUrl.pathname === '/test/cached') {
19+
return NextResponse.next({
20+
request: {
21+
headers: new Headers({
22+
...requestHeaders,
23+
'netlify-cdn-cache-control': 's-maxage=31536000, durable',
24+
}),
25+
},
26+
})
27+
}
28+
29+
if (request.nextUrl.pathname === '/test/uncached') {
30+
return NextResponse.next({
31+
request: {
32+
headers: requestHeaders,
33+
},
34+
})
35+
}
36+
37+
return NextResponse.json({ error: 'Error' }, { status: 500 })
38+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/** @type {import('next').NextConfig} */
2+
const nextConfig = {
3+
output: 'standalone',
4+
eslint: {
5+
ignoreDuringBuilds: true,
6+
},
7+
}
8+
9+
module.exports = nextConfig
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"name": "middleware-edge-cache",
3+
"version": "0.1.0",
4+
"private": true,
5+
"scripts": {
6+
"postinstall": "next build",
7+
"dev": "next dev",
8+
"build": "next build"
9+
},
10+
"dependencies": {
11+
"next": "latest",
12+
"react": "18.2.0",
13+
"react-dom": "18.2.0"
14+
}
15+
}

tests/integration/edge-handler.test.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,4 +625,40 @@ describe('page router', () => {
625625
expect(bodyFr.nextUrlPathname).toBe('/json')
626626
expect(bodyFr.nextUrlLocale).toBe('fr')
627627
})
628+
629+
test<FixtureTestContext>('should use edge caching', async (ctx) => {
630+
vi.stubEnv('NEXT_MIDDLEWARE_CACHE', 'true')
631+
632+
await createFixture('middleware-edge-cache', ctx)
633+
await runPlugin(ctx)
634+
const origin = await LocalServer.run(async (req, res) => {
635+
res.write(
636+
JSON.stringify({
637+
url: req.url,
638+
headers: req.headers,
639+
}),
640+
)
641+
res.end()
642+
})
643+
ctx.cleanup?.push(() => origin.stop())
644+
645+
const response = await invokeEdgeFunction(ctx, {
646+
functions: ['___netlify-edge-handler-middleware'],
647+
origin,
648+
url: `/test/cached`,
649+
})
650+
expect(response.status).toBe(200)
651+
652+
expect(response.headers.has('netlify-cdn-cache-control')).toBeTruthy()
653+
expect(response.headers.get('netlify-cdn-cache-control')).toBe('s-maxage=31536000, durable')
654+
655+
const responseUncached = await invokeEdgeFunction(ctx, {
656+
functions: ['___netlify-edge-handler-middleware'],
657+
origin,
658+
url: `/test/uncached`,
659+
})
660+
expect(responseUncached.status).toBe(200)
661+
662+
expect(responseUncached.headers.has('netlify-cdn-cache-control')).toBeFalsy()
663+
})
628664
})

0 commit comments

Comments
 (0)