I have some legacy code using react-apollo and apollo-client querying and mutating with the apollo react-components.
Trying to updating slowly my code, I integrated hooks, having components still working. To do that, I deleted all apollo related package and replace them by @apollo/client according to Migrating to Apollo Client 3.0.
"dependencies" : {
"@apollo/client": "^3.3.4",
...
"graphql": "^14.6.0",
"graphql-tag": "^2.10.3",
},
I am using yarn to install my packages and Parcel to bundle my app.
Everything is working like a charm locally. So I have both hooks and components queries cohabiting.
My issue occurs when I run my app on staging environment. Build and Deploy passed, but when I browse to my staging url, I get this error:
```
Uncaught Error: Cannot use e "__Schema" from another module or realm.
Ensure that there is only one instance of "graphql" in the node_modules
directory. If different versions of "graphql" are the dependencies of other
relied on modules, use "resolutions" to ensure only one version is installed.
https://yarnpkg.com/en/docs/selective-version-resolutions
Duplicate "graphql" modules cannot be used at the same time since different
versions may have different capabilities and behavior. The data from one
version used in the function from another could produce confusing and
spurious results.
````
Checking my yarn.lock only gives me one reference for graphql.
Looking for a solution, I hit this stackoverflow answer to the exact same issue.
Indeed, if I set NODE_ENV=production instead or staging it works, but my staging environment is not my production environment and the error still occurs with NODE_ENV=development, so that doesn鈥檛 answer my issue.
Do you have any key or suggestion ?
@TimTim75 Just to be sure, could you also check for duplicate graphql packages within your node_modules directory?
find node_modules | grep '\bgraphql$'
Note: this command assumes you're using a UNIX-compatible shell with find and grep.
@benjamn thanks for your quick answer
Here is my output of your line
find node_modules | grep '\bgraphql$'
> node_modules/@apollo/client/utilities/graphql
> node_modules/graphql
@TimTim75 Does your Parcel setup do any kind of hot module replacement or fast refresh? Wondering if the graphql package might be getting evaluated more than once, somehow.
@benjamn I don't have any hot module replacement nor fast refresh.
Here is my package.json if it can help in any way.
{
"name": "my-app",
"version": "0.0.0",
"description": "My App.",
"engines": {
"node": ">= 12",
"npm": "6.11",
"yarn": ">= 1.17"
},
"dependencies": {
"@apollo/client": "^3.3.5",
"@apollo/react-testing": "^3.0.1",
"@babel/cli": "^7.8.4",
"@babel/core": "^7.8.4",
"@babel/node": "^7.8.4",
"@babel/plugin-syntax-object-rest-spread": "^7.8.3",
"@babel/polyfill": "^7.8.3",
"@babel/preset-env": "^7.8.4",
"@babel/preset-react": "^7.8.3",
"@formatjs/intl-relativetimeformat": "^4.5.9",
"@sentry/browser": "^5.12.5",
"@stripe/react-stripe-js": "^1.0.3",
"@urbancampus/uc-kit": "^0.3.0",
"apollo-link": "^1.2.13",
"apollo-link-context": "^1.0.19",
"apollo-upload-client": "^12.1.0",
"babel-core": "^7.0.0-bridge.0",
"babel-plugin-add-react-displayname": "^0.0.5",
"babel-plugin-react-intl": "^5.1.18",
"babel-polyfill": "^6.26.0",
"date-fns": "^2.10.0",
"datepicker": "^0.0.0",
"graphql": "^15.4.0",
"graphql-tag": "^2.10.3",
"hellosign-embedded": "^2.7.1",
"lodash": "^4.17.15",
"moment": "^2.29.1",
"parcel-bundler": "^1.12.3",
"prop-types": "^15.7.1",
"react": "^16.13.0",
"react-datepicker": "^2.13.0",
"react-dom": "^16.13.0",
"react-ga": "^2.6.0",
"react-intl": "^3.12.0",
"react-modal": "^3.11.2",
"react-router": "^5.0.1",
"react-router-dom": "^5.1.2",
"react-test-renderer": "^16.13.0",
"react-toastify": "^5.5.0",
"react-tooltip": "^4.0.3",
"styled-components": "^5.0.1"
},
"devDependencies": {
"babel-jest": "^25.1.0",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.2",
"enzyme-to-json": "^3.4.4",
"eslint": "^7.12.1",
"eslint-config-airbnb": "^18.2.0",
"eslint-plugin-import": "^2.20.1",
"eslint-plugin-jsx-a11y": "^6.2.1",
"eslint-plugin-react": "^7.18.3",
"eslint-plugin-react-hooks": "^4.2.0",
"jest": "^25.1.0",
"jest-styled-components": "^7.0.0",
"pug": "^2.0.4"
},
"scripts": {
"build:langs": "NODE_ENV='production' babel-node scripts/mergeMessages.js",
"build": "npm run build:langs && parcel build src/index.pug --out-dir build --public-url / --no-cache --no-source-maps",
"start": "parcel src/index.pug --no-cache --no-source-maps",
"test": "jest -u --coverage",
"lint": "eslint --ext js ."
},
"jest": {
"setupFilesAfterEnv": [
"<rootDir>/setupTest.js"
],
"moduleNameMapper": {
"\\.(css|jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/scripts/assetsTransformer.js"
}
},
"resolutions": {
"@babel/preset-env": "7.5.5"
},
"alias": {
"react": "./node_modules/react"
},
"eslintConfig": {
"env": {
"es6": true,
"browser": true,
"node": true
},
"parserOptions": {
"ecmaVersion": 8,
"ecmaFeatures": {
"jsx": true
},
"sourceType": "module"
}
}
}
Hello @benjamn,
Any chances you had a few time to have a look on it ?
Thanks a lot
Hi @benjamn, any news on this issue? I tried the same setup with version 6.6.3 and we get the same isssue... Thanks
Hello @benjamn,
Do you have any clues on what we can do to avoid this error ?
Thanks
@TimTim75 @cberez I tried using @TimTim75's package.json to create a basic Parcel app, but I wasn't immediately able to reproduce the error. If either of you can reproduce the problem, that would help a lot. I realize that reproduction template is not using Parcel, but I would be happy to add a Parcel example to https://github.com/apollographql/apollo-client/tree/main/examples/bundling if that seems like it would help.
@benjamn Thanks for trying it.
I have tried, on my side, to reproduce the error with the template you gave us. But I can't.
Maybe you would have an idea if I give you more context. What we are trying to do is to have
But it seems that depending on which
I think that if you have a simple way to do that, it will fix our issue.
Thanks
@TimTim75 Ahh, that is helpful!
Where are you importing the Query component from? I believe it should come from @apollo/client/react/components, in case you're still using @apollo/react-components or something else.
The Query component should work together with useQuery (we do that for some of our own legacy apps at Apollo), so if it's not working for you, that's definitely a bug that we will fix (once diagnosed).
Indeed, and it's working like a charm locally, but going on our staging environment gives us the error:
Uncaught Error: Cannot use e "__Schema" from another module or realm.
Ensure that there is only one instance of "graphql" in the node_modules
directory. If different versions of "graphql" are the dependencies of other
relied on modules, use "resolutions" to ensure only one version is installed.
https://yarnpkg.com/en/docs/selective-version-resolutions
Duplicate "graphql" modules cannot be used at the same time since different
versions may have different capabilities and behavior. The data from one
version used in the function from another could produce confusing and
spurious results.
@TimTim75 After some more research, here's my best theory:
In your staging environment, code is presumably minified (to match production), which means class names are shortened, possibly using the same short string for multiple different classes (e in this case).
Your minifier assumes it's safe to use e for multiple different classes because their names don't collide in the same scope, but that optimization is not entirely safe, because graphql package's instanceOf utility examines constructor.name to trigger the Cannot use e "__Schema" from another module or realm error when value instanceof constructor fails. The reasoning here is that instanceof might have failed just because you're using a constructor from a different realm, which is potentially a mistake you'd want to know about. However, I'm confident we've ruled out that possibility in your case, because you do not seem to have multiple copies of the graphql package in your node_modules.
This error is disabled when NODE_ENV is "production", thanks to https://github.com/graphql/graphql-js/pull/1174, but there's still a risk of false positives any time code is minified in a non-production environment, because the minification is what causes the renaming of classes that confuses instanceOf. Since you're running with NODE_ENV="staging" and also minifying the code, this error can happen whenever value instanceof constructor is false, as long as value.constructor.name === constructor.name, which can happen by accident just because multiple different minified classes all have constructor.name === "e". In these cases, instanceOf(value, constructor) really should return false, without an error.
I'm going to attempt a PR to fix this problem upstream in https://github.com/graphql/graphql-js, and I will keep thinking about other ways to work around it, but I wanted to let you know what's going on as soon as I figured it out.
Here's the PR: https://github.com/graphql/graphql-js/pull/2894. Please have a look!
@TimTim75 In the meantime, if you're using Parcel, you should be able to configure the terser minifier options specifically for the graphql package by writing the following contents into a node_modules/graphql/.terserrc file:
{
"keep_classnames": true,
"keep_fnames": true
}
Of course, this file will get thrown away every time you rerun npm install, but you can use a tool called patch-package to make sure it gets added after every npm install.
@benjamn unfortunately even with the .terserrc fix we still have the issue but disabling minification in parcel (ie parcel build --no-minify) does the work so your analysis seems correct. I'll check if the terser fix needs to be applied to other graphql libs we depend on.
I had a look at the PR on graphql, I hope it won't be stuck until v16 馃檹
Had a look at our Dockerfile and the patches directory wasn't copied before yarn command, fixed it and now the patch works as expected 馃帀
We'll be monitoring the graphql PR and keep the patch in the meantime, thx @benjamn
Most helpful comment
@TimTim75 After some more research, here's my best theory:
In your staging environment, code is presumably minified (to match production), which means class names are shortened, possibly using the same short string for multiple different classes (
ein this case).Your minifier assumes it's safe to use
efor multiple different classes because their names don't collide in the same scope, but that optimization is not entirely safe, becausegraphqlpackage'sinstanceOfutility examinesconstructor.nameto trigger theCannot use e "__Schema" from another module or realmerror whenvalue instanceof constructorfails. The reasoning here is thatinstanceofmight have failed just because you're using aconstructorfrom a different realm, which is potentially a mistake you'd want to know about. However, I'm confident we've ruled out that possibility in your case, because you do not seem to have multiple copies of thegraphqlpackage in yournode_modules.This error is disabled when
NODE_ENVis"production", thanks to https://github.com/graphql/graphql-js/pull/1174, but there's still a risk of false positives any time code is minified in a non-production environment, because the minification is what causes the renaming of classes that confusesinstanceOf. Since you're running withNODE_ENV="staging"and also minifying the code, this error can happen whenevervalue instanceof constructorisfalse, as long asvalue.constructor.name === constructor.name, which can happen by accident just because multiple different minified classes all haveconstructor.name === "e". In these cases,instanceOf(value, constructor)really should returnfalse, without an error.I'm going to attempt a PR to fix this problem upstream in https://github.com/graphql/graphql-js, and I will keep thinking about other ways to work around it, but I wanted to let you know what's going on as soon as I figured it out.