diff --git a/docs/advanced-features/middleware.md b/docs/advanced-features/middleware.md index e7f22f7776f7eac..9ce455f984b6f36 100644 --- a/docs/advanced-features/middleware.md +++ b/docs/advanced-features/middleware.md @@ -221,18 +221,7 @@ export function middleware(request: NextRequest) { ## Producing a Response -You can respond to middleware directly by returning a `NextResponse` (responding from middleware is available since Next.js v13.0.0). - -To enable middleware responses, update `next.config.js`: - -```js -// next.config.js -module.exports = { - experimental: { - allowMiddlewareResponseBody: true, - }, -} -``` +You can respond to middleware directly by returning a `NextResponse` (responding from middleware is available since Next.js v13.1.0). Once enabled, you can provide a response from middleware using the `Response` or `NextResponse` API: diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index 3eac73c220edf01..463215a56fb2052 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -301,9 +301,6 @@ export function getDefineEnv({ 'process.env.__NEXT_I18N_SUPPORT': JSON.stringify(!!config.i18n), 'process.env.__NEXT_I18N_DOMAINS': JSON.stringify(config.i18n?.domains), 'process.env.__NEXT_ANALYTICS_ID': JSON.stringify(config.analyticsId), - 'process.env.__NEXT_ALLOW_MIDDLEWARE_RESPONSE_BODY': JSON.stringify( - config.allowMiddlewareResponseBody - ), 'process.env.__NEXT_NO_MIDDLEWARE_URL_NORMALIZE': JSON.stringify( config.skipMiddlewareUrlNormalize ), @@ -2062,7 +2059,6 @@ export default async function getBaseWebpackConfig( dev, sriEnabled: !dev && !!config.experimental.sri?.algorithm, hasFontLoaders: !!config.experimental.fontLoaders, - allowMiddlewareResponseBody: !!config.allowMiddlewareResponseBody, }), isClient && new BuildManifestPlugin({ @@ -2154,10 +2150,6 @@ export default async function getBaseWebpackConfig( ['swcEmotion', !!config.compiler?.emotion], ['turbotrace', !!config.experimental.turbotrace], ['transpilePackages', !!config.transpilePackages], - [ - 'allowMiddlewareResponseBody', - !!config.allowMiddlewareResponseBody, - ], [ 'skipMiddlewareUrlNormalize', !!config.skipMiddlewareUrlNormalize, diff --git a/packages/next/build/webpack/loaders/next-middleware-loader.ts b/packages/next/build/webpack/loaders/next-middleware-loader.ts index f68c2f71cc77122..2223269ed6fc304 100644 --- a/packages/next/build/webpack/loaders/next-middleware-loader.ts +++ b/packages/next/build/webpack/loaders/next-middleware-loader.ts @@ -40,7 +40,7 @@ export default function middlewareLoader(this: any) { buildInfo.rootDir = rootDir return ` - import { adapter, blockUnallowedResponse, enhanceGlobals } from 'next/dist/esm/server/web/adapter' + import { adapter, enhanceGlobals } from 'next/dist/esm/server/web/adapter' enhanceGlobals() @@ -52,11 +52,11 @@ export default function middlewareLoader(this: any) { } export default function (opts) { - return blockUnallowedResponse(adapter({ + return adapter({ ...opts, page: ${JSON.stringify(page)}, handler, - })) + }) } ` } diff --git a/packages/next/build/webpack/plugins/middleware-plugin.ts b/packages/next/build/webpack/plugins/middleware-plugin.ts index c191044087547b6..faaa98e38cee3ba 100644 --- a/packages/next/build/webpack/plugins/middleware-plugin.ts +++ b/packages/next/build/webpack/plugins/middleware-plugin.ts @@ -232,21 +232,6 @@ function isInMiddlewareLayer(parser: webpack.javascript.JavascriptParser) { return parser.state.module?.layer === 'middleware' } -function isInMiddlewareFile(parser: webpack.javascript.JavascriptParser) { - return ( - parser.state.current?.layer === 'middleware' && - /middleware\.\w+$/.test(parser.state.current?.rawRequest) - ) -} - -function isNullLiteral(expr: any) { - return expr.value === null -} - -function isUndefinedIdentifier(expr: any) { - return expr.name === 'undefined' -} - function isProcessEnvMemberExpression(memberExpression: any): boolean { return ( memberExpression.object?.type === 'Identifier' && @@ -345,14 +330,12 @@ function getCodeAnalyzer(params: { dev: boolean compiler: webpack.Compiler compilation: webpack.Compilation - allowMiddlewareResponseBody: boolean }) { return (parser: webpack.javascript.JavascriptParser) => { const { dev, compiler: { webpack: wp }, compilation, - allowMiddlewareResponseBody, } = params const { hooks } = parser @@ -488,32 +471,6 @@ function getCodeAnalyzer(params: { } } - /** - * A handler for calls to `new Response()` so we can fail if user is setting the response's body. - */ - const handleNewResponseExpression = (node: any) => { - const firstParameter = node?.arguments?.[0] - if ( - isInMiddlewareFile(parser) && - firstParameter && - !isNullLiteral(firstParameter) && - !isUndefinedIdentifier(firstParameter) - ) { - const error = buildWebpackError({ - message: `Middleware is returning a response body (line: ${node.loc.start.line}), which is not supported. -Learn more: https://nextjs.org/docs/messages/returning-response-body-in-middleware`, - compilation, - parser, - ...node, - }) - if (dev) { - compilation.warnings.push(error) - } else { - compilation.errors.push(error) - } - } - } - /** * Handler to store original source location of static and dynamic imports into module's buildInfo. */ @@ -568,10 +525,6 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`, .tap(NAME, handleWrapWasmInstantiateExpression) } - if (!allowMiddlewareResponseBody) { - hooks.new.for('Response').tap(NAME, handleNewResponseExpression) - hooks.new.for('NextResponse').tap(NAME, handleNewResponseExpression) - } hooks.callMemberChain.for('process').tap(NAME, handleCallMemberChain) hooks.expressionMemberChain.for('process').tap(NAME, handleCallMemberChain) hooks.importCall.tap(NAME, handleImport) @@ -835,23 +788,19 @@ export default class MiddlewarePlugin { private readonly dev: boolean private readonly sriEnabled: boolean private readonly hasFontLoaders: boolean - private readonly allowMiddlewareResponseBody: boolean constructor({ dev, sriEnabled, hasFontLoaders, - allowMiddlewareResponseBody, }: { dev: boolean sriEnabled: boolean hasFontLoaders: boolean - allowMiddlewareResponseBody: boolean }) { this.dev = dev this.sriEnabled = sriEnabled this.hasFontLoaders = hasFontLoaders - this.allowMiddlewareResponseBody = allowMiddlewareResponseBody } public apply(compiler: webpack.Compiler) { @@ -864,7 +813,6 @@ export default class MiddlewarePlugin { dev: this.dev, compiler, compilation, - allowMiddlewareResponseBody: this.allowMiddlewareResponseBody, }) hooks.parser.for('javascript/auto').tap(NAME, codeAnalyzer) hooks.parser.for('javascript/dynamic').tap(NAME, codeAnalyzer) diff --git a/packages/next/build/webpack/plugins/telemetry-plugin.ts b/packages/next/build/webpack/plugins/telemetry-plugin.ts index 37b96aa416eb0cf..1541db4333ca2f0 100644 --- a/packages/next/build/webpack/plugins/telemetry-plugin.ts +++ b/packages/next/build/webpack/plugins/telemetry-plugin.ts @@ -38,7 +38,6 @@ export type Feature = | `swc/target/${SWC_TARGET_TRIPLE}` | 'turbotrace' | 'transpilePackages' - | 'allowMiddlewareResponseBody' | 'skipMiddlewareUrlNormalize' | 'skipTrailingSlashRedirect' @@ -101,7 +100,6 @@ const BUILD_FEATURES: Array = [ 'swc/target/aarch64-pc-windows-msvc', 'turbotrace', 'transpilePackages', - 'allowMiddlewareResponseBody', 'skipMiddlewareUrlNormalize', 'skipTrailingSlashRedirect', ] diff --git a/packages/next/server/config-schema.ts b/packages/next/server/config-schema.ts index e6613681b08ce81..6cbfc8247cc38ad 100644 --- a/packages/next/server/config-schema.ts +++ b/packages/next/server/config-schema.ts @@ -7,9 +7,6 @@ const configSchema = { type: 'object', additionalProperties: false, properties: { - allowMiddlewareResponseBody: { - type: 'boolean', - }, amp: { additionalProperties: false, properties: { diff --git a/packages/next/server/config-shared.ts b/packages/next/server/config-shared.ts index 6b94aef5eb7b249..93f37ee86001191 100644 --- a/packages/next/server/config-shared.ts +++ b/packages/next/server/config-shared.ts @@ -504,8 +504,6 @@ export interface NextConfig extends Record { // A list of packages that should always be transpiled and bundled in the server transpilePackages?: string[] - allowMiddlewareResponseBody?: boolean - skipMiddlewareUrlNormalize?: boolean skipTrailingSlashRedirect?: boolean diff --git a/packages/next/server/config.ts b/packages/next/server/config.ts index afe9cf374a83850..8ff3d3c6c96cb6e 100644 --- a/packages/next/server/config.ts +++ b/packages/next/server/config.ts @@ -615,18 +615,6 @@ function assignDefaults(dir: string, userConfig: { [key: string]: any }) { result.transpilePackages = (result.experimental as any).transpilePackages } - if ( - result.experimental && - 'allowMiddlewareResponseBody' in (result.experimental as any) - ) { - Log.warn( - `\`allowMiddlewareResponseBody\` has been moved out of \`experimental\`. Please update your ${configFileName} file accordingly.` - ) - result.allowMiddlewareResponseBody = ( - result.experimental as any - ).allowMiddlewareResponseBody - } - if ( result.experimental && 'skipMiddlewareUrlNormalize' in (result.experimental as any) diff --git a/packages/next/server/web/adapter.ts b/packages/next/server/web/adapter.ts index 9595dd62084619c..01e050eee980c0b 100644 --- a/packages/next/server/web/adapter.ts +++ b/packages/next/server/web/adapter.ts @@ -198,32 +198,6 @@ export async function adapter(params: { } } -export function blockUnallowedResponse( - promise: Promise -): Promise { - if (process.env.__NEXT_ALLOW_MIDDLEWARE_RESPONSE_BODY) { - return promise - } - - return promise.then((result) => { - if (result.response?.body) { - console.error( - new Error( - `A middleware can not alter response's body. Learn more: https://nextjs.org/docs/messages/returning-response-body-in-middleware` - ) - ) - return { - ...result, - response: new Response('Internal Server Error', { - status: 500, - statusText: 'Internal Server Error', - }), - } - } - return result - }) -} - function getUnsupportedModuleErrorMessage(module: string) { // warning: if you change these messages, you must adjust how react-dev-overlay's middleware detects modules not found return `The edge runtime does not support Node.js '${module}' module. diff --git a/packages/next/telemetry/events/build.ts b/packages/next/telemetry/events/build.ts index 2deee0d6bb14193..45cbd6eb0926fc8 100644 --- a/packages/next/telemetry/events/build.ts +++ b/packages/next/telemetry/events/build.ts @@ -167,7 +167,6 @@ export type EventBuildFeatureUsage = { | 'build-lint' | 'vercelImageGeneration' | 'transpilePackages' - | 'allowMiddlewareResponseBody' | 'skipMiddlewareUrlNormalize' | 'skipTrailingSlashRedirect' invocationCount: number diff --git a/test/development/middleware-warnings/index.test.ts b/test/development/middleware-warnings/index.test.ts index 8be16043bdd08e9..fb72050354c3eaf 100644 --- a/test/development/middleware-warnings/index.test.ts +++ b/test/development/middleware-warnings/index.test.ts @@ -61,9 +61,9 @@ describe('middlewares', () => { return new Response(await fetch('https://example.vercel.sh')); }`, }, - ])('warns when $title', async ({ code }) => { + ])('does not warn when $title', async ({ code }) => { ;({ cleanup } = await sandbox(next, new Map([[middlewarePath, code]]))) - expect(next.cliOutput).toMatch(middlewareWarning) + expect(next.cliOutput).not.toMatch(middlewareWarning) }) it.each([ diff --git a/test/e2e/app-dir/app-middleware/next.config.js b/test/e2e/app-dir/app-middleware/next.config.js index 858ebde3005dccd..cfa3ac3d7aa94b3 100644 --- a/test/e2e/app-dir/app-middleware/next.config.js +++ b/test/e2e/app-dir/app-middleware/next.config.js @@ -1,5 +1,4 @@ module.exports = { - allowMiddlewareResponseBody: true, experimental: { appDir: true, }, diff --git a/test/e2e/middleware-responses/test/index.test.ts b/test/e2e/middleware-responses/test/index.test.ts index 6fd4bcd9623cbe0..4e2251abc644893 100644 --- a/test/e2e/middleware-responses/test/index.test.ts +++ b/test/e2e/middleware-responses/test/index.test.ts @@ -29,25 +29,23 @@ describe('Middleware Responses', () => { ]) }) - it(`${label}should fail when returning a stream`, async () => { + it(`${label}should not fail when returning a stream`, async () => { const res = await fetchViaHTTP(next.url, `${locale}/stream-a-response`) - expect(res.status).toBe(500) + expect(res.status).toBe(200) if (!(global as any).isNextDeploy) { - expect(await res.text()).toEqual('Internal Server Error') - expect(next.cliOutput).toContain( + expect(next.cliOutput).not.toContain( `A middleware can not alter response's body. Learn more: https://nextjs.org/docs/messages/returning-response-body-in-middleware` ) } }) - it(`${label}should fail when returning a text body`, async () => { + it(`${label}should not fail when returning a text body`, async () => { const res = await fetchViaHTTP(next.url, `${locale}/send-response`) - expect(res.status).toBe(500) + expect(res.status).toBe(200) if (!(global as any).isNextDeploy) { - expect(await res.text()).toEqual('Internal Server Error') - expect(next.cliOutput).toContain( + expect(next.cliOutput).not.toContain( `A middleware can not alter response's body. Learn more: https://nextjs.org/docs/messages/returning-response-body-in-middleware` ) } diff --git a/test/e2e/skip-trailing-slash-redirect/app/next.config.js b/test/e2e/skip-trailing-slash-redirect/app/next.config.js index 5c43bb59d11b645..c413d4df8fe066e 100644 --- a/test/e2e/skip-trailing-slash-redirect/app/next.config.js +++ b/test/e2e/skip-trailing-slash-redirect/app/next.config.js @@ -1,6 +1,5 @@ /** @type {import('next').NextConfig} */ const nextConfig = { - allowMiddlewareResponseBody: true, skipMiddlewareUrlNormalize: true, skipTrailingSlashRedirect: true, async redirects() { diff --git a/test/integration/middleware-build-errors/test/index.test.js b/test/integration/middleware-build-errors/test/index.test.js index 60591260eb42aa3..99ab65ebf3d370c 100644 --- a/test/integration/middleware-build-errors/test/index.test.js +++ b/test/integration/middleware-build-errors/test/index.test.js @@ -53,13 +53,13 @@ describe('Middleware validation during build', () => { ])('given a middleware $title', ({ code }) => { beforeAll(() => writeFile(middlewareFile, code)) - it('throws an error', async () => { + it('does not throw an error', async () => { const { stderr, code } = await nextBuild(appDir, [], { stderr: true, stdout: true, }) - expect(stderr).toMatch(middlewareError) - expect(code).toBe(1) + expect(stderr).not.toMatch(middlewareError) + expect(code).toBe(0) }) }) diff --git a/test/integration/telemetry/next.config.middleware-options b/test/integration/telemetry/next.config.middleware-options index 892345d5d3e41d1..a71f9539b704d1d 100644 --- a/test/integration/telemetry/next.config.middleware-options +++ b/test/integration/telemetry/next.config.middleware-options @@ -1,5 +1,4 @@ module.exports = { - allowMiddlewareResponseBody: true, skipMiddlewareUrlNormalize: true, skipTrailingSlashRedirect: true, } \ No newline at end of file diff --git a/test/integration/telemetry/test/index.test.js b/test/integration/telemetry/test/index.test.js index 76767314514fba5..36f133afe671452 100644 --- a/test/integration/telemetry/test/index.test.js +++ b/test/integration/telemetry/test/index.test.js @@ -1137,10 +1137,6 @@ describe('Telemetry CLI', () => { stderr, 'NEXT_BUILD_FEATURE_USAGE' ) - expect(featureUsageEvents).toContainEqual({ - featureName: 'allowMiddlewareResponseBody', - invocationCount: 1, - }) expect(featureUsageEvents).toContainEqual({ featureName: 'skipMiddlewareUrlNormalize', invocationCount: 1,