Skip to content

Commit

Permalink
fix node.js module warning in middleware (#65112)
Browse files Browse the repository at this point in the history
`server-utils` should not be imported into middleware as it contains
imports that won't work in the edge runtime. Those imports aren't
technically used, but it was causing a warning nonetheless.

This adds a regression test to confirm the warning is only present when
actually importing a Node.js module in userland.

Closes NEXT-3246

<!-- Thanks for opening a PR! Your contribution is much appreciated.
To make sure your PR is handled as smoothly as possible we request that
you follow the checklist sections below.
Choose the right checklist for the change(s) that you're making:

## For Contributors

### Improving Documentation

- Run `pnpm prettier-fix` to fix formatting issues before opening the
PR.
- Read the Docs Contribution Guide to ensure your contribution follows
the docs guidelines:
https://nextjs.org/docs/community/contribution-guide

### Adding or Updating Examples

- The "examples guidelines" are followed from our contributing doc
https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md
- Make sure the linting passes by running `pnpm build && pnpm lint`. See
https://github.com/vercel/next.js/blob/canary/contributing/repository/linting.md

### Fixing a bug

- Related issues linked using `fixes #number`
- Tests added. See:
https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs
- Errors have a helpful link attached, see
https://github.com/vercel/next.js/blob/canary/contributing.md

### Adding a feature

- Implements an existing feature request or RFC. Make sure the feature
request has been accepted for implementation before opening a PR. (A
discussion must be opened, see
https://github.com/vercel/next.js/discussions/new?category=ideas)
- Related issues/discussions are linked using `fixes #number`
- e2e tests added
(https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs)
- Documentation added
- Telemetry added. In case of a feature if it's used or not.
- Errors have a helpful link attached, see
https://github.com/vercel/next.js/blob/canary/contributing.md


## For Maintainers

- Minimal description (aim for explaining to someone not on the team to
understand the PR)
- When linking to a Slack thread, you might want to share details of the
conclusion
- Link both the Linear (Fixes NEXT-xxx) and the GitHub issues
- Add review comments if necessary to explain to the reviewer the logic
behind a change

### What?

### Why?

### How?

Closes NEXT-
Fixes #

-->
  • Loading branch information
ztanner committed Apr 27, 2024
1 parent 5897fc0 commit 3050f45
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 21 deletions.
3 changes: 2 additions & 1 deletion packages/next/src/server/base-server.ts
Expand Up @@ -70,7 +70,7 @@ import { removeTrailingSlash } from '../shared/lib/router/utils/remove-trailing-
import { denormalizePagePath } from '../shared/lib/page-path/denormalize-page-path'
import * as Log from '../build/output/log'
import escapePathDelimiters from '../shared/lib/router/utils/escape-path-delimiters'
import { getUtils, normalizeNextQueryParam } from './server-utils'
import { getUtils } from './server-utils'
import isError, { getProperError } from '../lib/is-error'
import {
addRequestMeta,
Expand Down Expand Up @@ -109,6 +109,7 @@ import { sendResponse } from './send-response'
import { handleInternalServerErrorResponse } from './future/route-modules/helpers/response-handlers'
import {
fromNodeOutgoingHttpHeaders,
normalizeNextQueryParam,
toNodeOutgoingHttpHeaders,
} from './web/utils'
import { CACHE_ONE_YEAR, NEXT_CACHE_TAGS_HEADER } from '../lib/constants'
Expand Down
18 changes: 0 additions & 18 deletions packages/next/src/server/server-utils.ts
Expand Up @@ -55,24 +55,6 @@ export function normalizeVercelUrl(
}
}

/**
* Normalizes `nxtP` and `nxtI` query param values to remove the prefix.
* This function does not mutate the input key; it calls the provided function
* with the normalized key.
*/
export function normalizeNextQueryParam(
key: string,
onKeyNormalized: (normalizedKey: string) => void
) {
const prefixes = [NEXT_QUERY_PARAM_PREFIX, NEXT_INTERCEPTION_MARKER_PREFIX]
for (const prefix of prefixes) {
if (key !== prefix && key.startsWith(prefix)) {
const normalizedKey = key.substring(prefix.length)
onKeyNormalized(normalizedKey)
}
}
}

export function interpolateDynamicPath(
pathname: string,
params: ParsedUrlQuery,
Expand Down
3 changes: 1 addition & 2 deletions packages/next/src/server/web/adapter.ts
Expand Up @@ -2,7 +2,7 @@ import type { RequestData, FetchEventResult } from './types'
import type { RequestInit } from './spec-extension/request'
import type { PrerenderManifest } from '../../build'
import { PageSignatureError } from './error'
import { fromNodeOutgoingHttpHeaders } from './utils'
import { fromNodeOutgoingHttpHeaders, normalizeNextQueryParam } from './utils'
import { NextFetchEvent } from './spec-extension/fetch-event'
import { NextRequest } from './spec-extension/request'
import { NextResponse } from './spec-extension/response'
Expand All @@ -18,7 +18,6 @@ import { requestAsyncStorage } from '../../client/components/request-async-stora
import { getTracer } from '../lib/trace/tracer'
import type { TextMapGetter } from 'next/dist/compiled/@opentelemetry/api'
import { MiddlewareSpan } from '../lib/trace/constants'
import { normalizeNextQueryParam } from '../server-utils'

export class NextRequestHint extends NextRequest {
sourcePage: string
Expand Down
22 changes: 22 additions & 0 deletions packages/next/src/server/web/utils.ts
@@ -1,4 +1,8 @@
import type { OutgoingHttpHeaders } from 'http'
import {
NEXT_INTERCEPTION_MARKER_PREFIX,
NEXT_QUERY_PARAM_PREFIX,
} from '../../lib/constants'

/**
* Converts a Node.js IncomingHttpHeaders object to a Headers object. Any
Expand Down Expand Up @@ -146,3 +150,21 @@ export function validateURL(url: string | URL): string {
)
}
}

/**
* Normalizes `nxtP` and `nxtI` query param values to remove the prefix.
* This function does not mutate the input key; it calls the provided function
* with the normalized key.
*/
export function normalizeNextQueryParam(
key: string,
onKeyNormalized: (normalizedKey: string) => void
) {
const prefixes = [NEXT_QUERY_PARAM_PREFIX, NEXT_INTERCEPTION_MARKER_PREFIX]
for (const prefix of prefixes) {
if (key !== prefix && key.startsWith(prefix)) {
const normalizedKey = key.substring(prefix.length)
onKeyNormalized(normalizedKey)
}
}
}
@@ -0,0 +1,68 @@
import { nextTestSetup } from 'e2e-utils'

describe('app edge middleware', () => {
describe('without node.js modules', () => {
const { next } = nextTestSetup({
files: {
'app/page.js': `
export default function Page() {
return <p>hello world</p>
}
`,
'app/layout.js': `
export default function Root({ children }) {
return (
<html>
<body>
{children}
</body>
</html>
)
}
`,
'middleware.js': `
import { NextResponse } from 'next/server';
export async function middleware() {
return NextResponse.next()
}
`,
},
})
it('should not have any errors about using Node.js modules if not present in middleware', async () => {
expect(next.cliOutput).not.toContain('node-module-in-edge-runtime')
})
})

describe('with node.js modules', () => {
const { next } = nextTestSetup({
files: {
'app/page.js': `
export default function Page() {
return <p>hello world</p>
}
`,
'app/layout.js': `
export default function Root({ children }) {
return (
<html>
<body>
{children}
</body>
</html>
)
}
`,
'middleware.js': `
import { NextResponse } from 'next/server';
import { parse } from 'url';
export async function middleware() {
return NextResponse.next()
}
`,
},
})
it('should have errors about using Node.js modules when present in middleware', async () => {
expect(next.cliOutput).toContain('node-module-in-edge-runtime')
})
})
})
11 changes: 11 additions & 0 deletions test/turbopack-build-tests-manifest.json
Expand Up @@ -14615,6 +14615,17 @@
"flakey": [],
"runtimeError": false
},
"test/production/app-dir/app-edge-middleware/app-edge-middleware.test.ts": {
"passed": [
"app edge middleware without node.js modules should not have any errors about using Node.js modules if not present in middleware"
],
"failed": [
"app edge middleware with node.js modules should have errors about using Node.js modules when present in middleware"
],
"pending": [],
"flakey": [],
"runtimeError": false
},
"test/production/app-dir/app-fetch-build-cache/app-fetch-build-cache.test.ts": {
"passed": [
"app fetch build cache should have done initial build",
Expand Down

0 comments on commit 3050f45

Please sign in to comment.