bgenc.net/content/posts/2023.08.13.nextjs-bindings-cannot-read-property-indexof-undefined-getFileName.md
Kaan Barmore-Genç d39d3ba79b
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
add nextjs native module bindings error
2023-08-13 11:56:53 -05:00

2.2 KiB

title date toc images tags
Next.js error about native node modules using bindings 2023-08-13T16:44:41Z false
dev

This might be a little niche, but I had trouble finding anyone else write about it so I might as well.

I was trying to use a native node module libheif-node-dy that uses bindings in a Next.js app, and I kept getting errors from bindings:

- error node_modules/.pnpm/bindings@1.5.0/node_modules/bindings/bindings.js (179:15) @ indexOf
- error Error [TypeError]: Cannot read properties of undefined (reading 'indexOf')
    at Function.getFileName (webpack-internal:///(rsc)/./node_modules/.pnpm/bindings@1.5.0/node_modules/bindings/bindings.js:193:18)
    at bindings (webpack-internal:///(rsc)/./node_modules/.pnpm/bindings@1.5.0/node_modules/bindings/bindings.js:130:52)

After a little digging, I came across this Github issue by Nicholas Ramz who diagnosed the issue down to the Webpack/Terser minimizer, which removes a line that looks like a no-op but is actually supposed to trigger an error stack. Bindings needs that to happen, otherwise you get this error.

The solution he suggested is that you change your Webpack config to disable that Terser optimization. This is sounds like a good solution, but it's a bit hard to apply to Next.js because I don't have a webpack config of myself. Next.js has it's Webpack config built-in, and while it allows you to override it the documentation is a little bare.

I found an easier solution for Next.js though: you can tell Next.js to not bundle a module. You can configure this with the serverComponentsExternalPackages option. My config file now looks like this:

/** @type {import('next').NextConfig} */
const nextConfig = {
  experimental: {    
    serverComponentsExternalPackages: ["libheif-node-dy"],
  },
};

module.exports = nextConfig;

And this immediately worked, the module no longer gets bundled but instead executed like a regular node module, which gets around this issue. Since native modules can't be bundled into a JS file anyway, I don't think you lose much by disabling bundling just for native modules anyway.