Skip to content

Commit 3efc842

Browse files
committed
Fix next/server apit push alias for ESM pkg (#61721)
We have a modularize imports config for `next/server` before, which will transform the `next/server` imports to directly import from the actual file, for instance: `import { NextRequest } from 'next/server'` will become `import { NextRequest } from 'next/dist/server/web/exports/next-request'`, where the NextRequest is exported as default export. This is fine in most case until you're using a ESM pkg, then it will be resolved as `{ default: NextRequest }` according to the spec. Since it's a ESM import to a CJS module in `next/dist`. Since we already have the ESM alias introduced in #59852 , this can handle the case more properly. Remove the modularize imports config for `next/server`, use the ESM api alias instead. Migrate the cjs optimizer tests from middleware to a separate endpoint `/cjs/server`. As now ESM imports for next/server are not going to get tree-shaken in dev, but since we don't have image response there it's still fine. Closes NEXT-2376 Closes NEXT-2374
1 parent 179d14e commit 3efc842

20 files changed

+47
-42
lines changed

packages/next/server.js

+2-5
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,8 @@ const serverExports = {
99
.userAgentFromString,
1010
userAgent: require('next/dist/server/web/spec-extension/user-agent')
1111
.userAgent,
12-
}
13-
14-
if (typeof URLPattern !== 'undefined') {
15-
// eslint-disable-next-line no-undef
16-
serverExports.URLPattern = URLPattern
12+
URLPattern: require('next/dist/server/web/spec-extension/url-pattern')
13+
.URLPattern,
1714
}
1815

1916
// https://nodejs.org/api/esm.html#commonjs-namespaces

packages/next/src/build/create-compiler-aliases.ts

+1
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ export function createNextApiEsmAliases() {
205205
navigation: 'next/dist/api/navigation',
206206
headers: 'next/dist/api/headers',
207207
og: 'next/dist/api/og',
208+
server: 'next/dist/api/server',
208209
// pages api
209210
document: 'next/dist/api/document',
210211
app: 'next/dist/api/app',

packages/next/src/server/config.ts

-3
Original file line numberDiff line numberDiff line change
@@ -831,9 +831,6 @@ function assignDefaults(
831831
lodash: {
832832
transform: 'lodash/{{member}}',
833833
},
834-
'next/server': {
835-
transform: 'next/dist/server/web/exports/{{ kebabCase member }}',
836-
},
837834
}
838835

839836
const userProvidedOptimizePackageImports =

packages/next/src/server/web/exports/image-response.ts

-2
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
// Alias index file of next/server for edge runtime for tree-shaking purpose
22

3-
export { default as ImageResponse } from './image-response'
4-
export { default as NextRequest } from './next-request'
5-
export { default as NextResponse } from './next-response'
6-
export { default as userAgent } from './user-agent'
7-
export { default as userAgentFromString } from './user-agent-from-string'
8-
export { default as URLPattern } from './url-pattern'
3+
export { ImageResponse } from '../spec-extension/image-response'
4+
export { NextRequest } from '../spec-extension/request'
5+
export { NextResponse } from '../spec-extension/response'
6+
export { userAgent, userAgentFromString } from '../spec-extension/user-agent'
7+
export { URLPattern } from '../spec-extension/url-pattern'

packages/next/src/server/web/exports/next-request.ts

-2
This file was deleted.

packages/next/src/server/web/exports/next-response.ts

-2
This file was deleted.

packages/next/src/server/web/exports/revalidate-path.ts

-2
This file was deleted.

packages/next/src/server/web/exports/revalidate-tag.ts

-2
This file was deleted.

packages/next/src/server/web/exports/unstable-cache.ts

-2
This file was deleted.

packages/next/src/server/web/exports/unstable-no-store.ts

-2
This file was deleted.

packages/next/src/server/web/exports/user-agent-from-string.ts

-2
This file was deleted.

packages/next/src/server/web/exports/user-agent.ts

-2
This file was deleted.

packages/next/src/server/web/exports/url-pattern.ts renamed to packages/next/src/server/web/spec-extension/url-pattern.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ const GlobalURLPattern =
22
// @ts-expect-error: URLPattern is not available in Node.js
33
typeof URLPattern === 'undefined' ? undefined : URLPattern
44

5-
export default GlobalURLPattern
5+
export { GlobalURLPattern as URLPattern }

test/e2e/app-dir/app-external/app-external.test.ts

+15-4
Original file line numberDiff line numberDiff line change
@@ -264,11 +264,13 @@ createNextDescribe(
264264
})
265265

266266
it('should have proper tree-shaking for known modules in CJS', async () => {
267-
const html = await next.render('/test-middleware')
268-
expect(html).toContain('it works')
267+
const html = await next.render('/cjs/server')
268+
expect(html).toContain('resolve response')
269269

270-
const middlewareBundle = await next.readFile('.next/server/middleware.js')
271-
expect(middlewareBundle).not.toContain('image-response')
270+
const outputFile = await next.readFile(
271+
'.next/server/app/cjs/server/page.js'
272+
)
273+
expect(outputFile).not.toContain('image-response')
272274
})
273275

274276
it('should use the same async storages if imported directly', async () => {
@@ -301,5 +303,14 @@ createNextDescribe(
301303
}, /success/)
302304
})
303305
})
306+
307+
describe('app route', () => {
308+
it('should resolve next/server api from external esm package', async () => {
309+
const res = await next.fetch('/app-routes')
310+
const text = await res.text()
311+
expect(res.status).toBe(200)
312+
expect(text).toBe('get route')
313+
})
314+
})
304315
}
305316
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { serverApi } from 'server-api-esm'
2+
3+
export function GET(req) {
4+
serverApi(req)
5+
return new Response('get route')
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { createResponse } from 'next-server-cjs-lib'
2+
3+
export default async function Page() {
4+
const response = createResponse('resolve response')
5+
const text = await response.text()
6+
return <p>{text}</p>
7+
}
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
1-
import { createResponse } from 'next-server-cjs-lib'
21
import { respond } from 'compat-next-server-module'
32

43
export async function middleware(request) {
5-
if (request.nextUrl.pathname === '/test-middleware') {
6-
return createResponse('it works')
7-
}
8-
94
return await respond()
105
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { NextRequest } from 'next/server'
2+
3+
export function serverApi(req) {
4+
return new NextRequest(req)
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"name": "server-api-module",
3+
"type": "module",
4+
"exports": "./index.js"
5+
}

0 commit comments

Comments
 (0)