From c497b3a5ff3199967f476323b9d2287f97ecbdea Mon Sep 17 00:00:00 2001 From: Javi Velasco Date: Tue, 26 Oct 2021 17:03:39 +0200 Subject: [PATCH] Improve deprecation errors for new middleware API (#30316) Co-authored-by: JJ Kasper Co-authored-by: Steven --- errors/manifest.json | 4 ++ errors/middleware-new-signature.md | 37 ++++++++++++++++++ .../webpack/loaders/next-middleware-loader.ts | 3 +- packages/next/server/web/adapter.ts | 38 ++++++++++++------- packages/next/server/web/error.ts | 6 ++- .../server/web/spec-compliant/fetch-event.ts | 5 --- .../server/web/spec-extension/fetch-event.ts | 20 +++++++--- 7 files changed, 87 insertions(+), 26 deletions(-) create mode 100644 errors/middleware-new-signature.md diff --git a/errors/manifest.json b/errors/manifest.json index 0145ee2569fb416..4d19b214c514467 100644 --- a/errors/manifest.json +++ b/errors/manifest.json @@ -502,6 +502,10 @@ { "title": "swc-minify-enabled", "path": "/errors/swc-minify-enabled.md" + }, + { + "title": "middleware-new-signature", + "path": "/errors/middleware-new-signature.md" } ] } diff --git a/errors/middleware-new-signature.md b/errors/middleware-new-signature.md new file mode 100644 index 000000000000000..b7bb43307b5ce6d --- /dev/null +++ b/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, + }) + } +} +``` diff --git a/packages/next/build/webpack/loaders/next-middleware-loader.ts b/packages/next/build/webpack/loaders/next-middleware-loader.ts index d036508e177b3a6..4768d485216fe08 100644 --- a/packages/next/build/webpack/loaders/next-middleware-loader.ts +++ b/packages/next/build/webpack/loaders/next-middleware-loader.ts @@ -26,7 +26,8 @@ export default function middlewareLoader(this: any) { export default function (opts) { return adapter({ ...opts, - handler + page: ${JSON.stringify(page)}, + handler, }) } ` diff --git a/packages/next/server/web/adapter.ts b/packages/next/server/web/adapter.ts index 32e210c4c5921a9..057337f25fb32b1 100644 --- a/packages/next/server/web/adapter.ts +++ b/packages/next/server/web/adapter.ts @@ -8,22 +8,27 @@ import { waitUntilSymbol } from './spec-compliant/fetch-event' export async function adapter(params: { handler: (request: NextRequest, event: NextFetchEvent) => Promise + page: string request: RequestData }): Promise { 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 { @@ -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 }) } } diff --git a/packages/next/server/web/error.ts b/packages/next/server/web/error.ts index 8efcdfb0836444b..ebe14d9f27d78a5 100644 --- a/packages/next/server/web/error.ts +++ b/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 `) } } diff --git a/packages/next/server/web/spec-compliant/fetch-event.ts b/packages/next/server/web/spec-compliant/fetch-event.ts index c410d39736e9f1f..916b32b6da186cd 100644 --- a/packages/next/server/web/spec-compliant/fetch-event.ts +++ b/packages/next/server/web/spec-compliant/fetch-event.ts @@ -3,15 +3,10 @@ export const passThroughSymbol = Symbol('passThrough') export const waitUntilSymbol = Symbol('waitUntil') export class FetchEvent { - readonly request: Request; readonly [waitUntilSymbol]: Promise[] = []; [responseSymbol]?: Promise; [passThroughSymbol] = false - constructor(request: Request) { - this.request = request - } - respondWith(response: Response | Promise): void { if (!this[responseSymbol]) { this[responseSymbol] = Promise.resolve(response) diff --git a/packages/next/server/web/spec-extension/fetch-event.ts b/packages/next/server/web/spec-extension/fetch-event.ts index 1d6d704ed3bdb85..4e1af9e28a1a08b 100644 --- a/packages/next/server/web/spec-extension/fetch-event.ts +++ b/packages/next/server/web/spec-extension/fetch-event.ts @@ -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, + }) } }