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

Cannot find module 'cheerio' from 'node_modules/enzyme/build/Utils.js' #2518

Open
mmarshad opened this issue May 6, 2021 · 31 comments
Open

Comments

@mmarshad
Copy link

mmarshad commented May 6, 2021

I just start receiving this message to my unit tests today, although it was working fine before

Cannot find module 'cheerio' from 'node_modules/enzyme/build/Utils.js'

Require stack:
  node_modules/enzyme/build/Utils.js
  node_modules/enzyme/build/ShallowWrapper.js
  node_modules/enzyme-to-json/utils.js
  node_modules/enzyme-to-json/createSerializer.js
  node_modules/enzyme-to-json/serializer.js

  at Resolver.resolveModule (node_modules/jest-runtime/node_modules/jest-resolve/build/index.js:306:11)
  at Object.<anonymous> (node_modules/enzyme/src/Utils.js:9:1)

Is there anything changed in serlizer.js?
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.6",
"enzyme-to-json": "^3.6.1",

@ljharb
Copy link
Member

ljharb commented May 6, 2021

enzyme-to-json is not maintained by the enzyme team, so you'd have to ask them.

@Mahdiyeh
Copy link

Mahdiyeh commented May 7, 2021

Same here for me:

`
Cannot find module 'cheerio' from 'node_modules/enzyme/build/Utils.js'

Require stack:
  node_modules/enzyme/build/Utils.js
  node_modules/enzyme/build/ReactWrapper.js
  node_modules/enzyme/build/index.js

  at Resolver.resolveModule (node_modules/jest-resolve/build/index.js:306:11)
  at Object.<anonymous> (node_modules/enzyme/build/Utils.js:80:16)
  `

My dependencies:
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.5"

@ljharb
Copy link
Member

ljharb commented May 7, 2021

Please try pinning cheerio to =1.0.0.rc-3, ensure it's installed, and let me know if the issue persists.

@rxgx
Copy link

rxgx commented May 20, 2022

Adding an override doesn't fix the issue with enzyme incorrectly using a loose RC pattern for a hard dependency.

  "overrides": {
    "enzyme": {
      "cheerio": "1.0.0.rc-3"
    }
  },

Cheerio is now a dual CommonJS and ESM module. That means that deep imports will now fail in newer versions of Node.
https://github.com/cheeriojs/cheerio/releases/tag/v1.0.0-rc.11

@ljharb
Copy link
Member

ljharb commented May 20, 2022

@rxgx while that should work - file an issue with npm if it doesn't - simply adding "cheerio": "=1.0.0.rc-3" to your devDependencies should be sufficient, no overrides required.

@rxgx
Copy link

rxgx commented May 20, 2022

@ljharb what old version of npm are you using?

npm ERR! code EINVALIDTAGNAME
npm ERR! Invalid tag name "=1.0.0.rc-3" of package "cheerio@=1.0.0.rc-3": Tags may not have any characters that encodeURIComponent encodes.

@ljharb
Copy link
Member

ljharb commented May 20, 2022

works fine with every version of npm, through the latest. That's a version specifier, not a tag name.

It's what the next release of enzyme will use: https://github.com/enzymejs/enzyme/blob/master/packages/enzyme/package.json#L42

@rxgx
Copy link

rxgx commented May 20, 2022

Is it possible that this version is missing from the registry? I get these errors even with rm node_modules and npm cache verify. OR something up with npm itself

lerna notice cli v4.0.0
lerna ERR! cheerio: No matching version found for cheerio@1.0.0.rc-3.
lerna ERR!     at module.exports (/Users/rgasparini/Code/monorepo/node_modules/npm-pick-manifest/index.js:209:23)
lerna ERR! lerna No matching version found for cheerio@1.0.0.rc-3.
$ npm i -D cheerio@1.0.0.rc-3 
npm ERR! code ETARGET
npm ERR! notarget No matching version found for cheerio@1.0.0.rc-3.
npm ERR! notarget In most cases you or one of your dependencies are requesting
npm ERR! notarget a package version that doesn't exist.
$ npm i -D cheerio@=1.0.0.rc-3
npm ERR! code EINVALIDTAGNAME
npm ERR! Invalid tag name "=1.0.0.rc-3" of package "cheerio@=1.0.0.rc-3": Tags may not have any characters that encodeURIComponent encodes.

@ljharb
Copy link
Member

ljharb commented May 20, 2022

Is it possible you're not using the public registry? It's quite there: https://unpkg.com/browse/cheerio@1.0.0-rc.3/

@rxgx
Copy link

rxgx commented May 20, 2022

Here's what I originally thought was the resolution before being derailed by the invalid = syntax. I got the hyphen and dots mixed up.

  "overrides": {
    "enzyme": {
      "cheerio": "1.0.0-rc.3"
    }
  },

If you manually change the version of the dependencies or devDependencies, your lock file is unfortunately going to be out of sync.

@ljharb
Copy link
Member

ljharb commented May 20, 2022

The = syntax is a range; overrides takes a specific version - it’s not invalid in general, i just wasn’t providing an override. Overrides should be used only as a last resort.

@nspector
Copy link

Looks like the change to pin it here: cafdb2b
was never published: https://unpkg.com/browse/enzyme@3.11.0/package.json. Can somebody publish it? Thank you!

@ljharb
Copy link
Member

ljharb commented May 20, 2022

@nspector correct; it hasn't been published yet. it'll be in the next release.

Again, you can get the benefit now merely by doing npm install --save-dev cheerio@=1.0.0-rc.3.

@tonnyskk
Copy link

tonnyskk commented May 21, 2022

Try lock your cheerio version to 1.0.0-rc.10 E.g. by yarn resolutions. 1.0.0-rc.11 will throw the error.

@billnbell
Copy link

This worked for me

   "resolutions": {
+    "cheerio": "1.0.0-rc.10"
   },

@richard1230
Copy link

Same here for me:

` Cannot find module 'cheerio' from 'node_modules/enzyme/build/Utils.js'

Require stack:
  node_modules/enzyme/build/Utils.js
  node_modules/enzyme/build/ReactWrapper.js
  node_modules/enzyme/build/index.js

  at Resolver.resolveModule (node_modules/jest-resolve/build/index.js:306:11)
  at Object.<anonymous> (node_modules/enzyme/build/Utils.js:80:16)
  `

My dependencies: "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5"

Do you resolve this one? I have the same issue

@richard1230
Copy link

This worked for me

   "resolutions": {
+    "cheerio": "1.0.0-rc.10"
   },

which file should it be put?

@ljharb
Copy link
Member

ljharb commented May 24, 2022

@richard1230 in package.json. resolutions only applies to yarn tho.

You should add "cheerio": "=1.0.0-rc.3" to your devDependencies in package.json instead.

@billnbell
Copy link

Well devDependencies did not help. When I added "resolutions" it works.

@ljharb

This comment was marked as resolved.

@mjperales
Copy link

This worked perfectly! If you copy/paste the above ☝️ then make sure there isn't a period at the end! That was causing the invalid tag name issue for me

@new-carrot

This comment was marked as off-topic.

@s100
Copy link

s100 commented Jun 13, 2022

This is happening because in ./build/Utils.js, enzyme is doing this:

import { isHtml } from 'cheerio/lib/utils';

Notice how this imports a specific internal module from deep inside the guts of cheerio, ./lib/utils.js.

This bypasses the public API of cheerio, which intends for users to either import ... from 'cheerio', or import ... from 'cheerio/lib/slim' only. Bypassing the public API of a package in this way is always hazardous, because it means that if cheerio rearranges its internal modules, this usage will break. This is an anti-pattern, and it is almost never officially supported by the package you're using.

Recently, webpack has started allowing a new field, "exports", to be used in package.json. This is intended to enable package maintainers to have greater control over this kind of direct import, and how Node.js resolves these dependencies. This field allows two things: firstly, an import like 'cheerio/lib/slim' doesn't have to resolve to ./lib/slim.js, it can be made to resolve to anything the maintainers want - this enables maintainers to rearrange their internals without breaking consumers. Secondly, it means all other deep imports like 'cheerio/lib/utils' now deliberately do not work at all. This disables that API bypass anti-pattern, and reduces the public interface of the package to only what the maintainers choose.

cheerio began using "exports" in cheeriojs/cheerio#2508, which went into cheerio@1.0.0-rc.11, which was released on 20 May 2022, thereby officially dropping support for deep imports. I don't know if deep imports were ever officially supported by cheerio, but they are no longer supported. Technically this is a breaking change, but cheerio@1.0.0-rc.11 is only a release candidate, which I'm guessing doesn't have any kind of commitment to avoiding breaking changes, so cheerio is entirely within its rights to do this.

The real problem, then, is that enzyme@3.11.0 specifies a dependency on a range of unstable release candidate versions of cheerio, which can break without warning in exactly this way:

"cheerio": "^1.0.0-rc.3",

The fix for this is for enzyme to pin to a specific RC of cheerio, which in fact has already been done, in December 2020. However, no new version of enzyme has been released since then.

@ljharb
Copy link
Member

ljharb commented Jun 13, 2022

The public api of a package is everything reachable inside it, and deep imports are always preferable since they obviate the need for treeshaking.

The exports field is a node thing, webpack just supports it, and rc11 added a breaking change to use it, but as you note, prereleases can have those. Prior to this, this file was absolutely part of the public api of cheerio.

You are also correct that enzyme just needs a release to fix this issue.

@s100

This comment was marked as off-topic.

@ljharb

This comment was marked as resolved.

@s100

This comment was marked as resolved.

@ljharb

This comment was marked as resolved.

@fengxinhhh

This comment was marked as outdated.

@blixt
Copy link

blixt commented Jun 18, 2022

I also ran into this issue and made this PR in the Cheerio repository:
cheeriojs/cheerio#2601

Though since it's such a simple function (which could be replaced by /<[a-zA-Z!][^>]*>/.test(str)) that follows a spec and has no need of knowledge of behaviors within Cheerio, one could argue the better solution is to just embed it into Enzyme to avoid depending on the internal structure of another package.

@ljharb
Copy link
Member

ljharb commented Jun 18, 2022

That’s a fair point. Cheerio could still be used to verify the results of the function in tests.

I’d be happy to accept a PR inlining that function.

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