Skip to content

Commit cd66e76

Browse files
authored
Skip build-time dynamic code checks for specific polyfills in the Edge runtime (#52009)
As discussed in https://vercel.slack.com/archives/C03ENM5HB4K/p1687999628589119 and #51910, it makes sense to have a known list for packages (mostly polyfills) that we know are having dynamic code (`eval`, `new Function`) but are safe to run in the Edge Runtime because that dynamic code will never be executed.
1 parent 6cb6092 commit cd66e76

File tree

3 files changed

+56
-0
lines changed

3 files changed

+56
-0
lines changed

packages/next/src/build/webpack/plugins/middleware-plugin.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { getModuleBuildInfo } from '../loaders/get-module-build-info'
99
import { getSortedRoutes } from '../../../shared/lib/router/utils'
1010
import { webpack, sources } from 'next/dist/compiled/webpack/webpack'
1111
import { isMatch } from 'next/dist/compiled/micromatch'
12+
import path from 'path'
1213
import {
1314
EDGE_RUNTIME_WEBPACK,
1415
EDGE_UNSUPPORTED_NODE_APIS,
@@ -29,6 +30,9 @@ import { normalizeAppPath } from '../../../shared/lib/router/utils/app-paths'
2930
import { INSTRUMENTATION_HOOK_FILENAME } from '../../../lib/constants'
3031
import { NextBuildContext } from '../../build-context'
3132

33+
const KNOWN_SAFE_DYNAMIC_PACKAGES =
34+
require('../../../lib/known-edge-safe-packages.json') as string[]
35+
3236
export interface EdgeFunctionDefinition {
3337
files: string[]
3438
name: string
@@ -249,6 +253,16 @@ function isDynamicCodeEvaluationAllowed(
249253
middlewareConfig?: MiddlewareConfig,
250254
rootDir?: string
251255
) {
256+
// Some packages are known to use `eval` but are safe to use in the Edge
257+
// Runtime because the dynamic code will never be executed.
258+
if (
259+
KNOWN_SAFE_DYNAMIC_PACKAGES.some((pkg) =>
260+
fileName.includes(`/node_modules/${pkg}/`.replace(/\//g, path.sep))
261+
)
262+
) {
263+
return true
264+
}
265+
252266
const name = fileName.replace(rootDir ?? '', '')
253267
return isMatch(name, middlewareConfig?.unstable_allowDynamicGlobs ?? [])
254268
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
["function-bind"]
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { createNext } from 'e2e-utils'
2+
import { NextInstance } from 'test/lib/next-modes/base'
3+
4+
// This test is basically for https://github.com/vercel/next.js/discussions/51910
5+
// to make sure that some libs that we know are using `eval` but don't break
6+
// because it will never run into that condition, but still can't to be DCE'd.
7+
8+
describe('Edge safe dynamic code', () => {
9+
let next: NextInstance
10+
11+
afterAll(() => next.destroy())
12+
13+
it('should not fail when "function-bind" package is used', async () => {
14+
next = await createNext({
15+
skipStart: true,
16+
dependencies: {
17+
'function-bind': 'latest',
18+
},
19+
files: {
20+
'pages/index.js': `
21+
export default function Page() {
22+
return <p>hello world</p>
23+
}
24+
`,
25+
'middleware.js': `
26+
import { NextResponse } from 'next/server'
27+
import * as bind from 'function-bind'
28+
console.log(bind)
29+
export default async function middleware(request) {
30+
return NextResponse.next()
31+
}
32+
`,
33+
},
34+
})
35+
await next.start()
36+
37+
expect(next.cliOutput).not.toContain(
38+
`Dynamic Code Evaluation (e. g. 'eval', 'new Function', 'WebAssembly.compile') not allowed in Edge Runtime`
39+
)
40+
})
41+
})

0 commit comments

Comments
 (0)