Skip to content

Commit c29381e

Browse files
authored
fix: handle node middleware bundling when pnpm is used (#3126)
1 parent 314da70 commit c29381e

File tree

3 files changed

+82
-31
lines changed

3 files changed

+82
-31
lines changed

src/build/functions/edge.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { cp, mkdir, readFile, rm, writeFile } from 'node:fs/promises'
1+
import { cp, mkdir, readdir, readFile, rm, stat, writeFile } from 'node:fs/promises'
22
import { dirname, join, relative } from 'node:path/posix'
33

44
import type { Manifest, ManifestFunction } from '@netlify/edge-functions'
@@ -259,14 +259,26 @@ const copyHandlerDependenciesForNodeMiddleware = async (ctx: PluginContext) => {
259259

260260
parts.push(`const virtualModules = new Map();`)
261261

262-
for (const file of files) {
263-
const srcPath = join(srcDir, file)
262+
const handleFileOrDirectory = async (fileOrDir: string) => {
263+
const srcPath = join(srcDir, fileOrDir)
264264

265-
const content = await readFile(srcPath, 'utf8')
265+
const stats = await stat(srcPath)
266+
if (stats.isDirectory()) {
267+
const filesInDir = await readdir(srcPath)
268+
for (const fileInDir of filesInDir) {
269+
await handleFileOrDirectory(join(fileOrDir, fileInDir))
270+
}
271+
} else {
272+
const content = await readFile(srcPath, 'utf8')
266273

267-
parts.push(
268-
`virtualModules.set(${JSON.stringify(join(commonPrefix, file))}, ${JSON.stringify(content)});`,
269-
)
274+
parts.push(
275+
`virtualModules.set(${JSON.stringify(join(commonPrefix, fileOrDir))}, ${JSON.stringify(content)});`,
276+
)
277+
}
278+
}
279+
280+
for (const file of files) {
281+
await handleFileOrDirectory(file)
270282
}
271283
parts.push(`registerCJSModules(import.meta.url, virtualModules);
272284

tests/e2e/middleware.test.ts

Lines changed: 59 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -569,33 +569,68 @@ for (const { expectedRuntime, isNodeMiddleware, label, testWithSwitchableMiddlew
569569
if (isNodeMiddleware) {
570570
// Node.js Middleware specific tests to test features not available in Edge Runtime
571571
test.describe('Node.js Middleware specific', () => {
572-
test('node:crypto module', async ({ middlewareNodeRuntimeSpecific }) => {
573-
const response = await fetch(`${middlewareNodeRuntimeSpecific.url}/test/crypto`)
574-
expect(response.status).toBe(200)
575-
const body = await response.json()
576-
expect(
577-
body.random,
578-
'random should have 16 random bytes generated with `randomBytes` function from node:crypto in hex format',
579-
).toMatch(/[0-9a-f]{32}/)
580-
})
572+
test.describe('npm package manager', () => {
573+
test('node:crypto module', async ({ middlewareNodeRuntimeSpecific }) => {
574+
const response = await fetch(`${middlewareNodeRuntimeSpecific.url}/test/crypto`)
575+
expect(response.status).toBe(200)
576+
const body = await response.json()
577+
expect(
578+
body.random,
579+
'random should have 16 random bytes generated with `randomBytes` function from node:crypto in hex format',
580+
).toMatch(/[0-9a-f]{32}/)
581+
})
581582

582-
test('node:http(s) module', async ({ middlewareNodeRuntimeSpecific }) => {
583-
const response = await fetch(`${middlewareNodeRuntimeSpecific.url}/test/http`)
584-
expect(response.status).toBe(200)
585-
const body = await response.json()
586-
expect(
587-
body.proxiedWithHttpRequest,
588-
'proxiedWithHttpRequest should be the result of `http.request` from node:http fetching static asset',
589-
).toStrictEqual({ hello: 'world' })
583+
test('node:http(s) module', async ({ middlewareNodeRuntimeSpecific }) => {
584+
const response = await fetch(`${middlewareNodeRuntimeSpecific.url}/test/http`)
585+
expect(response.status).toBe(200)
586+
const body = await response.json()
587+
expect(
588+
body.proxiedWithHttpRequest,
589+
'proxiedWithHttpRequest should be the result of `http.request` from node:http fetching static asset',
590+
).toStrictEqual({ hello: 'world' })
591+
})
592+
593+
test('node:path module', async ({ middlewareNodeRuntimeSpecific }) => {
594+
const response = await fetch(`${middlewareNodeRuntimeSpecific.url}/test/path`)
595+
expect(response.status).toBe(200)
596+
const body = await response.json()
597+
expect(
598+
body.joined,
599+
'joined should be the result of `join` function from node:path',
600+
).toBe('a/b')
601+
})
590602
})
591603

592-
test('node:path module', async ({ middlewareNodeRuntimeSpecific }) => {
593-
const response = await fetch(`${middlewareNodeRuntimeSpecific.url}/test/path`)
594-
expect(response.status).toBe(200)
595-
const body = await response.json()
596-
expect(body.joined, 'joined should be the result of `join` function from node:path').toBe(
597-
'a/b',
598-
)
604+
test.describe('pnpm package manager', () => {
605+
test('node:crypto module', async ({ middlewareNodeRuntimeSpecificPnpm }) => {
606+
const response = await fetch(`${middlewareNodeRuntimeSpecificPnpm.url}/test/crypto`)
607+
expect(response.status).toBe(200)
608+
const body = await response.json()
609+
expect(
610+
body.random,
611+
'random should have 16 random bytes generated with `randomBytes` function from node:crypto in hex format',
612+
).toMatch(/[0-9a-f]{32}/)
613+
})
614+
615+
test('node:http(s) module', async ({ middlewareNodeRuntimeSpecificPnpm }) => {
616+
const response = await fetch(`${middlewareNodeRuntimeSpecificPnpm.url}/test/http`)
617+
expect(response.status).toBe(200)
618+
const body = await response.json()
619+
expect(
620+
body.proxiedWithHttpRequest,
621+
'proxiedWithHttpRequest should be the result of `http.request` from node:http fetching static asset',
622+
).toStrictEqual({ hello: 'world' })
623+
})
624+
625+
test('node:path module', async ({ middlewareNodeRuntimeSpecificPnpm }) => {
626+
const response = await fetch(`${middlewareNodeRuntimeSpecificPnpm.url}/test/path`)
627+
expect(response.status).toBe(200)
628+
const body = await response.json()
629+
expect(
630+
body.joined,
631+
'joined should be the result of `join` function from node:path',
632+
).toBe('a/b')
633+
})
599634
})
600635
})
601636
}

tests/utils/create-e2e-fixture.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,10 @@ export const fixtureFactories = {
345345
publishDirectory: '.next-node-middleware',
346346
}),
347347
middlewareNodeRuntimeSpecific: () => createE2EFixture('middleware-node-runtime-specific'),
348+
middlewareNodeRuntimeSpecificPnpm: () =>
349+
createE2EFixture('middleware-node-runtime-specific', {
350+
packageManger: 'pnpm',
351+
}),
348352
middlewareI18n: () => createE2EFixture('middleware-i18n'),
349353
middlewareI18nNode: () =>
350354
createE2EFixture('middleware-i18n', {

0 commit comments

Comments
 (0)