diff --git a/src/build/content/server.ts b/src/build/content/server.ts index 40e15663f3..3959dc6dc9 100644 --- a/src/build/content/server.ts +++ b/src/build/content/server.ts @@ -17,6 +17,7 @@ import { trace } from '@opentelemetry/api' import { wrapTracer } from '@opentelemetry/api/experimental' import glob from 'fast-glob' import type { MiddlewareManifest } from 'next/dist/build/webpack/plugins/middleware-plugin.js' +import type { FunctionsConfigManifest } from 'next-with-cache-handler-v2/dist/build/index.js' import { prerelease, satisfies, lt as semverLowerThan, lte as semverLowerThanOrEqual } from 'semver' import type { RunConfig } from '../../run/config.js' @@ -131,6 +132,10 @@ export const copyNextServerCode = async (ctx: PluginContext): Promise => { return } + if (path === 'server/functions-config-manifest.json') { + await verifyFunctionsConfigManifest(join(srcDir, path)) + } + await cp(srcPath, destPath, { recursive: true, force: true }) }), ) @@ -376,6 +381,19 @@ const replaceMiddlewareManifest = async (sourcePath: string, destPath: string) = await writeFile(destPath, newData) } +const verifyFunctionsConfigManifest = async (sourcePath: string) => { + const data = await readFile(sourcePath, 'utf8') + const manifest = JSON.parse(data) as FunctionsConfigManifest + + // https://github.com/vercel/next.js/blob/8367faedd61501025299e92d43a28393c7bb50e2/packages/next/src/build/index.ts#L2465 + // Node.js Middleware has hardcoded /_middleware path + if (manifest.functions['/_middleware']) { + throw new Error( + 'Only Edge Runtime Middleware is supported. Node.js Middleware is not supported.', + ) + } +} + export const verifyHandlerDirStructure = async (ctx: PluginContext) => { const { nextConfig } = JSON.parse( await readFile(join(ctx.serverHandlerDir, RUN_CONFIG_FILE), 'utf-8'), diff --git a/tests/fixtures/middleware-node/app/layout.js b/tests/fixtures/middleware-node/app/layout.js new file mode 100644 index 0000000000..6565e7bafd --- /dev/null +++ b/tests/fixtures/middleware-node/app/layout.js @@ -0,0 +1,12 @@ +export const metadata = { + title: 'Simple Next App', + description: 'Description for Simple Next App', +} + +export default function RootLayout({ children }) { + return ( + + {children} + + ) +} diff --git a/tests/fixtures/middleware-node/app/page.js b/tests/fixtures/middleware-node/app/page.js new file mode 100644 index 0000000000..1a9fe06903 --- /dev/null +++ b/tests/fixtures/middleware-node/app/page.js @@ -0,0 +1,7 @@ +export default function Home() { + return ( +
+

Home

+
+ ) +} diff --git a/tests/fixtures/middleware-node/middleware.ts b/tests/fixtures/middleware-node/middleware.ts new file mode 100644 index 0000000000..064f5bb6c3 --- /dev/null +++ b/tests/fixtures/middleware-node/middleware.ts @@ -0,0 +1,9 @@ +import type { NextRequest } from 'next/server' + +export async function middleware(request: NextRequest) { + console.log('Node.js Middleware request:', request.method, request.nextUrl.pathname) +} + +export const config = { + runtime: 'nodejs', +} diff --git a/tests/fixtures/middleware-node/next.config.js b/tests/fixtures/middleware-node/next.config.js new file mode 100644 index 0000000000..24a4bdfa44 --- /dev/null +++ b/tests/fixtures/middleware-node/next.config.js @@ -0,0 +1,12 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + output: 'standalone', + eslint: { + ignoreDuringBuilds: true, + }, + experimental: { + nodeMiddleware: true, + }, +} + +module.exports = nextConfig diff --git a/tests/fixtures/middleware-node/package.json b/tests/fixtures/middleware-node/package.json new file mode 100644 index 0000000000..ce0360a5f4 --- /dev/null +++ b/tests/fixtures/middleware-node/package.json @@ -0,0 +1,20 @@ +{ + "name": "middleware-node", + "version": "0.1.0", + "private": true, + "scripts": { + "postinstall": "next build", + "dev": "next dev", + "build": "next build" + }, + "dependencies": { + "next": "latest", + "react": "18.2.0", + "react-dom": "18.2.0" + }, + "test": { + "dependencies": { + "next": ">=15.2.0" + } + } +} diff --git a/tests/integration/edge-handler.test.ts b/tests/integration/edge-handler.test.ts index 825ed6fac1..b3632a279c 100644 --- a/tests/integration/edge-handler.test.ts +++ b/tests/integration/edge-handler.test.ts @@ -4,6 +4,7 @@ import { type FixtureTestContext } from '../utils/contexts.js' import { createFixture, invokeEdgeFunction, runPlugin } from '../utils/fixture.js' import { generateRandomObjectID, startMockBlobStore } from '../utils/helpers.js' import { LocalServer } from '../utils/local-server.js' +import { nextVersionSatisfies } from '../utils/next-version-helpers.mjs' beforeEach(async (ctx) => { // set for each test a new deployID and siteID @@ -626,3 +627,13 @@ describe('page router', () => { expect(bodyFr.nextUrlLocale).toBe('fr') }) }) + +test.skipIf(!nextVersionSatisfies('>=15.2.0'))( + 'should throw an Not Supported error when node middleware is used', + async (ctx) => { + await createFixture('middleware-node', ctx) + await expect(runPlugin(ctx)).rejects.toThrow( + 'Only Edge Runtime Middleware is supported. Node.js Middleware is not supported.', + ) + }, +)