-
Notifications
You must be signed in to change notification settings - Fork 2k
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
feat: replace instanceOf with unique Symbol checks #3617
base: main
Are you sure you want to change the base?
Conversation
✅ Deploy Preview for compassionate-pike-271cb3 ready!
To edit notification comments on pull requests, go to your Netlify site settings. |
Makes sense to me in terms of separating version checks from instanceOf checks, the two are related, but ultimately separate concerns. I guess the version check changes should be part of this PR if old instanceOf behavior is being deprecated. [Fundamentally, I don't think we should be doing version checks. If the TS type signatures align, imo that is the package manager's responsibility and graphql-js should get out of the way. But considering we currently do, I guess it is reasonable to continue.] |
GraphQLNonNull wrapper can only be applies to nullable types related: graphql#3597 see also: graphql#3617 (comment)
GraphQLNonNull wrapper can only be applies to nullable types related: graphql#3597 see also: graphql#3617 (comment)
`GraphQLNonNull<GraphQLNullableType>` This is related to graphql#3597, in the sense that graphql#3597 made the `GraphQLNonNull<GraphQL*Type>` => `GraphQLNonNull<GraphQLNullable*Type>` change in other code points related to the `isNonNullType` function, but not within `GraphQLWrappingType` or assertNonNullType. This PR was prompted by the uncovering of a bug by a different PR, see: graphql#3617 (comment)
`GraphQLNonNull<GraphQLNullableType>` This is related to graphql#3597, in the sense that graphql#3597 made the `GraphQLNonNull<GraphQL*Type>` => `GraphQLNonNull<GraphQLNullable*Type>` change in other code points related to the `isNonNullType` function, but not within `GraphQLWrappingType` or assertNonNullType. This PR was prompted by the uncovering of a bug by a different PR, see: graphql#3617 (comment)
b0a4395
to
29fabcb
Compare
) `GraphQLNonNull<GraphQLNullableType>` This is related to #3597, in the sense that #3597 made the `GraphQLNonNull<GraphQL*Type>` => `GraphQLNonNull<GraphQLNullable*Type>` change in other code points related to the `isNonNullType` function, but not within `GraphQLWrappingType` or assertNonNullType. This PR was prompted by the uncovering of a bug by a different PR, see: #3617 (comment)
1d4faf8
to
8bd61d7
Compare
Review requested? Approach seems great -- although we also need to decide about whether/where/how to enforce common version. Generally, I think we need feedback from @IvanGoncharov or perhaps the larger graphql-js-wg or even the main graphql-wg to figure out which way forward on esm only. |
src/error/GraphQLError.ts
Outdated
/** | ||
* A GraphQLError describes an Error found during the parse, validate, or | ||
* execute phases of performing a GraphQL operation. In addition to a message | ||
* and stack trace, it also includes information about the locations in a | ||
* GraphQL document and/or execution result that correspond to the Error. | ||
*/ | ||
export class GraphQLError extends Error { | ||
[isGraphQLErrorSymbol]: true = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure whether making it a static property would make sense as another issue this might solve in the future is to have GraphQLError like-objects that are not instances of the GraphQLErro class. I am sure @yaacovCR also has opinions on that.
The following seems way too specific for classes:
maybeError.constructor?.[isGraphQLErrorSymbol] === true
vs
maybeError[isGraphQLErrorSymbol] === true
I am not sure whether a boolean per instance is that big of an issue and a memory monster. 🤔
Regarding: "I suggest having a single static property with symbol graphql@{git_hash} as key and enum similar to what @yaacovCR has in #3616"
I am not sure whether I get this right, but do you assume that each symbol should be scoped to a git hash commit in order to avoid cross-version usage?
In that case, I would rather propose the solution mentioned in #3603 (comment) and raise an error as soon as a second GraphQL.js version is loaded which IMHO should be a separate pull request.
Instead could be another solution to add something like this to the "entry" modules to ensure only one version of GraphQL.js is loaded? Are there use-cases in which you would want to run two graphql-js versions alongside each other?
import { version } from './version'; interface GlobalThisCast { loadedGraphQLVersion?: undefined | string; } const alreadyLoadedGraphQLVersion = (globalThis as GlobalThisCast) .loadedGraphQLVersion; if ( alreadyLoadedGraphQLVersion !== undefined && alreadyLoadedGraphQLVersion !== version ) { throw new TypeError( `Tried loading graphql-js '${version}' alongside '${alreadyLoadedGraphQLVersion}'.` + '\nPlease revisit your resolutions and installed graphql-js versions and make sure only a single version is loaded at a time.', ); } (globalThis as GlobalThisCast).loadedGraphQLVersion = version;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure whether we need this check at all. Our runtime code should not address wrongly configured/installed dependencies. Only installing and loading a single version of graphql-js should be a package manager's concern, not ours.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we leave the check in, we may need to keep it working the way it does, ie by verifying the version used when passing objects around.
This is because some libraries could in theory want to support multiple versions of graphql as long as they ensure that the right versions talk to each other.
I am envisioning a version of graphiql that lets you dynamically switch between versions of graphql js or something like that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But I generally agree with @n1ru4l that we should seriously consider removing this check. It made sense for the time when the library moved from being a regular dependency to a peer dependency, but that time was long ago.
We have two use cases that this change potentially can solve:
However Do you know any other use case this change solves beyond |
I'm asking because if we just addressing CJS/MJS here, we need to compare it with the solution from #3361 or other similar solutions. |
@IvanGoncharov I am not a big fan of #3361 as it would require using resolution overwrites. On yarn using resolutions is straightforward and handy. On npm, you will have to use third-party packages. 🙁 (https://www.npmjs.com/package/npm-force-resolutions) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do like the idea of Symbol
also being used for version checks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the Symbol solution. Seems like a pretty straightforward solution.
Since Symbol.for
will work regardless of where it was executed from, I think it will also solve the multiple instances issue.
This is the first step for a potential reintroduction of CommonJS alongside ESM that avoids the dual package hazard
instanceOf
issues.In addition, I think it would make sense to introduce and assert a flag onglobalThis
in order to avoid multiple GraphQL.js versions being used together (unless there is a valid use case) that should be importet at the top of each entry-point file.entry-shim.ts
Update: I don't think we should manually assert the GraphQL version with an
entry-shim
as described above. Resolving a single version of GraphQL is the responsibility of the package manager.The motivation behind this PR is the reality that CommonJS and ESM will co-exist for some more time until the whole ecosystem catches up. See #3603
Related: