Skip to content

Commit

Permalink
Improve deprecation errors for new middleware API (#30316)
Browse files Browse the repository at this point in the history
Co-authored-by: JJ Kasper <jj@jjsweb.site>
Co-authored-by: Steven <steven@ceriously.com>
  • Loading branch information
3 people committed Oct 26, 2021
1 parent 8b85801 commit c497b3a
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 26 deletions.
4 changes: 4 additions & 0 deletions errors/manifest.json
Expand Up @@ -502,6 +502,10 @@
{
"title": "swc-minify-enabled",
"path": "/errors/swc-minify-enabled.md"
},
{
"title": "middleware-new-signature",
"path": "/errors/middleware-new-signature.md"
}
]
}
Expand Down
37 changes: 37 additions & 0 deletions errors/middleware-new-signature.md
@@ -0,0 +1,37 @@
# Deprecated Middleware API Signature

#### Why This Error Occurred

Your application is using a Middleware function that is using parameters from the deprecated API.

```typescript
// _middleware.js
import { NextResponse } from 'next/server'

export function middleware(event) {
if (event.request.nextUrl.pathname === '/blocked') {
event.respondWith(
new NextResponse(null, {
status: 403,
})
)
}
}
```

#### Possible Ways to Fix It

Update to use the new API for Middleware:

```typescript
// _middleware.js
import { NextResponse } from 'next/server'

export function middleware(request) {
if (request.nextUrl.pathname === '/blocked') {
return new NextResponse(null, {
status: 403,
})
}
}
```
Expand Up @@ -26,7 +26,8 @@ export default function middlewareLoader(this: any) {
export default function (opts) {
return adapter({
...opts,
handler
page: ${JSON.stringify(page)},
handler,
})
}
`
Expand Down
38 changes: 25 additions & 13 deletions packages/next/server/web/adapter.ts
Expand Up @@ -8,22 +8,27 @@ import { waitUntilSymbol } from './spec-compliant/fetch-event'

export async function adapter(params: {
handler: (request: NextRequest, event: NextFetchEvent) => Promise<Response>
page: string
request: RequestData
}): Promise<FetchEventResult> {
const url = params.request.url.startsWith('/')
? `https://${params.request.headers.host}${params.request.url}`
: params.request.url

const request = new NextRequestHint(url, {
geo: params.request.geo,
headers: fromNodeHeaders(params.request.headers),
ip: params.request.ip,
method: params.request.method,
nextConfig: params.request.nextConfig,
page: params.request.page,
const request = new NextRequestHint({
page: params.page,
input: url,
init: {
geo: params.request.geo,
headers: fromNodeHeaders(params.request.headers),
ip: params.request.ip,
method: params.request.method,
nextConfig: params.request.nextConfig,
page: params.request.page,
},
})

const event = new NextFetchEvent(request)
const event = new NextFetchEvent({ request, page: params.page })
const original = await params.handler(request, event)

return {
Expand All @@ -33,19 +38,26 @@ export async function adapter(params: {
}

class NextRequestHint extends NextRequest {
constructor(input: Request | string, init: RequestInit = {}) {
super(input, init)
sourcePage: string

constructor(params: {
init: RequestInit
input: Request | string
page: string
}) {
super(params.input, params.init)
this.sourcePage = params.page
}

get request() {
throw new DeprecationError()
throw new DeprecationError({ page: this.sourcePage })
}

respondWith() {
throw new DeprecationError()
throw new DeprecationError({ page: this.sourcePage })
}

waitUntil() {
throw new DeprecationError()
throw new DeprecationError({ page: this.sourcePage })
}
}
6 changes: 4 additions & 2 deletions packages/next/server/web/error.ts
@@ -1,10 +1,12 @@
export class DeprecationError extends Error {
constructor() {
super(`Middleware now accepts an async API directly with the form:
constructor({ page }: { page: string }) {
super(`The middleware "${page}" accepts an async API directly with the form:
export function middleware(request, event) {
return new Response("Hello " + request.url)
}
Read more: https://nextjs.org/docs/messages/middleware-new-signature
`)
}
}
5 changes: 0 additions & 5 deletions packages/next/server/web/spec-compliant/fetch-event.ts
Expand Up @@ -3,15 +3,10 @@ export const passThroughSymbol = Symbol('passThrough')
export const waitUntilSymbol = Symbol('waitUntil')

export class FetchEvent {
readonly request: Request;
readonly [waitUntilSymbol]: Promise<any>[] = [];
[responseSymbol]?: Promise<Response>;
[passThroughSymbol] = false

constructor(request: Request) {
this.request = request
}

respondWith(response: Response | Promise<Response>): void {
if (!this[responseSymbol]) {
this[responseSymbol] = Promise.resolve(response)
Expand Down
20 changes: 15 additions & 5 deletions packages/next/server/web/spec-extension/fetch-event.ts
Expand Up @@ -3,13 +3,23 @@ import { FetchEvent } from '../spec-compliant/fetch-event'
import { NextRequest } from './request'

export class NextFetchEvent extends FetchEvent {
readonly request: NextRequest
constructor(request: NextRequest) {
super(request)
this.request = request
sourcePage: string

constructor(params: { request: NextRequest; page: string }) {
super(params.request)
this.sourcePage = params.page
}

// @ts-ignore
get request() {
throw new DeprecationError({
page: this.sourcePage,
})
}

respondWith() {
throw new DeprecationError()
throw new DeprecationError({
page: this.sourcePage,
})
}
}

0 comments on commit c497b3a

Please sign in to comment.