Skip to content

Commit efdb03d

Browse files
committed
feat: add support for rewriting middleware responses
1 parent 5d67f5f commit efdb03d

File tree

8 files changed

+921
-21
lines changed

8 files changed

+921
-21
lines changed

.prettierignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,5 @@ node_modules
2121
lib
2222
tsconfig.json
2323
demos/nx-next-monorepo-demo
24-
plugin/src/templates/edge
2524

2625
plugin/CHANGELOG.md

demos/middleware/middleware.ts

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,68 @@
11
import { NextResponse } from 'next/server'
2-
import { NextFetchEvent, NextRequest } from 'next/server'
2+
import type { NextRequest } from 'next/server'
33

4-
export function middleware(request: NextRequest, ev: NextFetchEvent) {
4+
/**
5+
* Supercharge your Next middleware with Netlify Edge Functions
6+
*/
7+
class NetlifyResponse {
8+
static async next(request: NextRequest): Promise<NetlifyNextResponse> {
9+
const context = (request.geo as any).__nf_context
10+
if (!context) {
11+
throw new Error('NetlifyResponse can only be used with Netlify Edge Functions')
12+
}
13+
const response: Response = await context.next()
14+
return new NetlifyNextResponse(response)
15+
}
16+
}
17+
18+
type NextDataTransform = <T extends Record<string, any>>(props: T) => T
19+
20+
// A NextReponse that will pass through the Netlify origin response
21+
// We can't pass it through directly, because Next disallows returning a response body
22+
class NetlifyNextResponse extends NextResponse {
23+
private originResponse: Response
24+
private transforms: NextDataTransform[]
25+
constructor(originResponse: Response) {
26+
super()
27+
this.originResponse = originResponse
28+
Object.defineProperty(this, 'transforms', {
29+
value: [],
30+
enumerable: false,
31+
writable: false,
32+
})
33+
}
34+
35+
/**
36+
* Transform the page props before they are passed to the client.
37+
* This works for both HTML pages and JSON data
38+
*/
39+
transformData(transform: NextDataTransform) {
40+
// The transforms are evaluated after the middleware is returned
41+
this.transforms.push(transform)
42+
}
43+
get headers(): Headers {
44+
// If we have the origin response, we should use its headers
45+
return this.originResponse?.headers || super.headers
46+
}
47+
}
48+
49+
export async function middleware(request: NextRequest) {
550
let response
651
const {
752
nextUrl: { pathname },
853
} = request
954

55+
if (pathname.startsWith('/static')) {
56+
// Unlike NextResponse.next(), this actually sends the request to the origin
57+
const res = await NetlifyResponse.next(request)
58+
res.transformData((data) => {
59+
data.pageProps.message = `This was static but has been transformed in ${request.geo.country}`
60+
return data
61+
})
62+
63+
return res
64+
}
65+
1066
if (pathname.startsWith('/cookies')) {
1167
response = NextResponse.next()
1268
response.cookies.set('netlifyCookie', 'true')

0 commit comments

Comments
 (0)