Skip to content

Commit 42eeab8

Browse files
authored
fix: handle edge runtime pages and middleware for turbopack builds (#3009)
* test: make sure we do SSR to ensure rendering fully works, add edge runtime page * fix: make sure to glob edge/chunks for edge runtime pages * test: add middleware to turbopack fixture * fix: adjust middleware setup to work with turbopack builds
1 parent 22fdac1 commit 42eeab8

File tree

7 files changed

+77
-14
lines changed

7 files changed

+77
-14
lines changed

edge-runtime/shim/index.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,8 @@ globalThis.require = function nextRuntimeMinimalRequireShim(name) {
3636
}
3737

3838
var _ENTRIES = {}
39+
try {
40+
// turbopack builds use self._ENTRIES not globalThis._ENTRIES
41+
// so making sure both points to same object
42+
self._ENTRIES = _ENTRIES
43+
} catch {}

src/build/content/server.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ export const copyNextServerCode = async (ctx: PluginContext): Promise<void> => {
105105
`server/*`,
106106
`server/chunks/**/*`,
107107
`server/edge-chunks/**/*`,
108+
`server/edge/chunks/**/*`,
108109
`server/+(app|pages)/**/*.js`,
109110
],
110111
{

src/build/functions/edge.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,15 @@ const copyHandlerDependencies = async (
150150
const entrypoint = await readFile(join(srcDir, file), 'utf8')
151151
parts.push(`;// Concatenated file: ${file} \n`, entrypoint)
152152
}
153-
const exports = `const middlewareEntryKey = Object.keys(_ENTRIES).find(entryKey => entryKey.startsWith("middleware_${name}")); export default _ENTRIES[middlewareEntryKey].default;`
153+
parts.push(
154+
`const middlewareEntryKey = Object.keys(_ENTRIES).find(entryKey => entryKey.startsWith("middleware_${name}"));`,
155+
// turbopack entries are promises so we await here to get actual entry
156+
// non-turbopack entries are already resolved, so await does not change anything
157+
`export default await _ENTRIES[middlewareEntryKey].default;`,
158+
)
154159
await mkdir(dirname(outputFile), { recursive: true })
155160

156-
await writeFile(outputFile, [...parts, exports].join('\n'))
161+
await writeFile(outputFile, parts.join('\n'))
157162
}
158163

159164
const createEdgeHandler = async (ctx: PluginContext, definition: NextDefinition): Promise<void> => {
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { connection } from 'next/server'
2+
3+
export const runtime = 'edge'
4+
5+
export default async function Page() {
6+
await connection()
7+
return <h1>Hello, Next.js!</h1>
8+
}
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1-
export default function Page() {
1+
import { connection } from 'next/server'
2+
3+
export default async function Page() {
4+
await connection()
25
return <h1>Hello, Next.js!</h1>
36
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import type { NextRequest } from 'next/server'
2+
import { NextResponse } from 'next/server'
3+
4+
export function middleware(request: NextRequest) {
5+
return NextResponse.json({
6+
message: `Hello from middleware at ${request.nextUrl.pathname}`,
7+
})
8+
}
9+
10+
export const config = {
11+
matcher: '/middleware/:path*',
12+
}

tests/integration/hello-world-turbopack.test.ts

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import { getLogger } from 'lambda-local'
33
import { HttpResponse, http, passthrough } from 'msw'
44
import { setupServer } from 'msw/node'
55
import { v4 } from 'uuid'
6-
import { afterAll, afterEach, beforeAll, beforeEach, expect, test, vi } from 'vitest'
6+
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest'
77
import { type FixtureTestContext } from '../utils/contexts.js'
8-
import { createFixture, invokeFunction, runPlugin } from '../utils/fixture.js'
8+
import { createFixture, invokeEdgeFunction, invokeFunction, runPlugin } from '../utils/fixture.js'
99
import { generateRandomObjectID, startMockBlobStore } from '../utils/helpers.js'
1010
import { nextVersionSatisfies } from '../utils/next-version-helpers.mjs'
1111

@@ -63,15 +63,44 @@ afterEach(() => {
6363

6464
// https://github.com/vercel/next.js/pull/77808 makes turbopack builds no longer gated only to canaries
6565
// allowing to run this test on both stable and canary versions of Next.js
66-
test.skipIf(!nextVersionSatisfies('>=15.3.0-canary.43'))<FixtureTestContext>(
66+
describe.skipIf(!nextVersionSatisfies('>=15.3.0-canary.43'))(
6767
'Test that the hello-world-turbopack next app is working',
68-
async (ctx) => {
69-
await createFixture('hello-world-turbopack', ctx)
70-
await runPlugin(ctx)
71-
72-
// test the function call
73-
const home = await invokeFunction(ctx)
74-
expect(home.statusCode).toBe(200)
75-
expect(load(home.body)('h1').text()).toBe('Hello, Next.js!')
68+
() => {
69+
test<FixtureTestContext>('regular page is working', async (ctx) => {
70+
await createFixture('hello-world-turbopack', ctx)
71+
await runPlugin(ctx)
72+
73+
// test the function call
74+
const home = await invokeFunction(ctx)
75+
expect(home.statusCode).toBe(200)
76+
expect(load(home.body)('h1').text()).toBe('Hello, Next.js!')
77+
})
78+
79+
test<FixtureTestContext>('edge page is working', async (ctx) => {
80+
await createFixture('hello-world-turbopack', ctx)
81+
await runPlugin(ctx)
82+
83+
// test the function call
84+
const home = await invokeFunction(ctx, { url: '/edge-page' })
85+
expect(home.statusCode).toBe(200)
86+
expect(load(home.body)('h1').text()).toBe('Hello, Next.js!')
87+
})
88+
89+
test<FixtureTestContext>('middleware is working', async (ctx) => {
90+
await createFixture('hello-world-turbopack', ctx)
91+
await runPlugin(ctx)
92+
93+
const pathname = '/middleware/test'
94+
95+
const response = await invokeEdgeFunction(ctx, {
96+
functions: ['___netlify-edge-handler-middleware'],
97+
url: pathname,
98+
})
99+
100+
expect(response.status).toBe(200)
101+
expect(await response.json()).toEqual({
102+
message: `Hello from middleware at ${pathname}`,
103+
})
104+
})
76105
},
77106
)

0 commit comments

Comments
 (0)