Skip to content

Commit

Permalink
Fix next/server apit push alias for ESM pkg (#61721)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
huozhi committed Feb 28, 2024
1 parent 179d14e commit 3efc842
Show file tree
Hide file tree
Showing 20 changed files with 47 additions and 42 deletions.
7 changes: 2 additions & 5 deletions packages/next/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,8 @@ const serverExports = {
.userAgentFromString,
userAgent: require('next/dist/server/web/spec-extension/user-agent')
.userAgent,
}

if (typeof URLPattern !== 'undefined') {
// eslint-disable-next-line no-undef
serverExports.URLPattern = URLPattern
URLPattern: require('next/dist/server/web/spec-extension/url-pattern')
.URLPattern,
}

// https://nodejs.org/api/esm.html#commonjs-namespaces
Expand Down
1 change: 1 addition & 0 deletions packages/next/src/build/create-compiler-aliases.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ export function createNextApiEsmAliases() {
navigation: 'next/dist/api/navigation',
headers: 'next/dist/api/headers',
og: 'next/dist/api/og',
server: 'next/dist/api/server',
// pages api
document: 'next/dist/api/document',
app: 'next/dist/api/app',
Expand Down
3 changes: 0 additions & 3 deletions packages/next/src/server/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -831,9 +831,6 @@ function assignDefaults(
lodash: {
transform: 'lodash/{{member}}',
},
'next/server': {
transform: 'next/dist/server/web/exports/{{ kebabCase member }}',
},
}

const userProvidedOptimizePackageImports =
Expand Down
2 changes: 0 additions & 2 deletions packages/next/src/server/web/exports/image-response.ts

This file was deleted.

11 changes: 5 additions & 6 deletions packages/next/src/server/web/exports/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
// Alias index file of next/server for edge runtime for tree-shaking purpose

export { default as ImageResponse } from './image-response'
export { default as NextRequest } from './next-request'
export { default as NextResponse } from './next-response'
export { default as userAgent } from './user-agent'
export { default as userAgentFromString } from './user-agent-from-string'
export { default as URLPattern } from './url-pattern'
export { ImageResponse } from '../spec-extension/image-response'
export { NextRequest } from '../spec-extension/request'
export { NextResponse } from '../spec-extension/response'
export { userAgent, userAgentFromString } from '../spec-extension/user-agent'
export { URLPattern } from '../spec-extension/url-pattern'
2 changes: 0 additions & 2 deletions packages/next/src/server/web/exports/next-request.ts

This file was deleted.

2 changes: 0 additions & 2 deletions packages/next/src/server/web/exports/next-response.ts

This file was deleted.

2 changes: 0 additions & 2 deletions packages/next/src/server/web/exports/revalidate-path.ts

This file was deleted.

2 changes: 0 additions & 2 deletions packages/next/src/server/web/exports/revalidate-tag.ts

This file was deleted.

2 changes: 0 additions & 2 deletions packages/next/src/server/web/exports/unstable-cache.ts

This file was deleted.

2 changes: 0 additions & 2 deletions packages/next/src/server/web/exports/unstable-no-store.ts

This file was deleted.

This file was deleted.

2 changes: 0 additions & 2 deletions packages/next/src/server/web/exports/user-agent.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ const GlobalURLPattern =
// @ts-expect-error: URLPattern is not available in Node.js
typeof URLPattern === 'undefined' ? undefined : URLPattern

export default GlobalURLPattern
export { GlobalURLPattern as URLPattern }
19 changes: 15 additions & 4 deletions test/e2e/app-dir/app-external/app-external.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,11 +264,13 @@ createNextDescribe(
})

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

const middlewareBundle = await next.readFile('.next/server/middleware.js')
expect(middlewareBundle).not.toContain('image-response')
const outputFile = await next.readFile(
'.next/server/app/cjs/server/page.js'
)
expect(outputFile).not.toContain('image-response')
})

it('should use the same async storages if imported directly', async () => {
Expand Down Expand Up @@ -301,5 +303,14 @@ createNextDescribe(
}, /success/)
})
})

describe('app route', () => {
it('should resolve next/server api from external esm package', async () => {
const res = await next.fetch('/app-routes')
const text = await res.text()
expect(res.status).toBe(200)
expect(text).toBe('get route')
})
})
}
)
6 changes: 6 additions & 0 deletions test/e2e/app-dir/app-external/app/app-routes/route.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { serverApi } from 'server-api-esm'

export function GET(req) {
serverApi(req)
return new Response('get route')
}
7 changes: 7 additions & 0 deletions test/e2e/app-dir/app-external/app/cjs/server/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { createResponse } from 'next-server-cjs-lib'

export default async function Page() {
const response = createResponse('resolve response')
const text = await response.text()
return <p>{text}</p>
}
5 changes: 0 additions & 5 deletions test/e2e/app-dir/app-external/middleware.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import { createResponse } from 'next-server-cjs-lib'
import { respond } from 'compat-next-server-module'

export async function middleware(request) {
if (request.nextUrl.pathname === '/test-middleware') {
return createResponse('it works')
}

return await respond()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { NextRequest } from 'next/server'

export function serverApi(req) {
return new NextRequest(req)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "server-api-module",
"type": "module",
"exports": "./index.js"
}

1 comment on commit 3efc842

@AkmaludinFitra
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commit

Please sign in to comment.