Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ERR_REQUIRE_ESM in Next.js app #1637

Closed
Jules-7 opened this issue Jan 23, 2023 · 44 comments
Closed

ERR_REQUIRE_ESM in Next.js app #1637

Jules-7 opened this issue Jan 23, 2023 · 44 comments

Comments

@Jules-7
Copy link

Jules-7 commented Jan 23, 2023

Import @visx/xycharts in a Next.js app returns the following error:

Error: require() of ES Module ~/app/node_modules/d3-scale/src/index.js from
~/app/node_modules/@visx/scale/lib/scales/band.js not supported.
Instead change the require of index.js in ~/app/node_modules/@visx/scale/lib/scales/band.js 
to a dynamic import() which is available in all CommonJS modules.

Used Node version 18.13.0, pacakge.json dependecies:

"dependencies": {
   ...
    "@visx/xychart": "^3.0.0",
    "next": "13.0.7",
    "react": "18.2.0",
    "react-dom": "18.2.0",
   ...
  },

Tested importing @visx/xycharts in a React app. Node version 18.13.0, package.json dependencies:

    ...
    "@visx/xychart": "^3.0.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    ...

No ERR_REQUIRE_ESM error when importing in a React app. Any idea how this error could be solved for a Next.js app? Maybe a configuration in nextjs.config.js?

@williaster
Copy link
Collaborator

Hi @Jules-7, sorry for the major version change here, this duplicates #1636 and is due to the breaking change #1621 that fixed some security vulnerabilities in d3. The resulting d3 dependencies have moved to ESM-only exports which is the ERR_REQUIRE_ESM you are seeing.

The visx demo site uses next and we had to update some of our config / upgrade to next@11 to support this as well:

  • add experimental.esmModules = true in next.config.js. However this should be the default behavior in next@12 and beyond (see the next docs here).
  • ^This should be enough to fix the problem, but it seems there's still an issue when a dependency of a dependency is using ESM modules (i.e., @visx/xychart using d3-scale), so we also had to add in next-transpile-modules and enumerate the problematic d3-* deps here.

There are a lot of next issues discussing similar problems which might also be useful to browse (e.g., vercel/next.js#27876)

Hope that helps, the ESM / CJS module stuff is likely going to be challenging in web dev for a while so would love to lean on the community to help share solutions that work for them across next versions 🙏

@Jules-7
Copy link
Author

Jules-7 commented Jan 24, 2023

Hi @williaster, thank you for your message.

I tried the following in next.config.js for next@13.1 to no avail:

const nextConfig = {
  transpilePackages: ['d3-scale'],
};

In next@13.1 module transpilation is built-in. Still got the same error.

Had to switch to @visx/xychart v2.18.0 to get it working.

@diginikkari
Copy link

I'm getting the same error when trying to test files having import from @visx/scale with vitest. Here is reproduction repo: https://github.com/diginikkari/visx-scale-esm-issue

@williaster
Copy link
Collaborator

@Jules-7 that's surprising, is there any chance there are other modules in addition to d3-scale that need transpiling? 2.18.0 should be a fine workaround, I'd just note that the d3 packages do have security vulnerabilities.

@diginikkari you'll have to add a proper transpiler to handle ESM modules in your tests for @visx/*@^3.0.0. You can see our jest config for inspiration.

Again, clarifying that this is not a visx issue, it's a change in the module ecosystem from d3-* which will unfortunately probably require tweaks to your dev infra to handle these ESM-only modules 😞

@diginikkari
Copy link

@williaster vitest should support esm modules natively, so is no need for transpiling.

I think that the issue is with invalid package.json. For package providing both commonjs and esm -modules there should be exports -field.

if I add following to @visx/scale -package file. Import from esm is working correctly:

  "exports": {
    ".": {
        "import":"./esm/index.js", 
        "require": "./lib/index.js"
    }
  },

@diginikkari
Copy link

@Jules-7 could you test, does it work with nextjs, if you modify your node_modules/@visx/xychart/package.json in your to have above exports?

@diginikkari
Copy link

I found good blog post regarding this Publish ESM and CJS in a single package

@Jules-7
Copy link
Author

Jules-7 commented Jan 25, 2023

@diginikkari I've tried adding exports to both @visx/scale and @visx/xychart package.json, unfortunately still getting the same error.

@williaster I find it very odd. Adding transpilePackages: ['d3-scale'], still returns exactly the same error:

Error: require() of ES Module ~/app/node_modules/d3-scale/src/index.js from
~/app/node_modules/@visx/scale/lib/scales/band.js not supported.
Instead change the require of index.js in ~/app/node_modules/@visx/scale/lib/scales/band.js 
to a dynamic import() which is available in all CommonJS modules.

I seems like it doesn't actually transpile.

@diginikkari
Copy link

@Jules-7 I think the problem comes from @visx/scale package not from d3-scale. Try to add @visx/scale to your transpilePackages.

The problem is that ~/app/node_modules/@visx/scale/lib/scales/band.js is from cjs and it's trying to use d3 ES Module. There is ESM version of @visx/scale available in ~/node_modules/@visx/scale/esm/scales/band.js. When I made that exports change, vitest was correctly able to use ESM version.

I think that client side code (e.g. React) is using ESM version of @visx/scale and therefore there is no error. Problem with next.js could be that when next.js is doing server rendering it's using node which is using CJS version. This is of course all my speculation so take it with grain of salt 🧂.

@jonambas
Copy link
Contributor

jonambas commented Jan 25, 2023

I'm still getting this on Next 13.1, I tried variations of the following in transpilePackages:

transpilePackages: ["@visx/scale", "d3-scale", "d3-interpolate"],

@williaster
Copy link
Collaborator

williaster commented Jan 26, 2023

Hey all, sorry I've been chatting with a few people to get their thoughts on this. I think @diginikkari is correct that basically visx export cjs + esm versions (under lib/ <-- the default as this is defined as main in our package.jsons, and esm/, respectively) – however now that d3- has esm-only packages we cannot effectively create cjs versions anymore because in our cjs version we import those esm modules which breaks everything unless they are transpiled somewhere 😞

So I think the suggestion to update our package.jsons with an export field will likely fix any systems where esm modules are supported (like vitest, and possibly the issue with transpilePackages in next.js), but this likely won't fix cjs infra setups and will still require transpiling d3-* packages.

My only thought for solving the cjs problem is that visx packages can update their imports of the problematic d3- packages to import(), but I'll need to test this to make sure it doesn't break other things. I am short on bandwidth but will try to land on a solution soon.

@williaster
Copy link
Collaborator

@ljharb it's been a while since you've 👀 on this project, but I'm curious if you have any suggestions for how to properly (or least-painfully) handle esm-only d3 dependencies we added in our 3.0.0 release. Does this effectively prevent us from shipping cjs versions of visx?

@ljharb
Copy link

ljharb commented Jan 26, 2023

@williaster yes - esm-only dependencies are user-hostile, because they ensure that everything using them synchronously must also be native ESM, and thus you can't ship CJS.

Your choices (in order of my recommendation) are:

  1. avoid using any packages that (or packages by maintainers who) go ESM-only, and find better alternatives
  2. permanently stay on pre-ESM versions of those packages, and/or fork the ESM-only versions
  3. try to use them asynchronously, via import() - this still creates potential problems for consumers who use bundlers, but hopefully minor ones
  4. go ESM-only yourself

There's simply no value in going ESM-only - native ESM in node still lacks most of the tooling and ecosystem support that CJS has - and I strongly suggest authoring in ESM but transpiling to CJS for the foreseeable future.

@camflan
Copy link

camflan commented Jan 26, 2023

Ugh, yeah - ESM-only libraries are so frustrating.

So where does this leave us Next.js users? Are we stuck on 2.18 for the foreseeable future?

@ljharb
Copy link

ljharb commented Jan 26, 2023

I'd be surprised if nextjs requires using native ESM, or any particular version of d3, so if this package's v3 depends on ESM-only versions, options 1-3 would be a non-semver-major update in the v3 line for this package, and I'd suggest going one of those routes.

@williaster
Copy link
Collaborator

Thanks for the great thoughts, Jordan 🙏 I agree going ESM-only would be the least ideal. Here are my thoughts on the other options

  1. Since d3-* are so fundamental to @visx/* I don't think this is feasible unfortunately
  2. d3 made the ESM-only decision quite a while ago and there have since been several security fixes I don't think they'll backwards-patch (the entire reason we upgraded to these ESM-only packages and released a major version bump was to fix a security vulnerability). One possible option we could consider here is using victory-vendor/d3-* packages. They faced a similar dllemma and decided to transpile & release their own CJS version of d3-* packages. This could be viable, my only concern is possible TS clashes and this wouldn't work for any future lib we depend on that went ESM-only
  3. I think this solution would be the simplest solution if it works, so is worth trying / would be the first thing I would try from here. I would note that we use next.js for our demo site, so we could test the feasibility ourselves with this.
  4. again, hoping that we can avoid this.

I am very limited on bandwidth the next couple of weeks, so if anyone would like to explore #3 I'd be happy to review/collaborate on a branch.

@alexmalev
Copy link

also looking for a solution for this. solved it temporarily by importing the component that uses @visx/xychart like so:

import dynamic from 'next/dynamic';
const MyLineChart = dynamic(() => import('./MyLineChart'), { ssr: false });

@peter-novak-m
Copy link

Thanks @alexmalev , I have been looking for a solution for this as well, and your fix is the only thing I found that did the trick!

@korompaiistvan
Copy link
Contributor

I'm running into the same issue and disabling ssr is not a viable option for me unfortunately.

just wanted to say that I checked if turbopack. Next.js's new bundler also produces this error and the answer is no.
unfortunately it is in alpha and produces a lot of different warnings for my app, but this specific error does not come up (and charts render correctly).

@korompaiistvan
Copy link
Contributor

I have manually replaced all instances of require("d3-scale") with import("d3-scale") in my project running next@13.2.4 and that fixed the problem for me together with adding the transpilePackages line to my next.config.js:

const nextConfig = {
  reactStrictMode: true,
  transpilePackages: ['d3-scale', '@visx/scale']
}

module.exports = nextConfig

while it is not ideal, one can use patch-package to save the manual changes and run them during automated deployment until the team figures out a stable solution.

@bradchristensen
Copy link

One possible option we could consider here is using victory-vendor/d3-* packages. They faced a similar dllemma and decided to transpile & release their own CJS version of d3-* packages. This could be viable, my only concern is possible TS clashes and this wouldn't work for any future lib we depend on that went ESM-only

@williaster just chiming in to say this actually sounds like the way to go in my opinion - encouraging to know there's prior art, and this would be a very simple, transparent solution with no downstream effect on the end user, other than perhaps an inflated bundle size if they still have other versions of d3-* packages lying around (but that would imply they have old versions that are still impacted by security problems). Probably even easier to implement (with a find/replace?) than switching to async imports?

Conversely, the async import option sounds like it would be another can of worms, depending on how the various bundlers behave (my understanding was that async imports typically turn into code split points, but I'm not sure if this is still true, or holds true within node_modules packages?). Certainly worth a try though.

@korompaiistvan
Copy link
Contributor

for anyone stumbling into this issue, here is a step-by-step of what worked for me on next13 using the pages router:

  1. install visx:
npm install @visx/visx
  1. add the following to next.config.js:
const nextConfig = {
  reactStrictMode: true,
  transpilePackages: ['d3-scale', '@visx/scale']
}

module.exports = nextConfig
  1. install patch-package. you can use this to make changes to dependencies and have those automatically applied after installation:
npm install patch-package
  1. add a postinstall script to your package.json. the package manager will run this after every install and apply the changes you'll make in the following steps.
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "postinstall": "patch-package" 
  },
  1. add the following to the package.json of all packages under node_modules/@visx:
"exports": {
    ".": {
        "import":"./esm/index.js", 
        "require": "./lib/index.js"
    }
  }
  1. for any @visx/ submodule that gives you the ERR_REQUIRE_ESM error, replace all instances of require("d3 with import("d3 (notice the space in the beginning of these strings) in the submodule's lib folder. I tried doing this everywhere within the @visx/ folder but that broke, so I decided to just do it selectively, everywhere I run into an actual issue
    For example:
  • I was getting this error from @visx/scale
  • using VSCode's Find in Files functionality (Cmd + Shift + F), I replaced all requires in the lib/ subfolder with imports
    image
  1. run patch-package for every single visx submodule. this will save the changes you made to a patches/ folder in your repository. you need to set the exclude flag to some dummy value, otherwise patch-package ignores the changes made in package.json:
npx patch-package --exclude 'nothingatall' @visx/annotation
npx patch-package --exclude 'nothingatall' @visx/axis
npx patch-package --exclude 'nothingatall' @visx/bounds
npx patch-package --exclude 'nothingatall' @visx/brush
npx patch-package --exclude 'nothingatall' @visx/clip-path
npx patch-package --exclude 'nothingatall' @visx/curve
npx patch-package --exclude 'nothingatall' @visx/drag
npx patch-package --exclude 'nothingatall' @visx/event
npx patch-package --exclude 'nothingatall' @visx/geo
npx patch-package --exclude 'nothingatall' @visx/glyph
npx patch-package --exclude 'nothingatall' @visx/gradient
npx patch-package --exclude 'nothingatall' @visx/grid
npx patch-package --exclude 'nothingatall' @visx/group
npx patch-package --exclude 'nothingatall' @visx/heatmap
npx patch-package --exclude 'nothingatall' @visx/hierarchy
npx patch-package --exclude 'nothingatall' @visx/legend
npx patch-package --exclude 'nothingatall' @visx/marker
npx patch-package --exclude 'nothingatall' @visx/mock-data
npx patch-package --exclude 'nothingatall' @visx/network
npx patch-package --exclude 'nothingatall' @visx/pattern
npx patch-package --exclude 'nothingatall' @visx/point
npx patch-package --exclude 'nothingatall' @visx/react-spring
npx patch-package --exclude 'nothingatall' @visx/responsive
npx patch-package --exclude 'nothingatall' @visx/scale
npx patch-package --exclude 'nothingatall' @visx/shape
npx patch-package --exclude 'nothingatall' @visx/text
npx patch-package --exclude 'nothingatall' @visx/threshold
npx patch-package --exclude 'nothingatall' @visx/tooltip
npx patch-package --exclude 'nothingatall' @visx/visx
npx patch-package --exclude 'nothingatall' @visx/voronoi
npx patch-package --exclude 'nothingatall' @visx/wordcloud
npx patch-package --exclude 'nothingatall' @visx/xychart
  1. commit the changes to the repo

Summary of the steps:

  • change next.config.js to transpile relevant packages
  • change @visx/* submodules package.json by adding exports
  • wherever needed replace require() with import()

I'm sure parts of this could be done smarter, but this worked for me so I thought I'd share

@rafaelsmgomes
Copy link

for anyone stumbling into this issue, here is a step-by-step of what worked for me on next13 using the pages router:

  1. install visx:
npm install @visx/visx
  1. add the following to next.config.js:
const nextConfig = {
  reactStrictMode: true,
  transpilePackages: ['d3-scale', '@visx/scale']
}

module.exports = nextConfig
  1. install patch-package. you can use this to make changes to dependencies and have those automatically applied after installation:
npm install patch-package
  1. add a postinstall script to your package.json. the package manager will run this after every install and apply the changes you'll make in the following steps.
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "postinstall": "patch-package" 
  },
  1. add the following to the package.json of all packages under node_modules/@visx:
"exports": {
    ".": {
        "import":"./esm/index.js", 
        "require": "./lib/index.js"
    }
  }
  1. for any @visx/ submodule that gives you the ERR_REQUIRE_ESM error, replace all instances of require("d3 with import("d3 (notice the space in the beginning of these strings) in the submodule's lib folder. I tried doing this everywhere within the @visx/ folder but that broke, so I decided to just do it selectively, everywhere I run into an actual issue
    For example:
  • I was getting this error from @visx/scale
  • using VSCode's Find in Files functionality (Cmd + Shift + F), I replaced all requires in the lib/ subfolder with imports
    image
  1. run patch-package for every single visx submodule. this will save the changes you made to a patches/ folder in your repository. you need to set the exclude flag to some dummy value, otherwise patch-package ignores the changes made in package.json:
npx patch-package --exclude 'nothingatall' @visx/annotation
npx patch-package --exclude 'nothingatall' @visx/axis
npx patch-package --exclude 'nothingatall' @visx/bounds
npx patch-package --exclude 'nothingatall' @visx/brush
npx patch-package --exclude 'nothingatall' @visx/clip-path
npx patch-package --exclude 'nothingatall' @visx/curve
npx patch-package --exclude 'nothingatall' @visx/drag
npx patch-package --exclude 'nothingatall' @visx/event
npx patch-package --exclude 'nothingatall' @visx/geo
npx patch-package --exclude 'nothingatall' @visx/glyph
npx patch-package --exclude 'nothingatall' @visx/gradient
npx patch-package --exclude 'nothingatall' @visx/grid
npx patch-package --exclude 'nothingatall' @visx/group
npx patch-package --exclude 'nothingatall' @visx/heatmap
npx patch-package --exclude 'nothingatall' @visx/hierarchy
npx patch-package --exclude 'nothingatall' @visx/legend
npx patch-package --exclude 'nothingatall' @visx/marker
npx patch-package --exclude 'nothingatall' @visx/mock-data
npx patch-package --exclude 'nothingatall' @visx/network
npx patch-package --exclude 'nothingatall' @visx/pattern
npx patch-package --exclude 'nothingatall' @visx/point
npx patch-package --exclude 'nothingatall' @visx/react-spring
npx patch-package --exclude 'nothingatall' @visx/responsive
npx patch-package --exclude 'nothingatall' @visx/scale
npx patch-package --exclude 'nothingatall' @visx/shape
npx patch-package --exclude 'nothingatall' @visx/text
npx patch-package --exclude 'nothingatall' @visx/threshold
npx patch-package --exclude 'nothingatall' @visx/tooltip
npx patch-package --exclude 'nothingatall' @visx/visx
npx patch-package --exclude 'nothingatall' @visx/voronoi
npx patch-package --exclude 'nothingatall' @visx/wordcloud
npx patch-package --exclude 'nothingatall' @visx/xychart
  1. commit the changes to the repo

Summary of the steps:

  • change next.config.js to transpile relevant packages
  • change @visx/* submodules package.json by adding exports
  • wherever needed replace require() with import()

I'm sure parts of this could be done smarter, but this worked for me so I thought I'd share

Thanks @korompaiistvan! That worked for me!

If anyone is using pnpm as their package manager, steps number 2, 3 and 8 can definitely be skipped in favor of using pnpm patch command. Please see their documentation and follow the steps on this video to make the changes recommended in this post.

PS: I actually haven't tried it, but I think you might be able to get away with just making the changes on steps 2, 3 and 8 using the pnpm patch command.

@DarrylBrooks97
Copy link

I'm on Next.js 13.2.0 within the App router and I was also able to fix this issue by setting esmExternals to loose within the next.config.js.

const nextConfig = {
     ...,
     experimental: {
	appDir: true,
	esmExternals: 'loose',
     },
}

module.exports = nextConfig;

Found this fix within their docs here

@implosivemosaic
Copy link

Oof I hit this problem too. It's preventing me from using visx in a NextJS project. I tried the solution proposed by @korompaiistvan but the page fails to load (rendering an ):

error - Error [TypeError]: (0 , _d3Scale.scaleOrdinal) is not a function
    at createOrdinalScale (node_modules/.pnpm/@visx+scale@3.0.0/node_modules/@visx/scale/lib/scales/ordinal.js:12:55)

If someone has an idea about what could be wrong here or could share a working example of a Next 13 project that would be amazing!

@dev-xo
Copy link

dev-xo commented May 5, 2023

Same issue here running on Remix.run / Next.js
Kinda pain, and I don't think patching it ourselves should be the right way to go.

Anyways, thanks to the ones who actually gave a try into looking for a temporary fix!

@williaster
Copy link
Collaborator

Sorry for the delay here. Trying to make the right decision and we are leaning toward creating transpiled versions of the esm-only d3-* dependencies that we have (similar to victory chart's vendor packages) so that we can continue to ship csj + esm versions of all visx packages.

We also put it on vercel's radar https://twitter.com/timneutkens/status/1653849232908886019

No concrete timeline but hoping to do this as soon as we can. If someone from the community is super motivated to try it we're happy to discuss and provide PR review.

@ericchernuka
Copy link

To help anyone that stumbles upon this with Remix, I configured my remix.config.js in the following way to have it work.

  serverDependenciesToBundle: [
    'd3',
    /^d3-*/,
    /^@visx\/*/,
    'delaunator',
    'internmap',
  ],

Hopefully, it helps those users and gleans something for Next users.

@dev-xo
Copy link

dev-xo commented May 7, 2023

Worked for me on Remix.run @ericchernuka!
Thank you so much mate!

@timneutkens
Copy link

timneutkens commented May 8, 2023

Hey, as promised I had a look into this.

As @ljharb pointed out ESM adoption is quite the problem.
The reason it doesn't just work in Next.js is that the package seems to have been published at a time before Node.js had built-in ESM. Because of that it's using main and module to differentiate CommonJS vs ESM. However, Node.js ESM is much stricter than what we had with bundlers.

E.g. node -e "import('@visx/scale')" and node -e "require('@visx/scale')" doesn't run currently.

Which is why this problem happens, the package is not compatible with Node.js's stricter ESM and requires bundling in order to work.

My recommendation would be to leverage conditional exports: https://nodejs.org/api/packages.html#conditional-exports. That way Next.js would correctly handle the package using import() instead of require().

Still this means the package has to change to be compatible with the rules like explicit extensions and such.

--

(not recommended)

I managed to get it working adding the follow:

Add this next.config.js:

// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  transpilePackages: [
    "@visx/mock-data",
    "@visx/group",
    "@visx/shape",
    "@visx/scale",
    "d3",
    "d3-interpolate",
  ],
};

module.exports = nextConfig;

Change node_modules/@visx/scale/package.json to have "type": "module".

Here's a sandbox with the changes applied:

MagneticWatermelon added a commit to MagneticWatermelon/grana that referenced this issue May 12, 2023
@panta82
Copy link

panta82 commented May 28, 2023

Solution by @timneutkens worked for me.

I added all the @visx imports I had, but I didn't have to change anything to "type": "module"

@FabioDainese
Copy link

Hi guys! I've stumbled upon the same issue in my NextJS v13.4.5 project. I first tried the - not recommended - solution proposed by timneutkens, but somehow it didn't work, so I decided to test the one suggested by [@korompaiistvan] (#1637 (comment)) (which I already used in another NextJS project some time ago and back then it worked), but sadly this time after the fix I get the following error:

- error node_modules/@visx/tooltip/lib/Portal.js (9:94) @ prototype
- error Error [TypeError]: Cannot read properties of undefined (reading 'prototype')
    at _inheritsLoose (webpack-internal:///(sc_server)/./node_modules/@visx/tooltip/lib/Portal.js:13:51)
    at eval (webpack-internal:///(sc_server)/./node_modules/@visx/tooltip/lib/Portal.js:25:5)
    at eval (webpack-internal:///(sc_server)/./node_modules/@visx/tooltip/lib/Portal.js:49:2)
    at Object.(sc_server)/./node_modules/@visx/tooltip/lib/Portal.js (/Users/Fabio/Desktop/test/project/.next/server/app/[locale]/dashboard/page.js:5038:1)
    at __webpack_require__ (/Users/Fabio/Desktop/test/project/.next/server/webpack-runtime.js:33:43)
    at eval (webpack-internal:///(sc_server)/./node_modules/@visx/tooltip/lib/hooks/useTooltipInPortal.js:6:38)
    at Object.(sc_server)/./node_modules/@visx/tooltip/lib/hooks/useTooltipInPortal.js (/Users/Fabio/Desktop/test/project/.next/server/app/[locale]/dashboard/page.js:5082:1)
    at __webpack_require__ (/Users/Fabio/Desktop/test/project/.next/server/webpack-runtime.js:33:43)
    at eval (webpack-internal:///(sc_server)/./node_modules/@visx/tooltip/lib/index.js:8:50)
    at Object.(sc_server)/./node_modules/@visx/tooltip/lib/index.js (/Users/Fabio/Desktop/test/project/.next/server/app/[locale]/dashboard/page.js:5093:1) {
  digest: undefined
}

To give you the full picture, here's the list of Visx dependencies that I'm currently using (and fun fact, in the project I'm not using any Portal component, just the TooltipWithBounds one and the useTooltip hook):

"@visx/axis": "^3.1.0",
"@visx/curve": "^3.0.0",
"@visx/event": "^3.0.1",
"@visx/glyph": "^3.0.0",
"@visx/grid": "^3.0.1",
"@visx/group": "^3.0.0",
"@visx/responsive": "^3.0.0",
"@visx/scale": "^3.0.0",
"@visx/shape": "^3.0.0",
"@visx/tooltip": "^3.1.2",
"d3-array": "^3.2.3",
"d3-time-format": "^4.1.0"

I gave a look at the /node_modules/@visx/tooltip/lib/Portal.js file, but I'm not quite sure on how to mitigate this issue. Did you guys have encounter the same problem and maybe found any solution?

@FabioDainese
Copy link

Hi guys! I've stumbled upon the same issue in my NextJS v13.4.5 project. I first tried the - not recommended - solution proposed by timneutkens, but somehow it didn't work, so I decided to test the one suggested by [@korompaiistvan] (#1637 (comment)) (which I already used in another NextJS project some time ago and back then it worked), but sadly this time after the fix I get the following error:

- error node_modules/@visx/tooltip/lib/Portal.js (9:94) @ prototype
- error Error [TypeError]: Cannot read properties of undefined (reading 'prototype')
    at _inheritsLoose (webpack-internal:///(sc_server)/./node_modules/@visx/tooltip/lib/Portal.js:13:51)
    at eval (webpack-internal:///(sc_server)/./node_modules/@visx/tooltip/lib/Portal.js:25:5)
    at eval (webpack-internal:///(sc_server)/./node_modules/@visx/tooltip/lib/Portal.js:49:2)
    at Object.(sc_server)/./node_modules/@visx/tooltip/lib/Portal.js (/Users/Fabio/Desktop/test/project/.next/server/app/[locale]/dashboard/page.js:5038:1)
    at __webpack_require__ (/Users/Fabio/Desktop/test/project/.next/server/webpack-runtime.js:33:43)
    at eval (webpack-internal:///(sc_server)/./node_modules/@visx/tooltip/lib/hooks/useTooltipInPortal.js:6:38)
    at Object.(sc_server)/./node_modules/@visx/tooltip/lib/hooks/useTooltipInPortal.js (/Users/Fabio/Desktop/test/project/.next/server/app/[locale]/dashboard/page.js:5082:1)
    at __webpack_require__ (/Users/Fabio/Desktop/test/project/.next/server/webpack-runtime.js:33:43)
    at eval (webpack-internal:///(sc_server)/./node_modules/@visx/tooltip/lib/index.js:8:50)
    at Object.(sc_server)/./node_modules/@visx/tooltip/lib/index.js (/Users/Fabio/Desktop/test/project/.next/server/app/[locale]/dashboard/page.js:5093:1) {
  digest: undefined
}

To give you the full picture, here's the list of Visx dependencies that I'm currently using (and fun fact, in the project I'm not using any Portal component, just the TooltipWithBounds one and the useTooltip hook):

"@visx/axis": "^3.1.0",
"@visx/curve": "^3.0.0",
"@visx/event": "^3.0.1",
"@visx/glyph": "^3.0.0",
"@visx/grid": "^3.0.1",
"@visx/group": "^3.0.0",
"@visx/responsive": "^3.0.0",
"@visx/scale": "^3.0.0",
"@visx/shape": "^3.0.0",
"@visx/tooltip": "^3.1.2",
"d3-array": "^3.2.3",
"d3-time-format": "^4.1.0"

I gave a look at the /node_modules/@visx/tooltip/lib/Portal.js file, but I'm not quite sure on how to mitigate this issue. Did you guys have encounter the same problem and maybe found any solution?

Okay, so the problem was that I totally forgot to include the "use client" string at the top of the component that uses Visx utilities. Such a rookie mistake 🙈

@williaster
Copy link
Collaborator

I'll take a shot at fixing this over the next week or so

@williaster
Copy link
Collaborator

also thank you very much @timneutkens for digging into this and giving some clarity on our esm/cjs module structure, will incorporate this as part of the fix. really appreciate your time! ❤️

@williaster
Copy link
Collaborator

williaster commented Jun 26, 2023

My recommendation would be to leverage conditional exports: https://nodejs.org/api/packages.html#conditional-exports. That way Next.js would correctly handle the package using import() instead of require().

Still this means the package has to change to be compatible with the rules like explicit extensions and such.

@timneutkens or @ljharb can you point to any favorite documentation or discussions regarding the (latest) best practices or requirements here? I've sifted through a lot but still am not clear about the following:

  1. should we continue to use top-level main/module/types package.json entries in addition to an exports entry (for anything that doesn't support exports)
  2. what is the best strategy relating to explicit file extensions for conditional exports:

a) continuing to export .js files into separate lib/ and esm/ directories as we do now
- currently our .d.ts exports sit in lib/, but it seems like exports.types entries with sub-paths like lib/ don't work out of the box with tooling like VS code microsoft/TypeScript#33079

b) if we should export everything into dist/ with .cjs, .mjs extensions, and duplicate .d.mjs, and .d.cjs type files

Thanks for your expertise on this 🙏

EDIT:
regarding both 1) and 2) above, after the move toward transpiling these ESM-only packages and vendoring them ourselves via @visx/vendor, our next.js (next@11) works without any modification of main/module/types to the more modern exports entry.

So maybe we don't actually need to update to use exports, and we don't need to modify our lib/ + esm/ exports

@ljharb
Copy link

ljharb commented Jun 27, 2023

@williaster for back compat, yes, you'd keep a top-level "types" key alongside the "exports" "types" key.

The best strategy imo is for ESM files to always be .mjs, for CJS files to always be .js, and to not set the "type" field at all.

I don't know for sure how TS works with d.mjs vs d.cjs but it kind of seems like types would always stay as .d.ts, since nothing uses them at runtime?

@williaster
Copy link
Collaborator

alright I think this is fixed folks. try 3.2.0 and let me know if you have issues, see #1716 where we introduced @visx/vendor for more details.

3.2.0 works without special transpiling logic in our next@11 demo app, the package contents look good, and the sandbox works. I didn't do another major version bump since csj was effectively broken in 3.0.x and 3.1.x anyway.

@hshoff
Copy link
Member

hshoff commented Jun 29, 2023

Worked for me with next@13

{
  "name": "visx-vendor-test",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start"
  },
  "dependencies": {
    "@visx/axis": "3.2.0",
    "@visx/grid": "3.2.0",
    "@visx/group": "3.0.0",
    "@visx/mock-data": "3.0.0",
    "@visx/scale": "3.2.0",
    "@visx/shape": "3.2.0",
    "next": "13.4.7",
    "react": "18.2.0",
    "react-dom": "18.2.0"
  }
}
image

@williaster
Copy link
Collaborator

^considering another validation in the wild, I'm going to go ahead and close this. but post any issues you have/we can re-open if necessary.

@timneutkens
Copy link

Awesome work @williaster, thank you! 🚀

@kyhorne
Copy link

kyhorne commented Jul 11, 2023

I'm still seeing this on Node v19, unfortunately:

Error [ERR_REQUIRE_ESM]: require() of ES Module /app/node_modules/d3-scale/src/index.js from /app/node_modules/@visx/scale/lib/scales/band.js not supported.
Instead, change the require of index.js in /app/node_modules/@visx/scale/lib/scales/band.js to a dynamic import() which is available in all CommonJS modules.

     at Object.<anonymous> (/app/node_modules/@visx/scale/lib/scales/band.js:6:16)
     at Object.<anonymous> (/app/node_modules/@visx/scale/lib/index.js:28:36)
{
  "name": "frontend",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
  },
  "dependencies": {
    "@visx/axis": "^2.0.0",
    "@visx/curve": "^2.0.0",
    "@visx/event": "^2.0.0",
    "@visx/glyph": "^2.0.0",
    "@visx/gradient": "^2.0.0",
    "@visx/grid": "^2.0.0",
    "@visx/group": "^2.0.0",
    "@visx/responsive": "^2.0.0",
    "@visx/scale": "^2.0.0",
    "@visx/shape": "^2.0.0",
    "@visx/text": "^2.0.0",
    "@visx/tooltip": "^2.0.0",
    "d3-array": "^3.2.4",
    "d3-scale": "^4.0.2",
    "next": "^13.4.9",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
  }
}

@williaster
Copy link
Collaborator

williaster commented Jul 11, 2023

Hey @kyhorne there are two issues I see with your package.json

  1. you're not using the latest @visx/*, can you try ^3.2.0 (some packages you use may only have 3.0.0 versions, but those with 3.2.0 versions published should be used)?
  2. you have versions of d3-scale and d3-array in your dependencies which are ESM-only. next@13 might be able to handle that okay, but if you aren't importing from them directly in your project, you might consider removing them.

@V-iktor
Copy link

V-iktor commented Sep 30, 2023

Okay, so the problem was that I totally forgot to include the "use client" string at the top of the component that uses Visx utilities. Such a rookie mistake 🙈

Thank you for pointing that out @FabioDainese

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests