rsnext/errors/edge-dynamic-code-evaluation.md
Damien Simonin Feugas bef709bc74
fix(middleware): 'instanceof Function' is dynamic code false-positive (#41249)
## 🐛 What's in there?

`foo instanceof Function` is wrongly considered as Dynamic code evaluation by our static analyzer.
This PR fixes it.

- [ ] Related issues linked using `fixes #number`
- [x] Integration tests added
- [x] Errors have a helpful link attached, see `contributing.md`

## 🧪 How to reproduce?

1. Create a simple repro in `examples` folder:
   ```js
   // examples/instance-of-function/pages/index.js
   export default function Home() {
     return <h1>home</h1>
   }
   
   // examples/instance-of-function/middleware.js
   import { NextResponse } from 'next/server'
   
   export default async function handler() {
     console.log('is arrow a function?', (() => {}) instanceof Function)
     return NextResponse.next()
   }
   ```
1. build with next `pnpm next build examples/instance-of-function`
   > the build fails
1. rebuild next to include PR's fix `pnpm build`
1. build with new next `pnpm next build examples/instance-of-function`
   > the build works

## 📔 Notes to reviewers

`hooks.expression.for(`${prefix}Function`).tap(NAME, handleExpression)` is actually legacy code from the original implementation. It's used when finding `Function` regardless of how it is used. We only want to find `new Function()` or `Function()`, which `hooks.calls` and `hooks.new` are covering.

`eval instanceof Function` is perfectly legit code on the edge, despite its uselessness :lol-think: 

Because we got multiple people asking "how do I relax this error when my code contains unreachable dynamic code evaluation", I've copy-pasted details about `config.unstable_allowDynamic` into the error page. Because users do not always click links :blob_shrug:
2022-10-07 14:14:11 +00:00

1.9 KiB

Dynamic code evaluation is not available in Middlewares or Edge API Routes

Why This Error Occurred

eval(), new Function() or compiling WASM binaries dynamically is not allowed in Middlewares or Edge API Routes. Specifically, the following APIs are not supported:

  • eval()
  • new Function()
  • WebAssembly.compile
  • WebAssembly.instantiate with a buffer parameter

Possible Ways to Fix It

You can bundle your WASM binaries using import:

import { NextResponse } from 'next/server'
import squareWasm from './square.wasm?module'

export default async function middleware() {
  const m = await WebAssembly.instantiate(squareWasm)
  const answer = m.exports.square(9)

  const response = NextResponse.next()
  response.headers.set('x-square', answer.toString())
  return response
}

In rare cases, your code could contain (or import) some dynamic code evaluation statements which can not be reached at runtime and which can not be removed by treeshaking. You can relax the check to allow specific files with your Middleware or Edge API Route exported configuration:

export const config = {
  runtime: 'experimental-edge', // for Edge API Routes only
  unstable_allowDynamic: [
    '/lib/utilities.js', // allows a single file
    '/node_modules/function-bind/**', // use a glob to allow anything in the function-bind 3rd party module
  ],
}

unstable_allowDynamic is a glob, or an array of globs, ignoring dynamic code evaluation for specific files. The globs are relative to your application root folder.

Be warned that if these statements are executed on the Edge, they will throw and cause a runtime error.