ljharb / qs

A querystring parser with nesting support
BSD 3-Clause "New" or "Revised" License
8.47k stars 731 forks source link

Does not work in NextJS edge middleware #477

Closed chfoidl closed 1 year ago

chfoidl commented 1 year ago

Using the qs library or any other module that depends on qs for that matter does not work when importing in a NextJS edge middleware.

It results in the following error message:

Failed to compile.

../../node_modules/.pnpm/function-bind@1.1.1/node_modules/function-bind/implementation.js
Dynamic Code Evaluation (e. g. 'eval', 'new Function', 'WebAssembly.compile') not allowed in Edge Runtime
Learn More: https://nextjs.org/docs/messages/edge-dynamic-code-evaluation

Import trace for requested module:
../../node_modules/.pnpm/function-bind@1.1.1/node_modules/function-bind/implementation.js
../../node_modules/.pnpm/function-bind@1.1.1/node_modules/function-bind/index.js
../../node_modules/.pnpm/get-intrinsic@1.2.1/node_modules/get-intrinsic/index.js
../../node_modules/.pnpm/side-channel@1.0.4/node_modules/side-channel/index.js
../../node_modules/.pnpm/qs@6.11.2/node_modules/qs/lib/stringify.js
../../node_modules/.pnpm/qs@6.11.2/node_modules/qs/lib/index.js

I have created a tiny demo project that depicts this problem: https://codesandbox.io/p/sandbox/affectionate-turing-hy2rwl

ljharb commented 1 year ago

Sounds like it's a restriction of Edge Runtime. It should probably do this by default, but for an environment in which you know that Function.prototype.bind exists, you can replace function-bind with module.exports = Function.bind with your build tool, and that should resolve the problem.

ljharb commented 1 year ago

See https://github.com/vercel/next.js/pull/52009 for that fix.

chfoidl commented 1 year ago

Thanks for pointing me in the right direction!

Here is what I did to get this working in NextJS:

  1. Create a new file function-bind.cjs:

    module.exports = Function.bind;
  2. Update webpack config in next.config.js:

module.exports = {
  // ...
  webpack: (config, context) => {
    if (context.nextRuntime === "edge") {=
      // Assuming the function-bind.cjs file is in your 
      // NextJS project root.
      config.resolve.alias["function-bind$"] =
        require.resolve("./function-bind.cjs");
    }

    return config;
  },
};

When using ESM for next.config.js

import { createRequire } from 'module';
const require = createRequire(import.meta.url);

export default {
  // ...
  webpack: (config, context) => {
    if (context.nextRuntime === "edge") {=
      // Assuming the function-bind.cjs file is in your 
      // NextJS project root.
      config.resolve.alias["function-bind$"] =
        require.resolve("./function-bind.cjs");
    }

    return config;
  },
};