From 67e63ffbc48f6389aa6441b5471df5ca46284f28 Mon Sep 17 00:00:00 2001 From: Michal Piechowiak Date: Wed, 19 Nov 2025 13:26:37 +0100 Subject: [PATCH 1/2] test: add smoke test case using: pnpm monorepo, base directory instead of package path and containing proxy / node middleware --- tests/smoke/deploy.test.ts | 11 +++++ .../app/next.config.js | 8 ++++ .../pnpm-monorepo-base-proxy/app/package.json | 13 ++++++ .../app/pages/index.js | 15 +++++++ .../pnpm-monorepo-base-proxy/app/proxy.ts | 6 +++ .../pnpm-monorepo-base-proxy/netlify.toml | 7 +++ .../pnpm-monorepo-base-proxy/package.json | 4 ++ .../pnpm-workspace.yaml | 2 + tests/utils/create-e2e-fixture.ts | 45 ++++++++++++++----- 9 files changed, 99 insertions(+), 12 deletions(-) create mode 100644 tests/smoke/fixtures/pnpm-monorepo-base-proxy/app/next.config.js create mode 100644 tests/smoke/fixtures/pnpm-monorepo-base-proxy/app/package.json create mode 100644 tests/smoke/fixtures/pnpm-monorepo-base-proxy/app/pages/index.js create mode 100644 tests/smoke/fixtures/pnpm-monorepo-base-proxy/app/proxy.ts create mode 100644 tests/smoke/fixtures/pnpm-monorepo-base-proxy/netlify.toml create mode 100644 tests/smoke/fixtures/pnpm-monorepo-base-proxy/package.json create mode 100644 tests/smoke/fixtures/pnpm-monorepo-base-proxy/pnpm-workspace.yaml diff --git a/tests/smoke/deploy.test.ts b/tests/smoke/deploy.test.ts index abee3ff93b..f7d3ab5592 100644 --- a/tests/smoke/deploy.test.ts +++ b/tests/smoke/deploy.test.ts @@ -49,6 +49,17 @@ if (nextVersionSatisfies('>=16.0.0')) { const body = await response.json() expect(body).toEqual({ proxy: true }) }) + + test('pnpm monorepo with proxy / node middleware with setup using base directory instead of package path', async () => { + // proxy ~= node middleware + const fixture = await selfCleaningFixtureFactories.pnpmMonorepoBaseProxy() + + const response = await fetch(fixture.url) + expect(response.status).toBe(200) + + const body = await response.json() + expect(body).toEqual({ proxy: true }) + }) } test('yarn@3 monorepo with pnpm linker', async () => { diff --git a/tests/smoke/fixtures/pnpm-monorepo-base-proxy/app/next.config.js b/tests/smoke/fixtures/pnpm-monorepo-base-proxy/app/next.config.js new file mode 100644 index 0000000000..8d2a9bf37a --- /dev/null +++ b/tests/smoke/fixtures/pnpm-monorepo-base-proxy/app/next.config.js @@ -0,0 +1,8 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + eslint: { + ignoreDuringBuilds: true, + }, +} + +module.exports = nextConfig diff --git a/tests/smoke/fixtures/pnpm-monorepo-base-proxy/app/package.json b/tests/smoke/fixtures/pnpm-monorepo-base-proxy/app/package.json new file mode 100644 index 0000000000..be9d2a6c85 --- /dev/null +++ b/tests/smoke/fixtures/pnpm-monorepo-base-proxy/app/package.json @@ -0,0 +1,13 @@ +{ + "name": "pnpm-monorepo-base-proxy-app", + "version": "0.1.0", + "private": true, + "scripts": { + "build": "next build" + }, + "dependencies": { + "next": "latest", + "react": "^18.2.0", + "react-dom": "^18.2.0" + } +} diff --git a/tests/smoke/fixtures/pnpm-monorepo-base-proxy/app/pages/index.js b/tests/smoke/fixtures/pnpm-monorepo-base-proxy/app/pages/index.js new file mode 100644 index 0000000000..70acbeca65 --- /dev/null +++ b/tests/smoke/fixtures/pnpm-monorepo-base-proxy/app/pages/index.js @@ -0,0 +1,15 @@ +export default function Home({ ssr }) { + return ( +
+
SSR: {ssr ? 'yes' : 'no'}
+
+ ) +} + +export const getServerSideProps = async () => { + return { + props: { + ssr: true, + }, + } +} diff --git a/tests/smoke/fixtures/pnpm-monorepo-base-proxy/app/proxy.ts b/tests/smoke/fixtures/pnpm-monorepo-base-proxy/app/proxy.ts new file mode 100644 index 0000000000..2cd076a129 --- /dev/null +++ b/tests/smoke/fixtures/pnpm-monorepo-base-proxy/app/proxy.ts @@ -0,0 +1,6 @@ +import type { NextRequest } from 'next/server' +import { NextResponse } from 'next/server' + +export async function proxy(request: NextRequest) { + return NextResponse.json({ proxy: true }) +} diff --git a/tests/smoke/fixtures/pnpm-monorepo-base-proxy/netlify.toml b/tests/smoke/fixtures/pnpm-monorepo-base-proxy/netlify.toml new file mode 100644 index 0000000000..374cfff2a1 --- /dev/null +++ b/tests/smoke/fixtures/pnpm-monorepo-base-proxy/netlify.toml @@ -0,0 +1,7 @@ +[build] +base = "app" +command = "pnpm run build" +publish = ".next" + +[[plugins]] +package = "@netlify/plugin-nextjs" diff --git a/tests/smoke/fixtures/pnpm-monorepo-base-proxy/package.json b/tests/smoke/fixtures/pnpm-monorepo-base-proxy/package.json new file mode 100644 index 0000000000..cb48cba417 --- /dev/null +++ b/tests/smoke/fixtures/pnpm-monorepo-base-proxy/package.json @@ -0,0 +1,4 @@ +{ + "name": "monorepo", + "private": true +} diff --git a/tests/smoke/fixtures/pnpm-monorepo-base-proxy/pnpm-workspace.yaml b/tests/smoke/fixtures/pnpm-monorepo-base-proxy/pnpm-workspace.yaml new file mode 100644 index 0000000000..5dddf2919f --- /dev/null +++ b/tests/smoke/fixtures/pnpm-monorepo-base-proxy/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +packages: + - 'app' diff --git a/tests/utils/create-e2e-fixture.ts b/tests/utils/create-e2e-fixture.ts index 961a446bfc..ff538ba59a 100644 --- a/tests/utils/create-e2e-fixture.ts +++ b/tests/utils/create-e2e-fixture.ts @@ -5,7 +5,7 @@ import { exec } from 'node:child_process' import { existsSync } from 'node:fs' import { appendFile, copyFile, mkdir, mkdtemp, readFile, rm } from 'node:fs/promises' import { tmpdir } from 'node:os' -import { dirname, join } from 'node:path' +import { dirname, join, relative } from 'node:path' import process from 'node:process' import { fileURLToPath } from 'node:url' import { cpus } from 'os' @@ -228,6 +228,14 @@ async function installRuntime( await rm(join(isolatedFixtureRoot, 'package-lock.json'), { force: true }) } + let relativePathToPackage = relative( + join(isolatedFixtureRoot, siteRelDir), + join(isolatedFixtureRoot, packageName), + ) + if (!relativePathToPackage.startsWith('.')) { + relativePathToPackage = `./${relativePathToPackage}` + } + switch (packageManger) { case 'npm': command = `npm install --ignore-scripts --no-audit --legacy-peer-deps ${packageName} ${ @@ -248,7 +256,7 @@ async function installRuntime( env['YARN_ENABLE_SCRIPTS'] = 'false' break case 'pnpm': - command = `pnpm add file:${join(isolatedFixtureRoot, packageName)} ${ + command = `pnpm add file:${relativePathToPackage} ${ workspaceRelPath ? `--filter ./${workspaceRelPath}` : '' } --ignore-scripts` break @@ -349,8 +357,8 @@ export async function deploySiteWithBuildbot( newZip.addLocalFolder(isolatedFixtureRoot, '', (entry) => { if ( // don't include node_modules / .git / publish dir in zip - entry.startsWith('node_modules') || - entry.startsWith('.git') || + entry.includes('node_modules') || + entry.includes('.git') || entry.startsWith(publishDirectory) ) { return false @@ -358,15 +366,18 @@ export async function deploySiteWithBuildbot( return true }) - const result = await fetch(`https://api.netlify.com/api/v1/sites/${siteId}/builds`, { - method: 'POST', - headers: { - 'Content-Type': 'application/zip', - Authorization: `Bearer ${process.env.NETLIFY_AUTH_TOKEN}`, + const result = await fetch( + `https://api.netlify.com/api/v1/sites/${siteId}/builds?clear_cache=true`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/zip', + Authorization: `Bearer ${process.env.NETLIFY_AUTH_TOKEN}`, + }, + // @ts-expect-error sigh, it works + body: newZip.toBuffer(), }, - // @ts-expect-error sigh, it works - body: newZip.toBuffer(), - }) + ) const { deploy_id } = await result.json() let didRunOnBuildStartCallback = false @@ -636,6 +647,16 @@ export const fixtureFactories = { publishDirectory: 'apps/site/.next', smoke: true, }), + pnpmMonorepoBaseProxy: () => + createE2EFixture('pnpm-monorepo-base-proxy', { + buildCommand: 'pnpm run build', + generateNetlifyToml: false, + packageManger: 'pnpm', + publishDirectory: '.next', + runtimeInstallationPath: 'app', + smoke: true, + useBuildbot: true, + }), dynamicCms: () => createE2EFixture('dynamic-cms'), after: () => createE2EFixture('after'), } From a10748f28c0b47e558b4dfc34f8e6391f613e250 Mon Sep 17 00:00:00 2001 From: Michal Piechowiak Date: Wed, 19 Nov 2025 11:43:36 +0100 Subject: [PATCH 2/2] fix: incorrect path of middleware nft in setups using base directory --- src/build/functions/edge.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/build/functions/edge.ts b/src/build/functions/edge.ts index a26ee857c9..773f0f212c 100644 --- a/src/build/functions/edge.ts +++ b/src/build/functions/edge.ts @@ -210,7 +210,7 @@ const copyHandlerDependenciesForNodeMiddleware = async (ctx: PluginContext) => { const entry = 'server/middleware.js' const nft = `${entry}.nft.json` - const nftFilesPath = join(process.cwd(), ctx.distDir, nft) + const nftFilesPath = join(ctx.publishDir, nft) const nftManifest = JSON.parse(await readFile(nftFilesPath, 'utf8')) const files: string[] = nftManifest.files.map((file: string) => join('server', file))